Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / pending_extension_manager.cc
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.
4
5 #include "chrome/browser/extensions/pending_extension_manager.h"
6
7 #include <algorithm>
8
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"
18
19 using content::BrowserThread;
20
21 namespace {
22
23 // Install predicate used by AddFromExternalUpdateUrl().
24 bool AlwaysInstall(const extensions::Extension* extension) {
25   return true;
26 }
27
28 std::string GetVersionString(const Version& version) {
29   return version.IsValid() ? version.GetString() : "invalid";
30 }
31
32 }  // namespace
33
34 namespace extensions {
35
36 PendingExtensionManager::PendingExtensionManager(
37     content::BrowserContext* context)
38     : context_(context) {}
39
40 PendingExtensionManager::~PendingExtensionManager() {}
41
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);
50   }
51
52   return NULL;
53 }
54
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;
63     }
64   }
65
66   return false;
67 }
68
69 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
70   return GetById(id) != NULL;
71 }
72
73 bool PendingExtensionManager::HasPendingExtensions() const {
74   return !pending_extension_list_.empty();
75 }
76
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;
84   }
85
86   return false;
87 }
88
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));
96
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;
102   }
103
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;
110   }
111
112   int creation_flags = Extension::NO_FLAGS;
113   if (installed_by_custodian) {
114     creation_flags |= Extension::WAS_INSTALLED_BY_CUSTODIAN;
115   }
116
117   static const bool kIsFromSync = true;
118   static const Manifest::Location kSyncLocation = Manifest::INTERNAL;
119   static const bool kMarkAcknowledged = false;
120
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);
131 }
132
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));
138
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;
144   }
145
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;
150
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);
161 }
162
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));
171
172   static const bool kIsFromSync = false;
173   static const bool kRemoteInstall = false;
174
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;
184
185     if (extension) {
186       LOG(DFATAL) << "Trying to add extension " << id
187                   << " by external update, but it is already installed.";
188       return false;
189     }
190   }
191
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);
202 }
203
204
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;
218
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);
229 }
230
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();
238
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;
245
246     out_ids_for_update_check->push_back(iter->id());
247   }
248 }
249
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));
262
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);
273
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);
286
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.
290
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;
295
296     VLOG(1) << "Overwrite existing record.";
297
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);
304   }
305
306   return true;
307 }
308
309 void PendingExtensionManager::AddForTesting(
310     const PendingExtensionInfo& pending_extension_info) {
311   pending_extension_list_.push_back(pending_extension_info);
312 }
313
314 }  // namespace extensions