Upstream version 10.39.225.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 install_silently,
94     bool remote_install,
95     bool installed_by_custodian) {
96   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
97
98   if (ExtensionRegistry::Get(context_)->GetExtensionById(
99           id, ExtensionRegistry::EVERYTHING)) {
100     LOG(ERROR) << "Trying to add pending extension " << id
101                << " which already exists";
102     return false;
103   }
104
105   // Make sure we don't ever try to install the CWS app, because even though
106   // it is listed as a syncable app (because its values need to be synced) it
107   // should already be installed on every instance.
108   if (id == extensions::kWebStoreAppId) {
109     NOTREACHED();
110     return false;
111   }
112
113   int creation_flags = Extension::NO_FLAGS;
114   if (installed_by_custodian) {
115     creation_flags |= Extension::WAS_INSTALLED_BY_CUSTODIAN;
116   }
117
118   static const bool kIsFromSync = true;
119   static const Manifest::Location kSyncLocation = Manifest::INTERNAL;
120   static const bool kMarkAcknowledged = false;
121
122   return AddExtensionImpl(id,
123                           std::string(),
124                           update_url,
125                           Version(),
126                           should_allow_install,
127                           kIsFromSync,
128                           install_silently,
129                           kSyncLocation,
130                           creation_flags,
131                           kMarkAcknowledged,
132                           remote_install);
133 }
134
135 bool PendingExtensionManager::AddFromExtensionImport(
136     const std::string& id,
137     const GURL& update_url,
138     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install) {
139   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140
141   if (ExtensionRegistry::Get(context_)->GetExtensionById(
142           id, ExtensionRegistry::EVERYTHING)) {
143     LOG(ERROR) << "Trying to add pending extension " << id
144                << " which already exists";
145     return false;
146   }
147
148   static const bool kIsFromSync = false;
149   static const bool kInstallSilently = true;
150   static const Manifest::Location kManifestLocation = Manifest::INTERNAL;
151   static const bool kMarkAcknowledged = false;
152   static const bool kRemoteInstall = false;
153
154   return AddExtensionImpl(id,
155                           std::string(),
156                           update_url,
157                           Version(),
158                           should_allow_install,
159                           kIsFromSync,
160                           kInstallSilently,
161                           kManifestLocation,
162                           Extension::NO_FLAGS,
163                           kMarkAcknowledged,
164                           kRemoteInstall);
165 }
166
167 bool PendingExtensionManager::AddFromExternalUpdateUrl(
168     const std::string& id,
169     const std::string& install_parameter,
170     const GURL& update_url,
171     Manifest::Location location,
172     int creation_flags,
173     bool mark_acknowledged) {
174   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175
176   static const bool kIsFromSync = false;
177   static const bool kInstallSilently = true;
178   static const bool kRemoteInstall = false;
179
180   const Extension* extension = ExtensionRegistry::Get(context_)
181       ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
182   if (extension && location == Manifest::GetHigherPriorityLocation(
183                                    location, extension->location())) {
184     // If the new location has higher priority than the location of an existing
185     // extension, let the update process overwrite the existing extension.
186   } else {
187     if (ExtensionPrefs::Get(context_)->IsExternalExtensionUninstalled(id))
188       return false;
189
190     if (extension) {
191       LOG(DFATAL) << "Trying to add extension " << id
192                   << " by external update, but it is already installed.";
193       return false;
194     }
195   }
196
197   return AddExtensionImpl(id,
198                           install_parameter,
199                           update_url,
200                           Version(),
201                           &AlwaysInstall,
202                           kIsFromSync,
203                           kInstallSilently,
204                           location,
205                           creation_flags,
206                           mark_acknowledged,
207                           kRemoteInstall);
208 }
209
210
211 bool PendingExtensionManager::AddFromExternalFile(
212     const std::string& id,
213     Manifest::Location install_source,
214     const Version& version,
215     int creation_flags,
216     bool mark_acknowledged) {
217   // TODO(skerner): AddFromSync() checks to see if the extension is
218   // installed, but this method assumes that the caller already
219   // made sure it is not installed.  Make all AddFrom*() methods
220   // consistent.
221   const GURL& kUpdateUrl = GURL::EmptyGURL();
222   static const bool kIsFromSync = false;
223   static const bool kInstallSilently = true;
224   static const bool kRemoteInstall = false;
225
226   return AddExtensionImpl(id,
227                           std::string(),
228                           kUpdateUrl,
229                           version,
230                           &AlwaysInstall,
231                           kIsFromSync,
232                           kInstallSilently,
233                           install_source,
234                           creation_flags,
235                           mark_acknowledged,
236                           kRemoteInstall);
237 }
238
239 void PendingExtensionManager::GetPendingIdsForUpdateCheck(
240     std::list<std::string>* out_ids_for_update_check) const {
241   PendingExtensionList::const_iterator iter;
242   for (iter = pending_extension_list_.begin();
243        iter != pending_extension_list_.end();
244        ++iter) {
245     Manifest::Location install_source = iter->install_source();
246
247     // Some install sources read a CRX from the filesystem.  They can
248     // not be fetched from an update URL, so don't include them in the
249     // set of ids.
250     if (install_source == Manifest::EXTERNAL_PREF ||
251         install_source == Manifest::EXTERNAL_REGISTRY)
252       continue;
253
254     out_ids_for_update_check->push_back(iter->id());
255   }
256 }
257
258 bool PendingExtensionManager::AddExtensionImpl(
259     const std::string& id,
260     const std::string& install_parameter,
261     const GURL& update_url,
262     const Version& version,
263     PendingExtensionInfo::ShouldAllowInstallPredicate should_allow_install,
264     bool is_from_sync,
265     bool install_silently,
266     Manifest::Location install_source,
267     int creation_flags,
268     bool mark_acknowledged,
269     bool remote_install) {
270   CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271
272   PendingExtensionInfo info(id,
273                             install_parameter,
274                             update_url,
275                             version,
276                             should_allow_install,
277                             is_from_sync,
278                             install_silently,
279                             install_source,
280                             creation_flags,
281                             mark_acknowledged,
282                             remote_install);
283
284   if (const PendingExtensionInfo* pending = GetById(id)) {
285     // Bugs in this code will manifest as sporadic incorrect extension
286     // locations in situations where multiple install sources run at the
287     // same time. For example, on first login to a chrome os machine, an
288     // extension may be requested by sync and the default extension set.
289     // The following logging will help diagnose such issues.
290     VLOG(1) << "Extension id " << id
291             << " was entered for update more than once."
292             << "  old location: " << pending->install_source()
293             << "  new location: " << install_source
294             << "  old version: " << GetVersionString(pending->version())
295             << "  new version: " << GetVersionString(version);
296
297     // Never override an existing extension with an older version. Only
298     // extensions from local CRX files have a known version; extensions from an
299     // update URL will get the latest version.
300
301     // If |pending| has the same or higher precedence than |info| then don't
302     // install |info| over |pending|.
303     if (pending->CompareTo(info) >= 0)
304       return false;
305
306     VLOG(1) << "Overwrite existing record.";
307
308     std::replace(pending_extension_list_.begin(),
309                  pending_extension_list_.end(),
310                  *pending,
311                  info);
312   } else {
313     pending_extension_list_.push_back(info);
314   }
315
316   return true;
317 }
318
319 void PendingExtensionManager::AddForTesting(
320     const PendingExtensionInfo& pending_extension_info) {
321   pending_extension_list_.push_back(pending_extension_info);
322 }
323
324 }  // namespace extensions