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 // TODO(crbug/1120685): Test that this is never sent to the server if the
101 // machine is not enterprise managed.
102 if (!app.release_channel.empty())
103 app_node.SetKey("release_channel", Value(app.release_channel));
104 if (!app.cohort.empty())
105 app_node.SetKey("cohort", Value(app.cohort));
106 if (!app.cohort_name.empty())
107 app_node.SetKey("cohortname", Value(app.cohort_name));
108 if (!app.cohort_hint.empty())
109 app_node.SetKey("cohorthint", Value(app.cohort_hint));
110 if (app.enabled)
111 app_node.SetKey("enabled", Value(*app.enabled));
112
113 if (app.disabled_reasons && !app.disabled_reasons->empty()) {
114 std::vector<Value> disabled_nodes;
115 for (const int disabled_reason : *app.disabled_reasons) {
116 Value disabled_node(Value::Type::DICTIONARY);
117 disabled_node.SetKey("reason", Value(disabled_reason));
118 disabled_nodes.push_back(std::move(disabled_node));
119 }
120 app_node.SetKey("disabled", Value(disabled_nodes));
121 }
122
123 for (const auto& attr : app.installer_attributes)
124 app_node.SetKey(attr.first, Value(attr.second));
125
126 if (app.update_check) {
127 auto* update_check_node =
128 app_node.SetKey("updatecheck", Value(Value::Type::DICTIONARY));
129 if (app.update_check->is_update_disabled)
130 update_check_node->SetKey("updatedisabled", Value(true));
131 }
132
133 if (app.ping) {
134 const auto& ping = *app.ping;
135 auto* ping_node = app_node.SetKey("ping", Value(Value::Type::DICTIONARY));
136 if (!ping.ping_freshness.empty())
137 ping_node->SetKey("ping_freshness", Value(ping.ping_freshness));
138
139 // Output "ad" or "a" only if the this app has been seen 'active'.
140 if (ping.date_last_active) {
141 ping_node->SetKey("ad", Value(*ping.date_last_active));
142 } else if (ping.days_since_last_active_ping) {
143 ping_node->SetKey("a", Value(*ping.days_since_last_active_ping));
144 }
145
146 // Output "rd" if valid or "r" as a last resort roll call metric.
147 if (ping.date_last_roll_call)
148 ping_node->SetKey("rd", Value(*ping.date_last_roll_call));
149 else
150 ping_node->SetKey("r", Value(ping.days_since_last_roll_call));
151 }
152
153 if (!app.fingerprint.empty()) {
154 std::vector<Value> package_nodes;
155 Value package(Value::Type::DICTIONARY);
156 package.SetKey("fp", Value(app.fingerprint));
157 package_nodes.push_back(std::move(package));
158 auto* packages_node =
159 app_node.SetKey("packages", Value(Value::Type::DICTIONARY));
160 packages_node->SetKey("package", Value(package_nodes));
161 }
162
163 if (app.events) {
164 std::vector<Value> event_nodes;
165 for (const auto& event : *app.events) {
166 DCHECK(event.is_dict());
167 DCHECK(!event.DictEmpty());
168 event_nodes.push_back(event.Clone());
169 }
170 app_node.SetKey("event", Value(event_nodes));
171 }
172
173 app_nodes.push_back(std::move(app_node));
174 }
175
176 if (!app_nodes.empty())
177 request_node->SetKey("app", Value(std::move(app_nodes)));
178
179 std::string msg;
180 return base::JSONWriter::WriteWithOptions(
181 root_node, base::JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
182 &msg)
183 ? msg
184 : std::string();
185 }
186
187 } // namespace update_client
188