blob: 7a1b924dddd65e6050fd4734477b87cdbd5e16ac [file] [log] [blame]
[email protected]4557d222012-03-04 23:33:361// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]90310d92011-04-17 07:35:042// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/extension_sync_data.h"
6
[email protected]418e953e2011-04-27 21:30:227#include "base/logging.h"
yoz870444532015-03-12 18:42:538#include "base/metrics/histogram_macros.h"
yoz768503cd2015-02-24 03:40:319#include "base/strings/stringprintf.h"
Giovanni Ortuño Urquidie7e79d452017-08-03 10:16:1510#include "chrome/browser/extensions/convert_web_app.h"
[email protected]3bdba0d2011-08-23 07:17:3011#include "chrome/browser/extensions/extension_service.h"
treib0c714f7c2015-07-08 10:04:5812#include "chrome/common/extensions/manifest_handlers/app_icon_color_info.h"
13#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
Christopher Lamcec8c4f2017-10-16 01:38:4314#include "chrome/common/extensions/manifest_handlers/app_theme_color_info.h"
treib0c714f7c2015-07-08 10:04:5815#include "chrome/common/extensions/manifest_handlers/linked_app_icons.h"
[email protected]fdd28372014-08-21 02:27:2616#include "components/crx_file/id_util.h"
skym71603842016-10-10 18:17:3117#include "components/sync/model/sync_data.h"
Max Boguefef332d2016-07-28 22:09:0918#include "components/sync/protocol/app_specifics.pb.h"
19#include "components/sync/protocol/extension_specifics.pb.h"
20#include "components/sync/protocol/sync.pb.h"
[email protected]e4452d32013-11-15 23:07:4121#include "extensions/common/extension.h"
rockotd5546142014-10-15 00:29:0822#include "extensions/common/manifest_url_handlers.h"
[email protected]418e953e2011-04-27 21:30:2223
treib0c714f7c2015-07-08 10:04:5824using syncer::StringOrdinal;
25
[email protected]5db9ada2012-04-11 13:48:2026namespace extensions {
27
yoz768503cd2015-02-24 03:40:3128namespace {
29
30std::string GetExtensionSpecificsLogMessage(
31 const sync_pb::ExtensionSpecifics& specifics) {
treib231f2bb2015-06-09 12:46:2432 return base::StringPrintf(
33 "id: %s\nversion: %s\nupdate_url: %s\nenabled: %i\ndisable_reasons: %i",
34 specifics.id().c_str(),
35 specifics.version().c_str(),
36 specifics.update_url().c_str(),
37 specifics.enabled(),
38 specifics.disable_reasons());
yoz768503cd2015-02-24 03:40:3139}
40
yoz870444532015-03-12 18:42:5341enum BadSyncDataReason {
42 // Invalid extension ID.
43 BAD_EXTENSION_ID,
44
45 // Invalid version.
46 BAD_VERSION,
47
48 // Invalid update URL.
49 BAD_UPDATE_URL,
50
51 // No ExtensionSpecifics in the EntitySpecifics.
52 NO_EXTENSION_SPECIFICS,
53
treib29e1b9b12015-11-11 08:50:5654 // Not used anymore; still here because of UMA.
55 DEPRECATED_BAD_DISABLE_REASONS,
treib231f2bb2015-06-09 12:46:2456
yoz870444532015-03-12 18:42:5357 // Must be at the end.
58 NUM_BAD_SYNC_DATA_REASONS
59};
60
61void RecordBadSyncData(BadSyncDataReason reason) {
62 UMA_HISTOGRAM_ENUMERATION("Extensions.BadSyncDataReason", reason,
63 NUM_BAD_SYNC_DATA_REASONS);
64}
65
yoz768503cd2015-02-24 03:40:3166} // namespace
67
treib0c714f7c2015-07-08 10:04:5868ExtensionSyncData::LinkedAppIconInfo::LinkedAppIconInfo() {
69}
70
71ExtensionSyncData::LinkedAppIconInfo::~LinkedAppIconInfo() {
72}
73
[email protected]90310d92011-04-17 07:35:0474ExtensionSyncData::ExtensionSyncData()
treib0c714f7c2015-07-08 10:04:5875 : is_app_(false),
76 uninstalled_(false),
[email protected]3bdba0d2011-08-23 07:17:3077 enabled_(false),
treib231f2bb2015-06-09 12:46:2478 supports_disable_reasons_(false),
Minh X. Nguyen45479012017-08-18 21:35:3679 disable_reasons_(disable_reason::DISABLE_NONE),
[email protected]075b3922014-05-03 06:14:1780 incognito_enabled_(false),
[email protected]6338fa32014-07-16 21:41:5981 remote_install_(false),
rdevlin.cronind1aa8522015-02-13 00:25:5782 all_urls_enabled_(BOOLEAN_UNSET),
treib0c714f7c2015-07-08 10:04:5883 installed_by_custodian_(false),
Minh X. Nguyen45479012017-08-18 21:35:3684 launch_type_(LAUNCH_TYPE_INVALID) {}
[email protected]3bdba0d2011-08-23 07:17:3085
[email protected]3bdba0d2011-08-23 07:17:3086ExtensionSyncData::ExtensionSyncData(const Extension& extension,
87 bool enabled,
treibc1192322015-05-20 12:56:0788 int disable_reasons,
[email protected]21db9ef2014-05-16 02:06:2789 bool incognito_enabled,
rdevlin.cronind1aa8522015-02-13 00:25:5790 bool remote_install,
mamir192d7882016-06-22 17:10:1691 OptionalBoolean all_urls_enabled,
92 bool installed_by_custodian)
treib0c714f7c2015-07-08 10:04:5893 : ExtensionSyncData(extension, enabled, disable_reasons, incognito_enabled,
mamir192d7882016-06-22 17:10:1694 remote_install, all_urls_enabled,
95 installed_by_custodian, StringOrdinal(),
treib0c714f7c2015-07-08 10:04:5896 StringOrdinal(), LAUNCH_TYPE_INVALID) {
97}
98
99ExtensionSyncData::ExtensionSyncData(const Extension& extension,
100 bool enabled,
101 int disable_reasons,
102 bool incognito_enabled,
103 bool remote_install,
104 OptionalBoolean all_urls_enabled,
mamir192d7882016-06-22 17:10:16105 bool installed_by_custodian,
treib0c714f7c2015-07-08 10:04:58106 const StringOrdinal& app_launch_ordinal,
107 const StringOrdinal& page_ordinal,
108 extensions::LaunchType launch_type)
109 : is_app_(extension.is_app()),
110 id_(extension.id()),
[email protected]5db9ada2012-04-11 13:48:20111 uninstalled_(false),
112 enabled_(enabled),
treib231f2bb2015-06-09 12:46:24113 supports_disable_reasons_(true),
treibc1192322015-05-20 12:56:07114 disable_reasons_(disable_reasons),
[email protected]5db9ada2012-04-11 13:48:20115 incognito_enabled_(incognito_enabled),
[email protected]21db9ef2014-05-16 02:06:27116 remote_install_(remote_install),
rdevlin.cronind1aa8522015-02-13 00:25:57117 all_urls_enabled_(all_urls_enabled),
mamir192d7882016-06-22 17:10:16118 installed_by_custodian_(installed_by_custodian),
[email protected]f4263c52014-04-09 12:40:51119 version_(extension.from_bookmark() ? base::Version("0")
Devlin Cronin03bf2d22017-12-20 08:21:05120 : extension.version()),
[email protected]65348062013-01-15 07:27:22121 update_url_(ManifestURL::GetUpdateURL(&extension)),
treib0c714f7c2015-07-08 10:04:58122 name_(extension.non_localized_name()),
123 app_launch_ordinal_(app_launch_ordinal),
124 page_ordinal_(page_ordinal),
125 launch_type_(launch_type) {
126 if (is_app_ && extension.from_bookmark()) {
127 bookmark_app_description_ = extension.description();
128 bookmark_app_url_ = AppLaunchInfo::GetLaunchWebURL(&extension).spec();
Giovanni Ortuño Urquidie7e79d452017-08-03 10:16:15129 bookmark_app_scope_ = GetScopeURLFromBookmarkApp(&extension).spec();
treib0c714f7c2015-07-08 10:04:58130 bookmark_app_icon_color_ = AppIconColorInfo::GetIconColorString(&extension);
Christopher Lamcec8c4f2017-10-16 01:38:43131 bookmark_app_theme_color_ = AppThemeColorInfo::GetThemeColor(&extension);
treib0c714f7c2015-07-08 10:04:58132 extensions::LinkedAppIcons icons =
133 LinkedAppIcons::GetLinkedAppIcons(&extension);
134 for (const auto& icon : icons.icons) {
135 LinkedAppIconInfo linked_icon;
136 linked_icon.url = icon.url;
137 linked_icon.size = icon.size;
138 linked_icons_.push_back(linked_icon);
139 }
140 }
[email protected]3bdba0d2011-08-23 07:17:30141}
[email protected]90310d92011-04-17 07:35:04142
vmpstrb8aacbe2016-02-26 02:00:48143ExtensionSyncData::ExtensionSyncData(const ExtensionSyncData& other) = default;
144
[email protected]90310d92011-04-17 07:35:04145ExtensionSyncData::~ExtensionSyncData() {}
[email protected]418e953e2011-04-27 21:30:22146
yoz870444532015-03-12 18:42:53147// static
dchengc963c7142016-04-08 03:55:22148std::unique_ptr<ExtensionSyncData> ExtensionSyncData::CreateFromSyncData(
yoz870444532015-03-12 18:42:53149 const syncer::SyncData& sync_data) {
dchengc963c7142016-04-08 03:55:22150 std::unique_ptr<ExtensionSyncData> data(new ExtensionSyncData);
yoz870444532015-03-12 18:42:53151 if (data->PopulateFromSyncData(sync_data))
dcheng1fc00f12015-12-26 22:18:03152 return data;
treib0c714f7c2015-07-08 10:04:58153 return nullptr;
yoz870444532015-03-12 18:42:53154}
155
156// static
dchengc963c7142016-04-08 03:55:22157std::unique_ptr<ExtensionSyncData> ExtensionSyncData::CreateFromSyncChange(
yoz870444532015-03-12 18:42:53158 const syncer::SyncChange& sync_change) {
dchengc963c7142016-04-08 03:55:22159 std::unique_ptr<ExtensionSyncData> data(
yoz870444532015-03-12 18:42:53160 CreateFromSyncData(sync_change.sync_data()));
161 if (!data.get())
treib0c714f7c2015-07-08 10:04:58162 return nullptr;
yoz870444532015-03-12 18:42:53163
treibecc63c8d2015-09-07 16:34:47164 if (sync_change.change_type() == syncer::SyncChange::ACTION_DELETE)
165 data->uninstalled_ = true;
dcheng1fc00f12015-12-26 22:18:03166 return data;
yoz870444532015-03-12 18:42:53167}
168
[email protected]65f173552012-06-28 22:43:58169syncer::SyncData ExtensionSyncData::GetSyncData() const {
[email protected]5db9ada2012-04-11 13:48:20170 sync_pb::EntitySpecifics specifics;
treib0c714f7c2015-07-08 10:04:58171 if (is_app_)
172 ToAppSpecifics(specifics.mutable_app());
173 else
174 ToExtensionSpecifics(specifics.mutable_extension());
[email protected]168389f2011-12-20 17:12:48175
[email protected]65f173552012-06-28 22:43:58176 return syncer::SyncData::CreateLocalData(id_, name_, specifics);
[email protected]5db9ada2012-04-11 13:48:20177}
[email protected]168389f2011-12-20 17:12:48178
[email protected]65f173552012-06-28 22:43:58179syncer::SyncChange ExtensionSyncData::GetSyncChange(
180 syncer::SyncChange::SyncChangeType change_type) const {
[email protected]b78170f2012-07-11 03:34:26181 return syncer::SyncChange(FROM_HERE, change_type, GetSyncData());
[email protected]aa7599d2011-10-28 07:24:32182}
183
treib0c714f7c2015-07-08 10:04:58184void ExtensionSyncData::ToExtensionSpecifics(
[email protected]3bdba0d2011-08-23 07:17:30185 sync_pb::ExtensionSpecifics* specifics) const {
[email protected]fdd28372014-08-21 02:27:26186 DCHECK(crx_file::id_util::IdIsValid(id_));
[email protected]3bdba0d2011-08-23 07:17:30187 specifics->set_id(id_);
188 specifics->set_update_url(update_url_.spec());
189 specifics->set_version(version_.GetString());
190 specifics->set_enabled(enabled_);
treib231f2bb2015-06-09 12:46:24191 if (supports_disable_reasons_)
192 specifics->set_disable_reasons(disable_reasons_);
[email protected]3bdba0d2011-08-23 07:17:30193 specifics->set_incognito_enabled(incognito_enabled_);
[email protected]075b3922014-05-03 06:14:17194 specifics->set_remote_install(remote_install_);
rdevlin.cronind1aa8522015-02-13 00:25:57195 if (all_urls_enabled_ != BOOLEAN_UNSET)
196 specifics->set_all_urls_enabled(all_urls_enabled_ == BOOLEAN_TRUE);
[email protected]6338fa32014-07-16 21:41:59197 specifics->set_installed_by_custodian(installed_by_custodian_);
[email protected]3bdba0d2011-08-23 07:17:30198 specifics->set_name(name_);
[email protected]0fac519c2011-08-19 18:05:57199}
[email protected]3bdba0d2011-08-23 07:17:30200
treib0c714f7c2015-07-08 10:04:58201void ExtensionSyncData::ToAppSpecifics(sync_pb::AppSpecifics* specifics) const {
202 DCHECK(specifics);
203 // Only sync the ordinal values and launch type if they are valid.
204 if (app_launch_ordinal_.IsValid())
205 specifics->set_app_launch_ordinal(app_launch_ordinal_.ToInternalValue());
206 if (page_ordinal_.IsValid())
207 specifics->set_page_ordinal(page_ordinal_.ToInternalValue());
208
209 sync_pb::AppSpecifics::LaunchType sync_launch_type =
210 static_cast<sync_pb::AppSpecifics::LaunchType>(launch_type_);
211
212 // The corresponding validation of this value during processing of an
treibc3494532015-07-21 14:51:45213 // ExtensionSyncData is in ExtensionSyncService::ApplySyncData.
treib0c714f7c2015-07-08 10:04:58214 if (launch_type_ >= LAUNCH_TYPE_FIRST && launch_type_ < NUM_LAUNCH_TYPES &&
215 sync_pb::AppSpecifics_LaunchType_IsValid(sync_launch_type)) {
216 specifics->set_launch_type(sync_launch_type);
217 }
218
219 if (!bookmark_app_url_.empty())
220 specifics->set_bookmark_app_url(bookmark_app_url_);
221
222 if (!bookmark_app_description_.empty())
223 specifics->set_bookmark_app_description(bookmark_app_description_);
224
Giovanni Ortuño Urquidie7e79d452017-08-03 10:16:15225 if (!bookmark_app_scope_.empty())
226 specifics->set_bookmark_app_scope(bookmark_app_scope_);
227
treib0c714f7c2015-07-08 10:04:58228 if (!bookmark_app_icon_color_.empty())
229 specifics->set_bookmark_app_icon_color(bookmark_app_icon_color_);
230
Christopher Lamcec8c4f2017-10-16 01:38:43231 if (bookmark_app_theme_color_)
232 specifics->set_bookmark_app_theme_color(bookmark_app_theme_color_.value());
233
treib0c714f7c2015-07-08 10:04:58234 for (const auto& linked_icon : linked_icons_) {
235 sync_pb::LinkedAppIconInfo* linked_app_icon_info =
236 specifics->add_linked_app_icons();
237 linked_app_icon_info->set_url(linked_icon.url.spec());
238 linked_app_icon_info->set_size(linked_icon.size);
239 }
240
241 ToExtensionSpecifics(specifics->mutable_extension());
242}
243
yoz870444532015-03-12 18:42:53244bool ExtensionSyncData::PopulateFromExtensionSpecifics(
[email protected]3bdba0d2011-08-23 07:17:30245 const sync_pb::ExtensionSpecifics& specifics) {
[email protected]fdd28372014-08-21 02:27:26246 if (!crx_file::id_util::IdIsValid(specifics.id())) {
yoz870444532015-03-12 18:42:53247 LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics (bad ID):\n"
yoz768503cd2015-02-24 03:40:31248 << GetExtensionSpecificsLogMessage(specifics);
yoz870444532015-03-12 18:42:53249 RecordBadSyncData(BAD_EXTENSION_ID);
250 return false;
[email protected]3bdba0d2011-08-23 07:17:30251 }
252
pwnallcbd73192016-08-22 18:59:17253 base::Version specifics_version(specifics.version());
yoz768503cd2015-02-24 03:40:31254 if (!specifics_version.IsValid()) {
yoz870444532015-03-12 18:42:53255 LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics (bad version):\n"
yoz768503cd2015-02-24 03:40:31256 << GetExtensionSpecificsLogMessage(specifics);
yoz870444532015-03-12 18:42:53257 RecordBadSyncData(BAD_VERSION);
258 return false;
yoz768503cd2015-02-24 03:40:31259 }
[email protected]3bdba0d2011-08-23 07:17:30260
261 // The update URL must be either empty or valid.
262 GURL specifics_update_url(specifics.update_url());
263 if (!specifics_update_url.is_empty() && !specifics_update_url.is_valid()) {
yoz870444532015-03-12 18:42:53264 LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics (bad update URL):\n"
yoz768503cd2015-02-24 03:40:31265 << GetExtensionSpecificsLogMessage(specifics);
yoz870444532015-03-12 18:42:53266 RecordBadSyncData(BAD_UPDATE_URL);
267 return false;
[email protected]3bdba0d2011-08-23 07:17:30268 }
269
270 id_ = specifics.id();
271 update_url_ = specifics_update_url;
[email protected]e1adb9a2011-09-09 17:42:52272 version_ = specifics_version;
[email protected]3bdba0d2011-08-23 07:17:30273 enabled_ = specifics.enabled();
treib231f2bb2015-06-09 12:46:24274 supports_disable_reasons_ = specifics.has_disable_reasons();
treibc1192322015-05-20 12:56:07275 disable_reasons_ = specifics.disable_reasons();
[email protected]3bdba0d2011-08-23 07:17:30276 incognito_enabled_ = specifics.incognito_enabled();
rdevlin.cronind1aa8522015-02-13 00:25:57277 if (specifics.has_all_urls_enabled()) {
278 all_urls_enabled_ =
279 specifics.all_urls_enabled() ? BOOLEAN_TRUE : BOOLEAN_FALSE;
280 } else {
281 // Set this explicitly (even though it's the default) on the offchance
282 // that someone is re-using an ExtensionSyncData object.
283 all_urls_enabled_ = BOOLEAN_UNSET;
284 }
[email protected]075b3922014-05-03 06:14:17285 remote_install_ = specifics.remote_install();
[email protected]6338fa32014-07-16 21:41:59286 installed_by_custodian_ = specifics.installed_by_custodian();
[email protected]3bdba0d2011-08-23 07:17:30287 name_ = specifics.name();
yoz870444532015-03-12 18:42:53288 return true;
[email protected]3bdba0d2011-08-23 07:17:30289}
290
treib0c714f7c2015-07-08 10:04:58291bool ExtensionSyncData::PopulateFromAppSpecifics(
292 const sync_pb::AppSpecifics& specifics) {
293 if (!PopulateFromExtensionSpecifics(specifics.extension()))
294 return false;
295
296 is_app_ = true;
297
298 app_launch_ordinal_ = syncer::StringOrdinal(specifics.app_launch_ordinal());
299 page_ordinal_ = syncer::StringOrdinal(specifics.page_ordinal());
300
301 launch_type_ = specifics.has_launch_type()
302 ? static_cast<extensions::LaunchType>(specifics.launch_type())
303 : LAUNCH_TYPE_INVALID;
304
305 bookmark_app_url_ = specifics.bookmark_app_url();
306 bookmark_app_description_ = specifics.bookmark_app_description();
Christopher Lamcec8c4f2017-10-16 01:38:43307 bookmark_app_scope_ = specifics.bookmark_app_scope();
treib0c714f7c2015-07-08 10:04:58308 bookmark_app_icon_color_ = specifics.bookmark_app_icon_color();
Christopher Lamcec8c4f2017-10-16 01:38:43309 if (specifics.has_bookmark_app_theme_color())
310 bookmark_app_theme_color_ = specifics.bookmark_app_theme_color();
treib0c714f7c2015-07-08 10:04:58311
312 for (int i = 0; i < specifics.linked_app_icons_size(); ++i) {
313 const sync_pb::LinkedAppIconInfo& linked_app_icon_info =
314 specifics.linked_app_icons(i);
315 if (linked_app_icon_info.has_url() && linked_app_icon_info.has_size()) {
316 LinkedAppIconInfo linked_icon;
317 linked_icon.url = GURL(linked_app_icon_info.url());
318 linked_icon.size = linked_app_icon_info.size();
319 linked_icons_.push_back(linked_icon);
320 }
321 }
322
323 return true;
324}
325
yoz870444532015-03-12 18:42:53326bool ExtensionSyncData::PopulateFromSyncData(
[email protected]65f173552012-06-28 22:43:58327 const syncer::SyncData& sync_data) {
[email protected]3bdba0d2011-08-23 07:17:30328 const sync_pb::EntitySpecifics& entity_specifics = sync_data.GetSpecifics();
[email protected]168389f2011-12-20 17:12:48329
treib0c714f7c2015-07-08 10:04:58330 if (entity_specifics.has_app())
331 return PopulateFromAppSpecifics(entity_specifics.app());
332
yoz870444532015-03-12 18:42:53333 if (entity_specifics.has_extension())
334 return PopulateFromExtensionSpecifics(entity_specifics.extension());
335
336 LOG(ERROR) << "Attempt to sync bad EntitySpecifics: no extension data.";
337 RecordBadSyncData(NO_EXTENSION_SPECIFICS);
338 return false;
[email protected]3bdba0d2011-08-23 07:17:30339}
[email protected]5db9ada2012-04-11 13:48:20340
341} // namespace extensions