extension_assets_manager_chromeos.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright (c) 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <map>
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include <vector>
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/command_line.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/file_util.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/memory/singleton.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/prefs/pref_registry_simple.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/prefs/pref_service.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/prefs/scoped_user_pref_update.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/sequenced_task_runner.h"
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/sys_info.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/browser_process.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/extension_service.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chromeos/chromeos_switches.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/browser/extension_system.h"
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/extension.h"
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/file_util.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "extensions/common/manifest.h"
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using content::BrowserThread;
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace extensions {
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)namespace {
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// A dictionary that maps shared extension IDs to version/paths/users.
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kSharedExtensions[] = "SharedExtensions";
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Name of path attribute in shared extensions map.
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kSharedExtensionPath[] = "path";
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Name of users attribute (list of user emails) in shared extensions map.
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kSharedExtensionUsers[] = "users";
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Shared install dir overrider for tests only.
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static const base::FilePath* g_shared_install_dir_override = NULL;
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// This helper class lives on UI thread only. Main purpose of this class is to
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// track shared installation in progress between multiple profiles.
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)class ExtensionAssetsManagerHelper {
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) public:
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Info about pending install request.
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  struct PendingInstallInfo {
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::FilePath unpacked_extension_root;
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::FilePath local_install_dir;
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Profile* profile;
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ExtensionAssetsManager::InstallExtensionCallback callback;
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  };
56cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef std::vector<PendingInstallInfo> PendingInstallList;
57cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  static ExtensionAssetsManagerHelper* GetInstance() {
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK_CURRENTLY_ON(BrowserThread::UI);
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return Singleton<ExtensionAssetsManagerHelper>::get();
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Remember that shared install is in progress. Return true if there is no
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // other installs for given id and version.
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  bool RecordSharedInstall(
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const std::string& id,
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const std::string& version,
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const base::FilePath& unpacked_extension_root,
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const base::FilePath& local_install_dir,
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      Profile* profile,
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionAssetsManager::InstallExtensionCallback callback) {
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PendingInstallInfo install_info;
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    install_info.unpacked_extension_root = unpacked_extension_root;
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    install_info.local_install_dir = local_install_dir;
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    install_info.profile = profile;
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    install_info.callback = callback;
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    std::vector<PendingInstallInfo>& callbacks =
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        install_queue_[InstallQueue::key_type(id, version)];
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    callbacks.push_back(install_info);
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return callbacks.size() == 1;
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Remove record about shared installation in progress and return
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // |pending_installs|.
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  void SharedInstallDone(const std::string& id,
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         const std::string& version,
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                         PendingInstallList* pending_installs) {
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    InstallQueue::iterator it = install_queue_.find(
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        InstallQueue::key_type(id, version));
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DCHECK(it != install_queue_.end());
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    pending_installs->swap(it->second);
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    install_queue_.erase(it);
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) private:
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  friend struct DefaultSingletonTraits<ExtensionAssetsManagerHelper>;
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ExtensionAssetsManagerHelper() {}
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ~ExtensionAssetsManagerHelper() {}
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Extension ID + version pair.
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef std::pair<std::string, std::string> InstallItem;
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Queue of pending installs in progress.
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  typedef std::map<InstallItem, std::vector<PendingInstallInfo> > InstallQueue;
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  InstallQueue install_queue_;
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ExtensionAssetsManagerHelper);
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)};
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Path to shared extensions install dir.
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char ExtensionAssetsManagerChromeOS::kSharedExtensionsDir[] =
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    "/var/cache/shared_extensions";
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ExtensionAssetsManagerChromeOS::ExtensionAssetsManagerChromeOS() { }
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ExtensionAssetsManagerChromeOS::~ExtensionAssetsManagerChromeOS() {
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (g_shared_install_dir_override) {
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    delete g_shared_install_dir_override;
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    g_shared_install_dir_override = NULL;
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)ExtensionAssetsManagerChromeOS* ExtensionAssetsManagerChromeOS::GetInstance() {
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return Singleton<ExtensionAssetsManagerChromeOS>::get();
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::RegisterPrefs(
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    PrefRegistrySimple* registry) {
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  registry->RegisterDictionaryPref(kSharedExtensions);
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::InstallExtension(
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Extension* extension,
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& unpacked_extension_root,
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& local_install_dir,
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Profile* profile,
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    InstallExtensionCallback callback) {
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!CanShareAssets(extension)) {
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    InstallLocalExtension(extension->id(),
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          extension->VersionString(),
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          unpacked_extension_root,
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          local_install_dir,
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                          callback);
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&ExtensionAssetsManagerChromeOS::CheckSharedExtension,
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 extension->id(),
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 extension->VersionString(),
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 unpacked_extension_root,
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 local_install_dir,
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 profile,
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 callback));
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::UninstallExtension(
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& id,
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Profile* profile,
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& local_install_dir,
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& extension_root) {
170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (local_install_dir.IsParent(extension_root)) {
171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    file_util::UninstallExtension(local_install_dir, id);
172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (GetSharedInstallDir().IsParent(extension_root)) {
176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // In some test extensions installed outside local_install_dir emulate
177cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // previous behavior that just do nothing in this case.
178cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
179cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(&ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused,
180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   id,
181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                   profile));
182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
186cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::SetSharedInstallDirForTesting(
187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& install_dir) {
188cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK(!g_shared_install_dir_override);
189cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  g_shared_install_dir_override = new base::FilePath(install_dir);
190cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
191cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::SequencedTaskRunner* ExtensionAssetsManagerChromeOS::GetFileTaskRunner(
194cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Profile* profile) {
195cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::UI);
196cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ExtensionService* extension_service =
197cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionSystem::Get(profile)->extension_service();
198cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return extension_service->GetFileTaskRunner();
199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)base::FilePath ExtensionAssetsManagerChromeOS::GetSharedInstallDir() {
203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (g_shared_install_dir_override)
204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return *g_shared_install_dir_override;
205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  else
206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return base::FilePath(kSharedExtensionsDir);
207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool ExtensionAssetsManagerChromeOS::CanShareAssets(
211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const Extension* extension) {
212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!CommandLine::ForCurrentProcess()->HasSwitch(
213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          chromeos::switches::kEnableExtensionAssetsSharing)) {
214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return false;
215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
216cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
217cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Chrome caches crx files for installed by default apps so sharing assets is
218cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // also possible. User specific apps should be excluded to not expose apps
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // unique for the user outside of user's cryptohome.
220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return Manifest::IsExternalLocation(extension->location());
221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::CheckSharedExtension(
225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& id,
226cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& version,
227cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& unpacked_extension_root,
228cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& local_install_dir,
229cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Profile* profile,
230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    InstallExtensionCallback callback) {
231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::UI);
232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* extension_info = NULL;
236cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* version_info = NULL;
237cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::ListValue* users = NULL;
238cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string shared_path;
239cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (shared_extensions->GetDictionary(id, &extension_info) &&
240cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      extension_info->GetDictionaryWithoutPathExpansion(
241cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          version, &version_info) &&
242cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      version_info->GetString(kSharedExtensionPath, &shared_path) &&
243cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      version_info->GetList(kSharedExtensionUsers, &users)) {
244cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This extension version already in shared location.
245cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& user_name = profile->GetProfileName();
246cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    size_t users_size = users->GetSize();
247cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bool user_found = false;
248cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (size_t i = 0; i < users_size; i++) {
249cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      std::string temp;
250cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (users->GetString(i, &temp) && temp == user_name) {
251cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        // Re-installation for the same user.
252cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        user_found = true;
253cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        break;
254cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
255cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
256cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!user_found)
257cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      users->AppendString(user_name);
258cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
259cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // unpacked_extension_root will be deleted by CrxInstaller.
260cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
261cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
262cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(callback, base::FilePath(shared_path)));
263cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  } else {
264cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Desired version is not found in shared location.
265cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ExtensionAssetsManagerHelper* helper =
266cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        ExtensionAssetsManagerHelper::GetInstance();
267cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (helper->RecordSharedInstall(id, version, unpacked_extension_root,
268cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                    local_install_dir, profile, callback)) {
269cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      // There is no install in progress for given <id, version> so run install.
270cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
271cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          FROM_HERE,
272cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          base::Bind(&ExtensionAssetsManagerChromeOS::InstallSharedExtension,
273cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     id,
274cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     version,
275cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     unpacked_extension_root));
276cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
277cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
278cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
280cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
281cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::InstallSharedExtension(
282cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const std::string& id,
283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const std::string& version,
284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const base::FilePath& unpacked_extension_root) {
285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::FilePath shared_install_dir = GetSharedInstallDir();
286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::FilePath shared_version_dir = file_util::InstallExtension(
287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      unpacked_extension_root, id, version, shared_install_dir);
288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
289cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::Bind(&ExtensionAssetsManagerChromeOS::InstallSharedExtensionDone,
290cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                 id, version, shared_version_dir));
291cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
292cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
293cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::InstallSharedExtensionDone(
295cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& id,
296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& version,
297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& shared_version_dir) {
298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::UI);
299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ExtensionAssetsManagerHelper* helper =
301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionAssetsManagerHelper::GetInstance();
302cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ExtensionAssetsManagerHelper::PendingInstallList pending_installs;
303cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  helper->SharedInstallDone(id, version, &pending_installs);
304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
305cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (shared_version_dir.empty()) {
306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // Installation to shared location failed, try local dir.
307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(dpolukhin): add UMA stats reporting.
308cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    for (size_t i = 0; i < pending_installs.size(); i++) {
309cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionAssetsManagerHelper::PendingInstallInfo& info =
310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          pending_installs[i];
311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionAssetsManagerChromeOS::GetFileTaskRunner(info.profile)->PostTask(
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          FROM_HERE,
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          base::Bind(&ExtensionAssetsManagerChromeOS::InstallLocalExtension,
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     id,
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     version,
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     info.unpacked_extension_root,
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     info.local_install_dir,
318cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     info.callback));
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
322cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
324cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
325cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* extension_info = NULL;
326cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!shared_extensions->GetDictionary(id, &extension_info)) {
327cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    extension_info = new base::DictionaryValue;
328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    shared_extensions->Set(id, extension_info);
329cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK(!shared_extensions->HasKey(version));
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* version_info = new base::DictionaryValue;
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  extension_info->SetWithoutPathExpansion(version, version_info);
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  version_info->SetString(kSharedExtensionPath, shared_version_dir.value());
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::ListValue* users = new base::ListValue;
337cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  version_info->Set(kSharedExtensionUsers, users);
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (size_t i = 0; i < pending_installs.size(); i++) {
339cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ExtensionAssetsManagerHelper::PendingInstallInfo& info =
340cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        pending_installs[i];
341cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      users->AppendString(info.profile->GetProfileName());
342cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
343cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    ExtensionAssetsManagerChromeOS::GetFileTaskRunner(info.profile)->PostTask(
344cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        FROM_HERE,
345cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        base::Bind(info.callback, shared_version_dir));
346cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
347cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
348cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
349cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
350cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::InstallLocalExtension(
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& id,
352cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& version,
353cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& unpacked_extension_root,
354cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& local_install_dir,
355cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    InstallExtensionCallback callback) {
356cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback.Run(file_util::InstallExtension(
357cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      unpacked_extension_root, id, version, local_install_dir));
358cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
359cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
360cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
361cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::MarkSharedExtensionUnused(
362cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& id,
363cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    Profile* profile) {
364cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_CURRENTLY_ON(BrowserThread::UI);
365cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
366cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  PrefService* local_state = g_browser_process->local_state();
367cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DictionaryPrefUpdate shared_extensions(local_state, kSharedExtensions);
368cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* extension_info = NULL;
369cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!shared_extensions->GetDictionary(id, &extension_info)) {
370cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    NOTREACHED();
371cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
372cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
373cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
374cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::vector<std::string> versions;
375cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  versions.reserve(extension_info->size());
376cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (base::DictionaryValue::Iterator it(*extension_info);
377cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       !it.IsAtEnd();
378cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       it.Advance()) {
379cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    versions.push_back(it.key());
380cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
381cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
382cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::StringValue user_name(profile->GetProfileName());
383cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  for (std::vector<std::string>::const_iterator it = versions.begin();
384cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)       it != versions.end(); it++) {
385cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::DictionaryValue* version_info = NULL;
386cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!extension_info->GetDictionaryWithoutPathExpansion(*it,
387cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                                           &version_info)) {
388cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      NOTREACHED();
389cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      continue;
390cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
391cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    base::ListValue* users = NULL;
392cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (!version_info->GetList(kSharedExtensionUsers, &users)) {
393cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      NOTREACHED();
394cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      continue;
395cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
396cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if (users->Remove(user_name, NULL) && !users->GetSize()) {
397cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      std::string shared_path;
398cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      if (!version_info->GetString(kSharedExtensionPath, &shared_path)) {
399cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        NOTREACHED();
400cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        continue;
401cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      }
402cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ExtensionAssetsManagerChromeOS::GetFileTaskRunner(profile)->PostTask(
403cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          FROM_HERE,
404cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          base::Bind(&ExtensionAssetsManagerChromeOS::DeleteSharedVersion,
405cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                     base::FilePath(shared_path)));
406cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      extension_info->RemoveWithoutPathExpansion(*it, NULL);
407cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    }
408cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
409cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // Don't remove extension dir in shared location. It will be removed by GC
410cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // when it is safe to do so, and this avoids a race condition between
411cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  // concurrent uninstall by one user and install by another.
412cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
413cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
414cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
415cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void ExtensionAssetsManagerChromeOS::DeleteSharedVersion(
416cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::FilePath& shared_version_dir) {
417cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  CHECK(GetSharedInstallDir().IsParent(shared_version_dir));
418cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DeleteFile(shared_version_dir, true);  // recursive.
419cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
420cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
421cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}  // namespace extensions
422