Upstream version 9.38.198.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/extension.h"
16 #include "url/gurl.h"
17
18 using content::BrowserThread;
19
20 namespace {
21
22 // Install predicate used by AddFromExternalUpdateUrl().
23 bool AlwaysInstall(const extensions::Extension* extension) {
24   return true;
25 }
26
27 std::string GetVersionString(const Version& version) {
28   return version.IsValid() ? version.GetString() : "invalid";
29 }
30
31 }  // namespace
32
33 namespace extensions {
34
35 PendingExtensionManager::PendingExtensionManager(
36     content::BrowserContext* context)
37     : context_(context) {}
38
39 PendingExtensionManager::~PendingExtensionManager() {}
40
41 const PendingExtensionInfo* PendingExtensionManager::GetById(
42     const std::string& id) const {
43   PendingExtensionList::const_iterator iter;
44   for (iter = pending_extension_list_.begin();
45        iter != pending_extension_list_.end();
46        ++iter) {
47     if (id == iter->id())
48       return &(*iter);
49   }
50
51   return NULL;
52 }
53
54 bool PendingExtensionManager::Remove(const std::string& id) {
55   PendingExtensionList::iterator iter;
56   for (iter = pending_extension_list_.begin();
57        iter != pending_extension_list_.end();
58        ++iter) {
59     if (id == iter->id()) {
60       pending_extension_list_.erase(iter);
61       return true;
62     }
63   }
64
65   return false;
66 }
67
68 bool PendingExtensionManager::IsIdPending(const std::string& id) const {
69   return GetById(id) != NULL;
70 }
71
72 bool PendingExtensionManager::HasPendingExtensions() const {
73   return !pending_extension_list_.empty();
74 }
75
76 bool PendingExtensionManager::HasPendingExtensionFromSync() const {
77   PendingExtensionList::const_iterator iter;
78   for (iter = pending_extension_list_.begin();
79        iter != pending_extension_list_.end();
80        ++iter) {
81     if (iter->is_from_sync())
82       return true;
83   }
84
85   return false;
86 }
87
88 bool PendingExtensionManager::AddFromSync(
89     const std::string& id,
90     const GURL& update_url,
91     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
92     bool install_silently,
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 == extension_misc::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                           install_silently,
128                           kSyncLocation,
129                           creation_flags,
130                           kMarkAcknowledged,
131                           remote_install);
132 }
133
134 bool PendingExtensionManager::AddFromExtensionImport(
135     const std::string& id,
136     const GURL& update_url,
137     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
138   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
139
140   if (ExtensionRegistry::Get(context_)->GetExtensionById(
141           id, ExtensionRegistry::EVERYTHING)) {
142     LOG(ERROR) << "Trying to add pending extension " << id
143                << " which already exists";
144     return false;
145   }
146
147   static const bool kIsFromSync = false;
148   static const bool kInstallSilently = true;
149   static const Manifest::Location kManifestLocation = Manifest::INTERNAL;
150   static const bool kMarkAcknowledged = false;
151   static const bool kRemoteInstall = false;
152
153   return AddExtensionImpl(id,
154                           std::string(),
155                           update_url,
156                           Version(),
157                           should_allow_install,
158                           kIsFromSync,
159                           kInstallSilently,
160                           kManifestLocation,
161                           Extension::NO_FLAGS,
162                           kMarkAcknowledged,
163                           kRemoteInstall);
164 }
165
166 bool PendingExtensionManager::AddFromExternalUpdateUrl(
167     const std::string& id,
168     const std::string& install_parameter,
169     const GURL& update_url,
170     Manifest::Location location,
171     int creation_flags,
172     bool mark_acknowledged) {
173   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174
175   static const bool kIsFromSync = false;
176   static const bool kInstallSilently = true;
177   static const bool kRemoteInstall = false;
178
179   const Extension* extension = ExtensionRegistry::Get(context_)
180       ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
181   if (extension && location == Manifest::GetHigherPriorityLocation(
182                                    location, extension->location())) {
183     // If the new location has higher priority than the location of an existing
184     // extension, let the update process overwrite the existing extension.
185   } else {
186     if (ExtensionPrefs::Get(context_)->IsExternalExtensionUninstalled(id))
187       return false;
188
189     if (extension) {
190       LOG(DFATAL) << "Trying to add extension " << id
191                   << " by external update, but it is already installed.";
192       return false;
193     }
194   }
195
196   return AddExtensionImpl(id,
197                           install_parameter,
198                           update_url,
199                           Version(),
200                           &AlwaysInstall,
201                           kIsFromSync,
202                           kInstallSilently,
203                           location,
204                           creation_flags,
205                           mark_acknowledged,
206                           kRemoteInstall);
207 }
208
209
210 bool PendingExtensionManager::AddFromExternalFile(
211     const std::string& id,
212     Manifest::Location install_source,
213     const Version& version,
214     int creation_flags,
215     bool mark_acknowledged) {
216   // TODO(skerner): AddFromSync() checks to see if the extension is
217   // installed, but this method assumes that the caller already
218   // made sure it is not installed.  Make all AddFrom*() methods
219   // consistent.
220   const GURL& kUpdateUrl = GURL::EmptyGURL();
221   static const bool kIsFromSync = false;
222   static const bool kInstallSilently = true;
223   static const bool kRemoteInstall = false;
224
225   return AddExtensionImpl(id,
226                           std::string(),
227                           kUpdateUrl,
228                           version,
229                           &AlwaysInstall,
230                           kIsFromSync,
231                           kInstallSilently,
232                           install_source,
233                           creation_flags,
234                           mark_acknowledged,
235                           kRemoteInstall);
236 }
237
238 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
239     std::list<std::string>* out_ids_for_update_check) const {
240   PendingExtensionList::const_iterator iter;
241   for (iter = pending_extension_list_.begin();
242        iter != pending_extension_list_.end();
243        ++iter) {
244     Manifest::Location install_source = iter->install_source();
245
246     // Some install sources read a CRX from the filesystem.  They can
247     // not be fetched from an update URL, so don't include them in the
248     // set of ids.
249     if (install_source == Manifest::EXTERNAL_PREF ||
250         install_source == Manifest::EXTERNAL_REGISTRY)
251       continue;
252
253     out_ids_for_update_check->push_back(iter->id());
254   }
255 }
256
257 bool PendingExtensionManager::AddExtensionImpl(
258     const std::string& id,
259     const std::string& install_parameter,
260     const GURL& update_url,
261     const Version& version,
262     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
263     bool is_from_sync,
264     bool install_silently,
265     Manifest::Location install_source,
266     int creation_flags,
267     bool mark_acknowledged,
268     bool remote_install) {
269   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
270
271   PendingExtensionInfo info(id,
272                             install_parameter,
273                             update_url,
274                             version,
275                             should_allow_install,
276                             is_from_sync,
277                             install_silently,
278                             install_source,
279                             creation_flags,
280                             mark_acknowledged,
281                             remote_install);
282
283   if (const PendingExtensionInfo* pending = GetById(id)) {
284     // Bugs in this code will manifest as sporadic incorrect extension
285     // locations in situations where multiple install sources run at the
286     // same time. For example, on first login to a chrome os machine, an
287     // extension may be requested by sync and the default extension set.
288     // The following logging will help diagnose such issues.
289     VLOG(1) << "Extension id " << id
290             << " was entered for update more than once."
291             << "  old location: " << pending->install_source()
292             << "  new location: " << install_source
293             << "  old version: " << GetVersionString(pending->version())
294             << "  new version: " << GetVersionString(version);
295
296     // Never override an existing extension with an older version. Only
297     // extensions from local CRX files have a known version; extensions from an
298     // update URL will get the latest version.
299
300     // If |pending| has the same or higher precedence than |info| then don't
301     // install |info| over |pending|.
302     if (pending->CompareTo(info) >= 0)
303       return false;
304
305     VLOG(1) << "Overwrite existing record.";
306
307     std::replace(pending_extension_list_.begin(),
308                  pending_extension_list_.end(),
309                  *pending,
310                  info);
311   } else {
312     pending_extension_list_.push_back(info);
313   }
314
315   return true;
316 }
317
318 void PendingExtensionManager::AddForTesting(
319     const PendingExtensionInfo& pending_extension_info) {
320   pending_extension_list_.push_back(pending_extension_info);
321 }
322
323 }  // namespace extensions