Extensions cleanup: Merge IsSyncableApp+Extension, ShouldSyncApp+Extension
[chromium-blink-merge.git] / chrome / browser / extensions / pending_extension_manager.cc
blobf643ef4783ea6735c0de069ebb5625bee1c52116
1 // Copyright 2014 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/pending_extension_manager.h"
7 #include <algorithm>
9 #include "base/logging.h"
10 #include "base/version.h"
11 #include "chrome/common/extensions/extension_constants.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "extensions/browser/extension_prefs.h"
14 #include "extensions/browser/extension_registry.h"
15 #include "extensions/common/constants.h"
16 #include "extensions/common/extension.h"
17 #include "url/gurl.h"
19 using content::BrowserThread;
21 namespace {
23 // Install predicate used by AddFromExternalUpdateUrl().
24 bool AlwaysInstall(const extensions::Extension* extension) {
25 return true;
28 std::string GetVersionString(const Version& version) {
29 return version.IsValid() ? version.GetString() : "invalid";
32 } // namespace
34 namespace extensions {
36 PendingExtensionManager::PendingExtensionManager(
37 content::BrowserContext* context)
38 : context_(context) {}
40 PendingExtensionManager::~PendingExtensionManager() {}
42 const PendingExtensionInfo* PendingExtensionManager::GetById(
43 const std::string& id) const {
44 PendingExtensionList::const_iterator iter;
45 for (iter = pending_extension_list_.begin();
46 iter != pending_extension_list_.end();
47 ++iter) {
48 if (id == iter->id())
49 return &(*iter);
52 return NULL;
55 bool PendingExtensionManager::Remove(const std::string& id) {
56 PendingExtensionList::iterator iter;
57 for (iter = pending_extension_list_.begin();
58 iter != pending_extension_list_.end();
59 ++iter) {
60 if (id == iter->id()) {
61 pending_extension_list_.erase(iter);
62 return true;
66 return false;
69 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
70 return GetById(id) != NULL;
73 bool PendingExtensionManager::HasPendingExtensions() const {
74 return !pending_extension_list_.empty();
77 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
78 PendingExtensionList::const_iterator iter;
79 for (iter = pending_extension_list_.begin();
80 iter != pending_extension_list_.end();
81 ++iter) {
82 if (iter->is_from_sync())
83 return true;
86 return false;
89 bool PendingExtensionManager::AddFromSync(
90 const std::string& id,
91 const GURL& update_url,
92 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
93 bool remote_install,
94 bool installed_by_custodian) {
95 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
97 if (ExtensionRegistry::Get(context_)->GetExtensionById(
98 id, ExtensionRegistry::EVERYTHING)) {
99 LOG(ERROR) << "Trying to add pending extension " << id
100 << " which already exists";
101 return false;
104 // Make sure we don't ever try to install the CWS app, because even though
105 // it is listed as a syncable app (because its values need to be synced) it
106 // should already be installed on every instance.
107 if (id == extensions::kWebStoreAppId) {
108 NOTREACHED();
109 return false;
112 int creation_flags = Extension::NO_FLAGS;
113 if (installed_by_custodian) {
114 creation_flags |= Extension::WAS_INSTALLED_BY_CUSTODIAN;
117 static const bool kIsFromSync = true;
118 static const Manifest::Location kSyncLocation = Manifest::INTERNAL;
119 static const bool kMarkAcknowledged = false;
121 return AddExtensionImpl(id,
122 std::string(),
123 update_url,
124 Version(),
125 should_allow_install,
126 kIsFromSync,
127 kSyncLocation,
128 creation_flags,
129 kMarkAcknowledged,
130 remote_install);
133 bool PendingExtensionManager::AddFromExtensionImport(
134 const std::string& id,
135 const GURL& update_url,
136 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
137 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139 if (ExtensionRegistry::Get(context_)->GetExtensionById(
140 id, ExtensionRegistry::EVERYTHING)) {
141 LOG(ERROR) << "Trying to add pending extension " << id
142 << " which already exists";
143 return false;
146 static const bool kIsFromSync = false;
147 static const Manifest::Location kManifestLocation = Manifest::INTERNAL;
148 static const bool kMarkAcknowledged = false;
149 static const bool kRemoteInstall = false;
151 return AddExtensionImpl(id,
152 std::string(),
153 update_url,
154 Version(),
155 should_allow_install,
156 kIsFromSync,
157 kManifestLocation,
158 Extension::NO_FLAGS,
159 kMarkAcknowledged,
160 kRemoteInstall);
163 bool PendingExtensionManager::AddFromExternalUpdateUrl(
164 const std::string& id,
165 const std::string& install_parameter,
166 const GURL& update_url,
167 Manifest::Location location,
168 int creation_flags,
169 bool mark_acknowledged) {
170 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
172 static const bool kIsFromSync = false;
173 static const bool kRemoteInstall = false;
175 const Extension* extension = ExtensionRegistry::Get(context_)
176 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
177 if (extension && location == Manifest::GetHigherPriorityLocation(
178 location, extension->location())) {
179 // If the new location has higher priority than the location of an existing
180 // extension, let the update process overwrite the existing extension.
181 } else {
182 if (ExtensionPrefs::Get(context_)->IsExternalExtensionUninstalled(id))
183 return false;
185 if (extension) {
186 LOG(DFATAL) << "Trying to add extension " << id
187 << " by external update, but it is already installed.";
188 return false;
192 return AddExtensionImpl(id,
193 install_parameter,
194 update_url,
195 Version(),
196 &AlwaysInstall,
197 kIsFromSync,
198 location,
199 creation_flags,
200 mark_acknowledged,
201 kRemoteInstall);
205 bool PendingExtensionManager::AddFromExternalFile(
206 const std::string& id,
207 Manifest::Location install_source,
208 const Version& version,
209 int creation_flags,
210 bool mark_acknowledged) {
211 // TODO(skerner): AddFromSync() checks to see if the extension is
212 // installed, but this method assumes that the caller already
213 // made sure it is not installed. Make all AddFrom*() methods
214 // consistent.
215 const GURL& kUpdateUrl = GURL::EmptyGURL();
216 static const bool kIsFromSync = false;
217 static const bool kRemoteInstall = false;
219 return AddExtensionImpl(id,
220 std::string(),
221 kUpdateUrl,
222 version,
223 &AlwaysInstall,
224 kIsFromSync,
225 install_source,
226 creation_flags,
227 mark_acknowledged,
228 kRemoteInstall);
231 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
232 std::list<std::string>* out_ids_for_update_check) const {
233 PendingExtensionList::const_iterator iter;
234 for (iter = pending_extension_list_.begin();
235 iter != pending_extension_list_.end();
236 ++iter) {
237 Manifest::Location install_source = iter->install_source();
239 // Some install sources read a CRX from the filesystem. They can
240 // not be fetched from an update URL, so don't include them in the
241 // set of ids.
242 if (install_source == Manifest::EXTERNAL_PREF ||
243 install_source == Manifest::EXTERNAL_REGISTRY)
244 continue;
246 out_ids_for_update_check->push_back(iter->id());
250 bool PendingExtensionManager::AddExtensionImpl(
251 const std::string& id,
252 const std::string& install_parameter,
253 const GURL& update_url,
254 const Version& version,
255 PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
256 bool is_from_sync,
257 Manifest::Location install_source,
258 int creation_flags,
259 bool mark_acknowledged,
260 bool remote_install) {
261 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
263 PendingExtensionInfo info(id,
264 install_parameter,
265 update_url,
266 version,
267 should_allow_install,
268 is_from_sync,
269 install_source,
270 creation_flags,
271 mark_acknowledged,
272 remote_install);
274 if (const PendingExtensionInfo* pending = GetById(id)) {
275 // Bugs in this code will manifest as sporadic incorrect extension
276 // locations in situations where multiple install sources run at the
277 // same time. For example, on first login to a chrome os machine, an
278 // extension may be requested by sync and the default extension set.
279 // The following logging will help diagnose such issues.
280 VLOG(1) << "Extension id " << id
281 << " was entered for update more than once."
282 << " old location: " << pending->install_source()
283 << " new location: " << install_source
284 << " old version: " << GetVersionString(pending->version())
285 << " new version: " << GetVersionString(version);
287 // Never override an existing extension with an older version. Only
288 // extensions from local CRX files have a known version; extensions from an
289 // update URL will get the latest version.
291 // If |pending| has the same or higher precedence than |info| then don't
292 // install |info| over |pending|.
293 if (pending->CompareTo(info) >= 0)
294 return false;
296 VLOG(1) << "Overwrite existing record.";
298 std::replace(pending_extension_list_.begin(),
299 pending_extension_list_.end(),
300 *pending,
301 info);
302 } else {
303 pending_extension_list_.push_back(info);
306 return true;
309 void PendingExtensionManager::AddForTesting(
310 const PendingExtensionInfo& pending_extension_info) {
311 pending_extension_list_.push_back(pending_extension_info);
314 } // namespace extensions