summaryrefslogtreecommitdiffstats
path: root/chrome/browser/media_gallery/media_file_system_registry.cc
blob: fae44387952706c0ae38a79acd9ad0fa032bc09d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// MediaFileSystemRegistry implementation.

#include "chrome/browser/media_gallery/media_file_system_registry.h"

#include <set>

#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
#include "webkit/fileapi/isolated_context.h"

namespace chrome {

static base::LazyInstance<MediaFileSystemRegistry>::Leaky
    g_media_file_system_registry = LAZY_INSTANCE_INITIALIZER;

using base::SystemMonitor;
using content::BrowserThread;
using content::RenderProcessHost;
using fileapi::IsolatedContext;

/******************
 * Public methods
 ******************/

// static
MediaFileSystemRegistry* MediaFileSystemRegistry::GetInstance() {
  return g_media_file_system_registry.Pointer();
}

std::vector<MediaFileSystemRegistry::MediaFSIDAndPath>
MediaFileSystemRegistry::GetMediaFileSystems(
    const content::RenderProcessHost* rph) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  std::vector<MediaFSIDAndPath> results;
  std::pair<ChildIdToMediaFSMap::iterator, bool> ret =
      media_fs_map_.insert(std::make_pair(rph, MediaPathToFSIDMap()));
  ChildIdToMediaFSMap::iterator& child_it = ret.first;
  if (ret.second) {
    // Never seen a GetMediaFileSystems call from this RPH. Initialize its
    // file system mappings.
    RegisterForRPHGoneNotifications(rph);
    FilePath pictures_path;
    if (PathService::Get(chrome::DIR_USER_PICTURES, &pictures_path)) {
      std::string fsid = RegisterPathAsFileSystem(pictures_path);
      child_it->second.insert(std::make_pair(pictures_path, fsid));
    }
  }

  // TODO(thestig) Handle overlap between devices and media directories.
  SystemMonitor* monitor = SystemMonitor::Get();
  const std::vector<SystemMonitor::MediaDeviceInfo> media_devices =
      monitor->GetAttachedMediaDevices();
  for (size_t i = 0; i < media_devices.size(); ++i) {
    const SystemMonitor::DeviceIdType& id = media_devices[i].a;
    const FilePath& path = media_devices[i].c;
    device_id_map_.insert(std::make_pair(id, path));
    std::string fsid = RegisterPathAsFileSystem(path);
    child_it->second.insert(std::make_pair(path, fsid));
  }

  MediaPathToFSIDMap& child_map = child_it->second;
  for (MediaPathToFSIDMap::const_iterator it = child_map.begin();
       it != child_map.end();
       ++it) {
    const FilePath path = it->first;
    const std::string fsid = it->second;
    results.push_back(std::make_pair(fsid, path));
  }
  return results;
}

void MediaFileSystemRegistry::OnMediaDeviceDetached(
    const base::SystemMonitor::DeviceIdType& id) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  DeviceIdToMediaPathMap::iterator it = device_id_map_.find(id);
  if (it == device_id_map_.end())
    return;
  RevokeMediaFileSystem(it->second);
  device_id_map_.erase(it);
}

void MediaFileSystemRegistry::Observe(
    int type,
    const content::NotificationSource& source,
    const content::NotificationDetails& details) {
  DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED ||
         type == content::NOTIFICATION_RENDERER_PROCESS_TERMINATED);
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  const RenderProcessHost* rph =
      content::Source<content::RenderProcessHost>(source).ptr();
  ChildIdToMediaFSMap::iterator child_it = media_fs_map_.find(rph);
  CHECK(child_it != media_fs_map_.end());
  // No need to revoke the isolated file systems. The RPH will do that.
  media_fs_map_.erase(child_it);
  UnregisterForRPHGoneNotifications(rph);
}

/******************
 * Private methods
 ******************/

MediaFileSystemRegistry::MediaFileSystemRegistry() {
}

MediaFileSystemRegistry::~MediaFileSystemRegistry() {
}

void MediaFileSystemRegistry::RegisterForRPHGoneNotifications(
    const content::RenderProcessHost* rph) {
  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
                 content::Source<RenderProcessHost>(rph));
  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
                 content::Source<RenderProcessHost>(rph));
}

void MediaFileSystemRegistry::UnregisterForRPHGoneNotifications(
    const content::RenderProcessHost* rph) {
  registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
                    content::Source<RenderProcessHost>(rph));
  registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
                    content::Source<RenderProcessHost>(rph));
}

std::string MediaFileSystemRegistry::RegisterPathAsFileSystem(
    const FilePath& path) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  // Sanity checks for |path|.
  CHECK(path.IsAbsolute());
  CHECK(!path.ReferencesParent());
  // Make sure |path| does not refer to '/' on Unix.
  // TODO(thestig) Check how BaseName() works for say, 'C:\' on Windows.
  CHECK(!path.BaseName().IsAbsolute());
  CHECK(!path.BaseName().empty());

  std::set<FilePath> fileset;
  fileset.insert(path);
  const std::string fsid =
      IsolatedContext::GetInstance()->RegisterIsolatedFileSystem(fileset);
  CHECK(!fsid.empty());
  return fsid;
}

void MediaFileSystemRegistry::RevokeMediaFileSystem(const FilePath& path) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  IsolatedContext* isolated_context = IsolatedContext::GetInstance();
  for (ChildIdToMediaFSMap::iterator child_it = media_fs_map_.begin();
       child_it != media_fs_map_.end();
       ++child_it) {
    MediaPathToFSIDMap& child_map = child_it->second;
    MediaPathToFSIDMap::iterator media_path_it = child_map.find(path);
    if (media_path_it == child_map.end())
      continue;
    isolated_context->RevokeIsolatedFileSystem(media_path_it->second);
    child_map.erase(media_path_it);
  }
}

}  // namespace chrome