1 // Copyright (c) 2012 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.
5 #include "chrome/browser/extensions/extension_sync_data.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram_macros.h"
9 #include "base/strings/stringprintf.h"
10 #include "chrome/browser/extensions/app_sync_data.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "components/crx_file/id_util.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/manifest_url_handlers.h"
15 #include "sync/api/sync_data.h"
16 #include "sync/protocol/extension_specifics.pb.h"
17 #include "sync/protocol/sync.pb.h"
19 namespace extensions
{
23 std::string
GetExtensionSpecificsLogMessage(
24 const sync_pb::ExtensionSpecifics
& specifics
) {
25 return base::StringPrintf("id: %s\nversion: %s\nupdate_url: %s",
26 specifics
.id().c_str(),
27 specifics
.version().c_str(),
28 specifics
.update_url().c_str());
31 enum BadSyncDataReason
{
32 // Invalid extension ID.
38 // Invalid update URL.
41 // No ExtensionSpecifics in the EntitySpecifics.
42 NO_EXTENSION_SPECIFICS
,
44 // Must be at the end.
45 NUM_BAD_SYNC_DATA_REASONS
48 void RecordBadSyncData(BadSyncDataReason reason
) {
49 UMA_HISTOGRAM_ENUMERATION("Extensions.BadSyncDataReason", reason
,
50 NUM_BAD_SYNC_DATA_REASONS
);
55 ExtensionSyncData::ExtensionSyncData()
56 : uninstalled_(false),
58 incognito_enabled_(false),
59 remote_install_(false),
60 all_urls_enabled_(BOOLEAN_UNSET
),
61 installed_by_custodian_(false) {
64 ExtensionSyncData::ExtensionSyncData(const Extension
& extension
,
66 bool incognito_enabled
,
68 OptionalBoolean all_urls_enabled
)
69 : id_(extension
.id()),
72 incognito_enabled_(incognito_enabled
),
73 remote_install_(remote_install
),
74 all_urls_enabled_(all_urls_enabled
),
75 installed_by_custodian_(extension
.was_installed_by_custodian()),
76 version_(extension
.from_bookmark() ? base::Version("0")
77 : *extension
.version()),
78 update_url_(ManifestURL::GetUpdateURL(&extension
)),
79 name_(extension
.non_localized_name()) {
82 ExtensionSyncData::~ExtensionSyncData() {}
85 scoped_ptr
<ExtensionSyncData
> ExtensionSyncData::CreateFromSyncData(
86 const syncer::SyncData
& sync_data
) {
87 scoped_ptr
<ExtensionSyncData
> data(new ExtensionSyncData
);
88 if (data
->PopulateFromSyncData(sync_data
))
90 return scoped_ptr
<ExtensionSyncData
>();
94 scoped_ptr
<ExtensionSyncData
> ExtensionSyncData::CreateFromSyncChange(
95 const syncer::SyncChange
& sync_change
) {
96 scoped_ptr
<ExtensionSyncData
> data(
97 CreateFromSyncData(sync_change
.sync_data()));
99 return scoped_ptr
<ExtensionSyncData
>();
101 data
->set_uninstalled(sync_change
.change_type() ==
102 syncer::SyncChange::ACTION_DELETE
);
106 syncer::SyncData
ExtensionSyncData::GetSyncData() const {
107 sync_pb::EntitySpecifics specifics
;
108 PopulateExtensionSpecifics(specifics
.mutable_extension());
110 return syncer::SyncData::CreateLocalData(id_
, name_
, specifics
);
113 syncer::SyncChange
ExtensionSyncData::GetSyncChange(
114 syncer::SyncChange::SyncChangeType change_type
) const {
115 return syncer::SyncChange(FROM_HERE
, change_type
, GetSyncData());
118 void ExtensionSyncData::PopulateExtensionSpecifics(
119 sync_pb::ExtensionSpecifics
* specifics
) const {
120 DCHECK(crx_file::id_util::IdIsValid(id_
));
121 specifics
->set_id(id_
);
122 specifics
->set_update_url(update_url_
.spec());
123 specifics
->set_version(version_
.GetString());
124 specifics
->set_enabled(enabled_
);
125 specifics
->set_incognito_enabled(incognito_enabled_
);
126 specifics
->set_remote_install(remote_install_
);
127 if (all_urls_enabled_
!= BOOLEAN_UNSET
)
128 specifics
->set_all_urls_enabled(all_urls_enabled_
== BOOLEAN_TRUE
);
129 specifics
->set_installed_by_custodian(installed_by_custodian_
);
130 specifics
->set_name(name_
);
133 bool ExtensionSyncData::PopulateFromExtensionSpecifics(
134 const sync_pb::ExtensionSpecifics
& specifics
) {
135 if (!crx_file::id_util::IdIsValid(specifics
.id())) {
136 LOG(ERROR
) << "Attempt to sync bad ExtensionSpecifics (bad ID):\n"
137 << GetExtensionSpecificsLogMessage(specifics
);
138 RecordBadSyncData(BAD_EXTENSION_ID
);
142 Version
specifics_version(specifics
.version());
143 if (!specifics_version
.IsValid()) {
144 LOG(ERROR
) << "Attempt to sync bad ExtensionSpecifics (bad version):\n"
145 << GetExtensionSpecificsLogMessage(specifics
);
146 RecordBadSyncData(BAD_VERSION
);
150 // The update URL must be either empty or valid.
151 GURL
specifics_update_url(specifics
.update_url());
152 if (!specifics_update_url
.is_empty() && !specifics_update_url
.is_valid()) {
153 LOG(ERROR
) << "Attempt to sync bad ExtensionSpecifics (bad update URL):\n"
154 << GetExtensionSpecificsLogMessage(specifics
);
155 RecordBadSyncData(BAD_UPDATE_URL
);
159 id_
= specifics
.id();
160 update_url_
= specifics_update_url
;
161 version_
= specifics_version
;
162 enabled_
= specifics
.enabled();
163 incognito_enabled_
= specifics
.incognito_enabled();
164 if (specifics
.has_all_urls_enabled()) {
166 specifics
.all_urls_enabled() ? BOOLEAN_TRUE
: BOOLEAN_FALSE
;
168 // Set this explicitly (even though it's the default) on the offchance
169 // that someone is re-using an ExtensionSyncData object.
170 all_urls_enabled_
= BOOLEAN_UNSET
;
172 remote_install_
= specifics
.remote_install();
173 installed_by_custodian_
= specifics
.installed_by_custodian();
174 name_
= specifics
.name();
178 void ExtensionSyncData::set_uninstalled(bool uninstalled
) {
179 uninstalled_
= uninstalled
;
182 bool ExtensionSyncData::PopulateFromSyncData(
183 const syncer::SyncData
& sync_data
) {
184 const sync_pb::EntitySpecifics
& entity_specifics
= sync_data
.GetSpecifics();
186 if (entity_specifics
.has_extension())
187 return PopulateFromExtensionSpecifics(entity_specifics
.extension());
189 LOG(ERROR
) << "Attempt to sync bad EntitySpecifics: no extension data.";
190 RecordBadSyncData(NO_EXTENSION_SPECIFICS
);
194 } // namespace extensions