1e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Copyright 2014 The Chromium Authors. All rights reserved.
2e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// found in the LICENSE file.
4e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
5e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/browser/extensions/extension_garbage_collector.h"
6e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
7e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/bind.h"
8e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/files/file_enumerator.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
10e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/logging.h"
11e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/memory/scoped_ptr.h"
12e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/message_loop/message_loop.h"
13e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/sequenced_task_runner.h"
14e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/strings/string_util.h"
15e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/strings/utf_string_conversions.h"
16e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "base/time/time.h"
170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/extensions/extension_garbage_collector_factory.h"
18e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/browser/extensions/extension_service.h"
19e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/browser/extensions/extension_util.h"
200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "chrome/browser/extensions/install_tracker.h"
21e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/browser/extensions/pending_extension_manager.h"
22e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
2303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)#include "components/crx_file/id_util.h"
24e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "content/public/browser/browser_context.h"
25e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "content/public/browser/browser_thread.h"
26e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "content/public/browser/storage_partition.h"
27e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "extensions/browser/extension_prefs.h"
28e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "extensions/browser/extension_registry.h"
29e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "extensions/browser/extension_system.h"
30e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch#include "extensions/common/extension.h"
31a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/common/file_util.h"
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/one_shot_event.h"
33e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
34e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochnamespace extensions {
35e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
36e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochnamespace {
37e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
38e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Wait this many seconds before trying to garbage collect extensions again.
39e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst int kGarbageCollectRetryDelayInSeconds = 30;
40e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
41e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// Wait this many seconds after startup to see if there are any extensions
42e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch// which can be garbage collected.
43e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochconst int kGarbageCollectStartupDelay = 30;
44e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
45e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochtypedef std::multimap<std::string, base::FilePath> ExtensionPathsMultimap;
46e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
47e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid CheckExtensionDirectory(const base::FilePath& path,
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                             const ExtensionPathsMultimap& extension_paths) {
49e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  base::FilePath basename = path.BaseName();
50e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Clean up temporary files left if Chrome crashed or quit in the middle
51e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // of an extension install.
52a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  if (basename.value() == file_util::kTempDirectoryName) {
530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    base::DeleteFile(path, true);  // Recursive.
54e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return;
55e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
56e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
57e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Parse directory name as a potential extension ID.
58e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::string extension_id;
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (base::IsStringASCII(basename.value())) {
60e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    extension_id = base::UTF16ToASCII(basename.LossyDisplayName());
6103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    if (!crx_file::id_util::IdIsValid(extension_id))
62e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      extension_id.clear();
63e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
64e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
65e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Delete directories that aren't valid IDs.
66e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (extension_id.empty()) {
67e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    base::DeleteFile(path, true);  // Recursive.
68e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return;
69e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
70e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
71e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  typedef ExtensionPathsMultimap::const_iterator Iter;
72e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::pair<Iter, Iter> iter_pair = extension_paths.equal_range(extension_id);
73e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
74e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // If there is no entry in the prefs file, just delete the directory and
75e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // move on. This can legitimately happen when an uninstall does not
76e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // complete, for example, when a plugin is in use at uninstall time.
77e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (iter_pair.first == iter_pair.second) {
78e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    base::DeleteFile(path, true);  // Recursive.
79e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return;
80e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
81e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
82e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  // Clean up old version directories.
83e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  base::FileEnumerator versions_enumerator(
84e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      path, false /* Not recursive */, base::FileEnumerator::DIRECTORIES);
85e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (base::FilePath version_dir = versions_enumerator.Next();
86e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       !version_dir.empty();
87e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       version_dir = versions_enumerator.Next()) {
88e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    bool known_version = false;
89e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    for (Iter iter = iter_pair.first; iter != iter_pair.second; ++iter) {
90e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      if (version_dir.BaseName() == iter->second.BaseName()) {
91e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        known_version = true;
92e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        break;
93e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      }
94e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
95e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (!known_version)
96e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::DeleteFile(version_dir, true);  // Recursive.
97e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
98e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
99e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
100e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}  // namespace
101e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
102e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochExtensionGarbageCollector::ExtensionGarbageCollector(
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    content::BrowserContext* context)
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    : context_(context), crx_installs_in_progress_(0), weak_factory_(this) {
105e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
106e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ExtensionSystem* extension_system = ExtensionSystem::Get(context_);
107e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK(extension_system);
108e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
109e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  extension_system->ready().PostDelayed(
110e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      FROM_HERE,
111e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::Bind(&ExtensionGarbageCollector::GarbageCollectExtensions,
112e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                 weak_factory_.GetWeakPtr()),
113e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::TimeDelta::FromSeconds(kGarbageCollectStartupDelay));
114e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
115e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  extension_system->ready().Post(
116e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      FROM_HERE,
117e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::Bind(
118e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          &ExtensionGarbageCollector::GarbageCollectIsolatedStorageIfNeeded,
119e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          weak_factory_.GetWeakPtr()));
1200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1210529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  InstallTracker::Get(context_)->AddObserver(this);
122e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
123e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
124e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen MurdochExtensionGarbageCollector::~ExtensionGarbageCollector() {}
125e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch// static
1270529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochExtensionGarbageCollector* ExtensionGarbageCollector::Get(
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    content::BrowserContext* context) {
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return ExtensionGarbageCollectorFactory::GetForBrowserContext(context);
1300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ExtensionGarbageCollector::Shutdown() {
1330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  InstallTracker::Get(context_)->RemoveObserver(this);
1340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
1350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
136e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid ExtensionGarbageCollector::GarbageCollectExtensionsForTest() {
137e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  GarbageCollectExtensions();
138e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
139e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
14046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)// static
14146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionGarbageCollector::GarbageCollectExtensionsOnFileThread(
14246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const base::FilePath& install_directory,
14346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    const ExtensionPathsMultimap& extension_paths) {
14446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
145e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
14646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // Nothing to clean up if it doesn't exist.
14746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!base::DirectoryExists(install_directory))
148e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return;
14946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  base::FileEnumerator enumerator(install_directory,
15146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  false,  // Not recursive.
15246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  base::FileEnumerator::DIRECTORIES);
15346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
15446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  for (base::FilePath extension_path = enumerator.Next();
15546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       !extension_path.empty();
15646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)       extension_path = enumerator.Next()) {
15746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    CheckExtensionDirectory(extension_path, extension_paths);
15846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
15946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
16046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
16146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)void ExtensionGarbageCollector::GarbageCollectExtensions() {
16246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
163e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
164e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context_);
165e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK(extension_prefs);
166e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
167e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (extension_prefs->pref_service()->ReadOnly())
168e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return;
169e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (crx_installs_in_progress_ > 0) {
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Don't garbage collect while there are installations in progress,
172e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // which may be using the temporary installation directory. Try to garbage
173e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    // collect again later.
174e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    base::MessageLoop::current()->PostDelayedTask(
175e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        FROM_HERE,
176e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::Bind(&ExtensionGarbageCollector::GarbageCollectExtensions,
177e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch                   weak_factory_.GetWeakPtr()),
178e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        base::TimeDelta::FromSeconds(kGarbageCollectRetryDelayInSeconds));
1790529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return;
180e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
181e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
182e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
183e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      extension_prefs->GetInstalledExtensionsInfo());
184e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  std::multimap<std::string, base::FilePath> extension_paths;
185e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (size_t i = 0; i < info->size(); ++i) {
186e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    extension_paths.insert(
187e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        std::make_pair(info->at(i)->extension_id, info->at(i)->extension_path));
188e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
189e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
190e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  info = extension_prefs->GetAllDelayedInstallInfo();
191e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  for (size_t i = 0; i < info->size(); ++i) {
192e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    extension_paths.insert(
193e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch        std::make_pair(info->at(i)->extension_id, info->at(i)->extension_path));
194e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
195e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
1960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ExtensionService* service =
1970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ExtensionSystem::Get(context_)->extension_service();
1980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (!service->GetFileTaskRunner()->PostTask(
199e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          FROM_HERE,
2000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch          base::Bind(&GarbageCollectExtensionsOnFileThread,
2010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     service->install_directory(),
2020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                     extension_paths))) {
203e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    NOTREACHED();
204e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
205e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
206e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
207e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdochvoid ExtensionGarbageCollector::GarbageCollectIsolatedStorageIfNeeded() {
208e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
209e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
210e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(context_);
211e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  DCHECK(extension_prefs);
212e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  if (!extension_prefs->NeedsStorageGarbageCollection())
213e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    return;
214e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  extension_prefs->SetNeedsStorageGarbageCollection(false);
215e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
216e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  scoped_ptr<base::hash_set<base::FilePath> > active_paths(
217e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      new base::hash_set<base::FilePath>());
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<ExtensionSet> extensions =
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      ExtensionRegistry::Get(context_)->GenerateInstalledExtensionsSet();
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  for (ExtensionSet::const_iterator iter = extensions->begin();
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu       iter != extensions->end();
222e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch       ++iter) {
223e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    if (AppIsolationInfo::HasIsolatedStorage(iter->get())) {
224e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      active_paths->insert(
225e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch          content::BrowserContext::GetStoragePartitionForSite(
226e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              context_, util::GetSiteForExtensionId((*iter)->id(), context_))
227e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch              ->GetPath());
228e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch    }
229e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  }
230e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
2310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ExtensionService* service =
2320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      ExtensionSystem::Get(context_)->extension_service();
2330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  service->OnGarbageCollectIsolatedStorageStart();
234e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  content::BrowserContext::GarbageCollectStoragePartitions(
235e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      context_,
236e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      active_paths.Pass(),
237e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      base::Bind(&ExtensionService::OnGarbageCollectIsolatedStorageFinished,
2380529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                 service->AsWeakPtr()));
2390529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
2400529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2410529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ExtensionGarbageCollector::OnBeginCrxInstall(
2420529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string& extension_id) {
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  crx_installs_in_progress_++;
2440529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch}
2450529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2460529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochvoid ExtensionGarbageCollector::OnFinishCrxInstall(
2470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const std::string& extension_id,
2480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    bool success) {
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  crx_installs_in_progress_--;
2500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (crx_installs_in_progress_ < 0) {
2510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // This can only happen if there is a mismatch in our begin/finish
2520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // accounting.
2530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    NOTREACHED();
2540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Don't let the count go negative to avoid garbage collecting when
2560529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // an install is actually in progress.
2570529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    crx_installs_in_progress_ = 0;
2580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  }
259e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}
260e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch
261e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch}  // namespace extensions
262