| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/download/download_file_manager.h" | 5 #include "chrome/browser/download/download_file_manager.h" |
| 6 | 6 |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/stl_util-inl.h" | 8 #include "base/stl_util-inl.h" |
| 9 #include "base/task.h" | 9 #include "base/task.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #elif defined(OS_MACOSX) | 28 #elif defined(OS_MACOSX) |
| 29 #include "chrome/browser/cocoa/file_metadata.h" | 29 #include "chrome/browser/cocoa/file_metadata.h" |
| 30 #endif | 30 #endif |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 // Throttle updates to the UI thread so that a fast moving download doesn't | 34 // Throttle updates to the UI thread so that a fast moving download doesn't |
| 35 // cause it to become unresponsive (in milliseconds). | 35 // cause it to become unresponsive (in milliseconds). |
| 36 const int kUpdatePeriodMs = 500; | 36 const int kUpdatePeriodMs = 500; |
| 37 | 37 |
| 38 DownloadManager* DownloadManagerForRenderViewHost(int render_process_id, |
| 39 int render_view_id) { |
| 40 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 41 |
| 42 TabContents* contents = tab_util::GetTabContentsByID(render_process_id, |
| 43 render_view_id); |
| 44 if (contents) { |
| 45 Profile* profile = contents->profile(); |
| 46 if (profile) |
| 47 return profile->GetDownloadManager(); |
| 48 } |
| 49 |
| 50 return NULL; |
| 51 } |
| 52 |
| 38 } // namespace | 53 } // namespace |
| 39 | 54 |
| 40 DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh) | 55 DownloadFileManager::DownloadFileManager(ResourceDispatcherHost* rdh) |
| 41 : next_id_(0), | 56 : next_id_(0), |
| 42 resource_dispatcher_host_(rdh) { | 57 resource_dispatcher_host_(rdh) { |
| 43 } | 58 } |
| 44 | 59 |
| 45 DownloadFileManager::~DownloadFileManager() { | 60 DownloadFileManager::~DownloadFileManager() { |
| 46 // Check for clean shutdown. | |
| 47 DCHECK(downloads_.empty()); | 61 DCHECK(downloads_.empty()); |
| 48 } | 62 } |
| 49 | 63 |
| 50 // Called during the browser shutdown process to clean up any state (open files, | |
| 51 // timers) that live on the download_thread_. | |
| 52 void DownloadFileManager::Shutdown() { | 64 void DownloadFileManager::Shutdown() { |
| 53 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 65 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 54 StopUpdateTimer(); | |
| 55 ChromeThread::PostTask( | 66 ChromeThread::PostTask( |
| 56 ChromeThread::FILE, FROM_HERE, | 67 ChromeThread::FILE, FROM_HERE, |
| 57 NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); | 68 NewRunnableMethod(this, &DownloadFileManager::OnShutdown)); |
| 58 } | 69 } |
| 59 | 70 |
| 60 // Cease download thread operations. | |
| 61 void DownloadFileManager::OnShutdown() { | 71 void DownloadFileManager::OnShutdown() { |
| 62 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 72 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 73 StopUpdateTimer(); |
| 63 STLDeleteValues(&downloads_); | 74 STLDeleteValues(&downloads_); |
| 64 } | 75 } |
| 65 | 76 |
| 66 // Notifications sent from the download thread and run on the UI thread. | 77 void DownloadFileManager::CreateDownloadFile( |
| 78 DownloadCreateInfo* info, DownloadManager* download_manager) { |
| 79 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 67 | 80 |
| 68 // Lookup the DownloadManager for this TabContents' profile and inform it of | 81 scoped_ptr<DownloadFile> download_file( |
| 69 // a new download. | 82 new DownloadFile(info, download_manager)); |
| 70 // TODO(paulg): When implementing download restart via the Downloads tab, | 83 if (!download_file->Initialize()) { |
| 71 // there will be no 'render_process_id' or 'render_view_id'. | |
| 72 void DownloadFileManager::OnStartDownload(DownloadCreateInfo* info) { | |
| 73 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 74 DownloadManager* manager = DownloadManagerFromRenderIds(info->child_id, | |
| 75 info->render_view_id); | |
| 76 if (!manager) { | |
| 77 ChromeThread::PostTask( | 84 ChromeThread::PostTask( |
| 78 ChromeThread::IO, FROM_HERE, | 85 ChromeThread::IO, FROM_HERE, |
| 79 NewRunnableFunction(&download_util::CancelDownloadRequest, | 86 NewRunnableFunction(&download_util::CancelDownloadRequest, |
| 80 resource_dispatcher_host_, | 87 resource_dispatcher_host_, |
| 81 info->child_id, | 88 info->child_id, |
| 82 info->request_id)); | 89 info->request_id)); |
| 83 delete info; | 90 delete info; |
| 84 return; | 91 return; |
| 85 } | 92 } |
| 86 | 93 |
| 94 DCHECK(GetDownloadFile(info->download_id) == NULL); |
| 95 downloads_[info->download_id] = download_file.release(); |
| 96 // TODO(phajdan.jr): fix the duplication of path info below. |
| 97 info->path = info->save_info.file_path; |
| 98 |
| 99 // The file is now ready, we can un-pause the request and start saving data. |
| 100 ChromeThread::PostTask( |
| 101 ChromeThread::IO, FROM_HERE, |
| 102 NewRunnableMethod(this, &DownloadFileManager::ResumeDownloadRequest, |
| 103 info->child_id, info->request_id)); |
| 104 |
| 87 StartUpdateTimer(); | 105 StartUpdateTimer(); |
| 88 | 106 |
| 89 // Add the download manager to our request maps for future updates. We want to | 107 ChromeThread::PostTask( |
| 90 // be able to cancel all in progress downloads when a DownloadManager is | 108 ChromeThread::UI, FROM_HERE, |
| 91 // deleted, such as when a profile is closed. We also want to be able to look | 109 NewRunnableMethod(download_manager, |
| 92 // up the DownloadManager associated with a given request without having to | 110 &DownloadManager::StartDownload, info)); |
| 93 // rely on using tab information, since a tab may be closed while a download | |
| 94 // initiated from that tab is still in progress. | |
| 95 DownloadRequests& downloads = requests_[manager]; | |
| 96 downloads.insert(info->download_id); | |
| 97 | |
| 98 // TODO(paulg): The manager will exist when restarts are implemented. | |
| 99 DownloadManagerMap::iterator dit = managers_.find(info->download_id); | |
| 100 if (dit == managers_.end()) | |
| 101 managers_[info->download_id] = manager; | |
| 102 else | |
| 103 NOTREACHED(); | |
| 104 | |
| 105 // StartDownload will clean up |info|. | |
| 106 manager->StartDownload(info); | |
| 107 } | 111 } |
| 108 | 112 |
| 109 // Update the Download Manager with the finish state, and remove the request | 113 void DownloadFileManager::ResumeDownloadRequest(int child_id, int request_id) { |
| 110 // tracking entries. | 114 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 111 void DownloadFileManager::OnDownloadFinished(int id, | 115 |
| 112 int64 bytes_so_far) { | 116 // This balances the pause in DownloadResourceHandler::OnResponseStarted. |
| 113 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 117 resource_dispatcher_host_->PauseRequest(child_id, request_id, false); |
| 114 DownloadManager* manager = GetDownloadManager(id); | |
| 115 if (manager) | |
| 116 manager->DownloadFinished(id, bytes_so_far); | |
| 117 RemoveDownload(id, manager); | |
| 118 RemoveDownloadFromUIProgress(id); | |
| 119 } | 118 } |
| 120 | 119 |
| 121 // Lookup one in-progress download. | |
| 122 DownloadFile* DownloadFileManager::GetDownloadFile(int id) { | 120 DownloadFile* DownloadFileManager::GetDownloadFile(int id) { |
| 123 DownloadFileMap::iterator it = downloads_.find(id); | 121 DownloadFileMap::iterator it = downloads_.find(id); |
| 124 return it == downloads_.end() ? NULL : it->second; | 122 return it == downloads_.end() ? NULL : it->second; |
| 125 } | 123 } |
| 126 | 124 |
| 127 // The UI progress is updated on the file thread and removed on the UI thread. | |
| 128 void DownloadFileManager::RemoveDownloadFromUIProgress(int id) { | |
| 129 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 130 AutoLock lock(progress_lock_); | |
| 131 if (ui_progress_.find(id) != ui_progress_.end()) | |
| 132 ui_progress_.erase(id); | |
| 133 } | |
| 134 | |
| 135 // Throttle updates to the UI thread by only posting update notifications at a | |
| 136 // regularly controlled interval. | |
| 137 void DownloadFileManager::StartUpdateTimer() { | 125 void DownloadFileManager::StartUpdateTimer() { |
| 138 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 126 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 139 if (!update_timer_.IsRunning()) { | 127 if (!update_timer_.IsRunning()) { |
| 140 update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), | 128 update_timer_.Start(base::TimeDelta::FromMilliseconds(kUpdatePeriodMs), |
| 141 this, &DownloadFileManager::UpdateInProgressDownloads); | 129 this, &DownloadFileManager::UpdateInProgressDownloads); |
| 142 } | 130 } |
| 143 } | 131 } |
| 144 | 132 |
| 145 void DownloadFileManager::StopUpdateTimer() { | 133 void DownloadFileManager::StopUpdateTimer() { |
| 146 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 134 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 147 update_timer_.Stop(); | 135 update_timer_.Stop(); |
| 148 } | 136 } |
| 149 | 137 |
| 150 // Our periodic timer has fired so send the UI thread updates on all in progress | |
| 151 // downloads. | |
| 152 void DownloadFileManager::UpdateInProgressDownloads() { | 138 void DownloadFileManager::UpdateInProgressDownloads() { |
| 153 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | 139 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 154 AutoLock lock(progress_lock_); | 140 for (DownloadFileMap::iterator i = downloads_.begin(); |
| 155 ProgressMap::iterator it = ui_progress_.begin(); | 141 i != downloads_.end(); ++i) { |
| 156 for (; it != ui_progress_.end(); ++it) { | 142 int id = i->first; |
| 157 const int id = it->first; | 143 DownloadFile* download_file = i->second; |
| 158 DownloadManager* manager = GetDownloadManager(id); | 144 DownloadManager* manager = download_file->GetDownloadManager(); |
| 159 if (manager) | 145 if (manager) { |
| 160 manager->UpdateDownload(id, it->second); | 146 ChromeThread::PostTask(ChromeThread::UI, FROM_HERE, |
| 147 NewRunnableMethod(manager, &DownloadManager::UpdateDownload, |
| 148 id, download_file->bytes_so_far())); |
| 149 } |
| 161 } | 150 } |
| 162 } | 151 } |
| 163 | 152 |
| 164 // Called on the IO thread once the ResourceDispatcherHost has decided that a | 153 // Called on the IO thread once the ResourceDispatcherHost has decided that a |
| 165 // request is a download. | 154 // request is a download. |
| 166 int DownloadFileManager::GetNextId() { | 155 int DownloadFileManager::GetNextId() { |
| 167 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | 156 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 168 return next_id_++; | 157 return next_id_++; |
| 169 } | 158 } |
| 170 | 159 |
| 171 // Notifications sent from the IO thread and run on the download thread: | |
| 172 | |
| 173 // The IO thread created 'info', but the download thread (this method) uses it | |
| 174 // to create a DownloadFile, then passes 'info' to the UI thread where it is | |
| 175 // finally consumed and deleted. | |
| 176 void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { | 160 void DownloadFileManager::StartDownload(DownloadCreateInfo* info) { |
| 177 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 161 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 178 DCHECK(info); | 162 DCHECK(info); |
| 179 | 163 |
| 180 DownloadFile* download = new DownloadFile(info); | 164 DownloadManager* manager = DownloadManagerForRenderViewHost( |
| 181 if (!download->Initialize()) { | 165 info->child_id, info->render_view_id); |
| 182 // Couldn't open, cancel the operation. The UI thread does not yet know | 166 if (!manager) { |
| 183 // about this download so we have to clean up 'info'. We need to get back | |
| 184 // to the IO thread to cancel the network request and CancelDownloadRequest | |
| 185 // on the UI thread is the safe way to do that. | |
| 186 ChromeThread::PostTask( | 167 ChromeThread::PostTask( |
| 187 ChromeThread::IO, FROM_HERE, | 168 ChromeThread::IO, FROM_HERE, |
| 188 NewRunnableFunction(&download_util::CancelDownloadRequest, | 169 NewRunnableFunction(&download_util::CancelDownloadRequest, |
| 189 resource_dispatcher_host_, | 170 resource_dispatcher_host_, |
| 190 info->child_id, | 171 info->child_id, |
| 191 info->request_id)); | 172 info->request_id)); |
| 192 delete info; | 173 delete info; |
| 193 delete download; | |
| 194 return; | 174 return; |
| 195 } | 175 } |
| 196 | 176 |
| 197 DCHECK(GetDownloadFile(info->download_id) == NULL); | 177 ChromeThread::PostTask(ChromeThread::FILE, FROM_HERE, |
| 198 downloads_[info->download_id] = download; | 178 NewRunnableMethod(this, &DownloadFileManager::CreateDownloadFile, |
| 199 // TODO(phajdan.jr): fix the duplication of path info below. | 179 info, manager)); |
| 200 info->path = info->save_info.file_path; | |
| 201 { | |
| 202 AutoLock lock(progress_lock_); | |
| 203 ui_progress_[info->download_id] = info->received_bytes; | |
| 204 } | |
| 205 | |
| 206 ChromeThread::PostTask( | |
| 207 ChromeThread::UI, FROM_HERE, | |
| 208 NewRunnableMethod(this, &DownloadFileManager::OnStartDownload, info)); | |
| 209 } | 180 } |
| 210 | 181 |
| 211 // We don't forward an update to the UI thread here, since we want to throttle | 182 // We don't forward an update to the UI thread here, since we want to throttle |
| 212 // the UI update rate via a periodic timer. If the user has cancelled the | 183 // the UI update rate via a periodic timer. If the user has cancelled the |
| 213 // download (in the UI thread), we may receive a few more updates before the IO | 184 // download (in the UI thread), we may receive a few more updates before the IO |
| 214 // thread gets the cancel message: we just delete the data since the | 185 // thread gets the cancel message: we just delete the data since the |
| 215 // DownloadFile has been deleted. | 186 // DownloadFile has been deleted. |
| 216 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { | 187 void DownloadFileManager::UpdateDownload(int id, DownloadBuffer* buffer) { |
| 217 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 188 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 218 std::vector<DownloadBuffer::Contents> contents; | 189 std::vector<DownloadBuffer::Contents> contents; |
| 219 { | 190 { |
| 220 AutoLock auto_lock(buffer->lock); | 191 AutoLock auto_lock(buffer->lock); |
| 221 contents.swap(buffer->contents); | 192 contents.swap(buffer->contents); |
| 222 } | 193 } |
| 223 | 194 |
| 224 // Keep track of how many bytes we have successfully saved to update | |
| 225 // our progress status in the UI. | |
| 226 int64 progress_bytes = 0; | |
| 227 | |
| 228 DownloadFile* download = GetDownloadFile(id); | 195 DownloadFile* download = GetDownloadFile(id); |
| 229 for (size_t i = 0; i < contents.size(); ++i) { | 196 for (size_t i = 0; i < contents.size(); ++i) { |
| 230 net::IOBuffer* data = contents[i].first; | 197 net::IOBuffer* data = contents[i].first; |
| 231 const int data_len = contents[i].second; | 198 const int data_len = contents[i].second; |
| 232 if (download) { | 199 if (download) |
| 233 if (download->AppendDataToFile(data->data(), data_len)) | 200 download->AppendDataToFile(data->data(), data_len); |
| 234 progress_bytes += data_len; | |
| 235 } | |
| 236 data->Release(); | 201 data->Release(); |
| 237 } | 202 } |
| 238 | |
| 239 if (download) { | |
| 240 AutoLock lock(progress_lock_); | |
| 241 ui_progress_[download->id()] += progress_bytes; | |
| 242 } | |
| 243 } | 203 } |
| 244 | 204 |
| 245 void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { | 205 void DownloadFileManager::DownloadFinished(int id, DownloadBuffer* buffer) { |
| 246 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 206 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 247 delete buffer; | 207 delete buffer; |
| 248 DownloadFileMap::iterator it = downloads_.find(id); | 208 DownloadFileMap::iterator it = downloads_.find(id); |
| 249 if (it != downloads_.end()) { | 209 if (it != downloads_.end()) { |
| 250 DownloadFile* download = it->second; | 210 DownloadFile* download = it->second; |
| 251 download->Finish(); | 211 download->Finish(); |
| 252 | 212 |
| 253 int64 download_size = -1; | 213 DownloadManager* download_manager = download->GetDownloadManager(); |
| 254 { | 214 if (download_manager) { |
| 255 AutoLock lock(progress_lock_); | 215 ChromeThread::PostTask( |
| 256 download_size = ui_progress_[download->id()]; | 216 ChromeThread::UI, FROM_HERE, |
| 217 NewRunnableMethod( |
| 218 download_manager, &DownloadManager::DownloadFinished, |
| 219 id, download->bytes_so_far())); |
| 257 } | 220 } |
| 258 | 221 |
| 259 ChromeThread::PostTask( | |
| 260 ChromeThread::UI, FROM_HERE, | |
| 261 NewRunnableMethod( | |
| 262 this, &DownloadFileManager::OnDownloadFinished, | |
| 263 id, download_size)); | |
| 264 | |
| 265 // We need to keep the download around until the UI thread has finalized | 222 // We need to keep the download around until the UI thread has finalized |
| 266 // the name. | 223 // the name. |
| 267 if (download->path_renamed()) { | 224 if (download->path_renamed()) { |
| 268 downloads_.erase(it); | 225 downloads_.erase(it); |
| 269 delete download; | 226 delete download; |
| 270 } | 227 } |
| 271 } | 228 } |
| 272 | 229 |
| 273 if (downloads_.empty()) | 230 if (downloads_.empty()) |
| 274 ChromeThread::PostTask( | 231 StopUpdateTimer(); |
| 275 ChromeThread::UI, FROM_HERE, | |
| 276 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); | |
| 277 } | 232 } |
| 278 | 233 |
| 279 // This method will be sent via a user action, or shutdown on the UI thread, and | 234 // This method will be sent via a user action, or shutdown on the UI thread, and |
| 280 // run on the download thread. Since this message has been sent from the UI | 235 // run on the download thread. Since this message has been sent from the UI |
| 281 // thread, the download may have already completed and won't exist in our map. | 236 // thread, the download may have already completed and won't exist in our map. |
| 282 void DownloadFileManager::CancelDownload(int id) { | 237 void DownloadFileManager::CancelDownload(int id) { |
| 283 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 238 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 284 DownloadFileMap::iterator it = downloads_.find(id); | 239 DownloadFileMap::iterator it = downloads_.find(id); |
| 285 if (it != downloads_.end()) { | 240 if (it != downloads_.end()) { |
| 286 DownloadFile* download = it->second; | 241 DownloadFile* download = it->second; |
| 287 download->Cancel(); | 242 download->Cancel(); |
| 288 | 243 |
| 289 ChromeThread::PostTask( | |
| 290 ChromeThread::UI, FROM_HERE, | |
| 291 NewRunnableMethod( | |
| 292 this, &DownloadFileManager::RemoveDownloadFromUIProgress, | |
| 293 download->id())); | |
| 294 | |
| 295 if (download->path_renamed()) { | 244 if (download->path_renamed()) { |
| 296 downloads_.erase(it); | 245 downloads_.erase(it); |
| 297 delete download; | 246 delete download; |
| 298 } | 247 } |
| 299 } | 248 } |
| 300 | 249 |
| 301 if (downloads_.empty()) { | 250 if (downloads_.empty()) |
| 302 ChromeThread::PostTask( | 251 StopUpdateTimer(); |
| 303 ChromeThread::UI, FROM_HERE, | 252 } |
| 304 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); | 253 |
| 254 void DownloadFileManager::OnDownloadManagerShutdown(DownloadManager* manager) { |
| 255 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 256 DCHECK(manager); |
| 257 |
| 258 for (DownloadFileMap::iterator i = downloads_.begin(); |
| 259 i != downloads_.end(); ++i) { |
| 260 DownloadFile* download_file = i->second; |
| 261 if (download_file->GetDownloadManager() == manager) |
| 262 download_file->OnDownloadManagerShutdown(); |
| 305 } | 263 } |
| 306 } | 264 } |
| 307 | 265 |
| 308 // Relate a download ID to its owning DownloadManager. | |
| 309 DownloadManager* DownloadFileManager::GetDownloadManager(int download_id) { | |
| 310 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 311 DownloadManagerMap::iterator it = managers_.find(download_id); | |
| 312 if (it != managers_.end()) | |
| 313 return it->second; | |
| 314 return NULL; | |
| 315 } | |
| 316 | |
| 317 // Utility function for look up table maintenance, called on the UI thread. | |
| 318 // A manager may have multiple downloads in progress, so we just look up the | |
| 319 // one download (id) and remove it from the set, and remove the set if it | |
| 320 // becomes empty. | |
| 321 void DownloadFileManager::RemoveDownload(int id, DownloadManager* manager) { | |
| 322 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 323 if (manager) { | |
| 324 RequestMap::iterator it = requests_.find(manager); | |
| 325 if (it != requests_.end()) { | |
| 326 DownloadRequests& downloads = it->second; | |
| 327 DownloadRequests::iterator rit = downloads.find(id); | |
| 328 if (rit != downloads.end()) | |
| 329 downloads.erase(rit); | |
| 330 if (downloads.empty()) | |
| 331 requests_.erase(it); | |
| 332 } | |
| 333 } | |
| 334 | |
| 335 // A download can only have one manager, so remove it if it exists. | |
| 336 DownloadManagerMap::iterator dit = managers_.find(id); | |
| 337 if (dit != managers_.end()) | |
| 338 managers_.erase(dit); | |
| 339 } | |
| 340 | |
| 341 // Utility function for converting request IDs to a TabContents. Must be called | |
| 342 // only on the UI thread since Profile operations may create UI objects, such as | |
| 343 // the first call to profile->GetDownloadManager(). | |
| 344 // static | |
| 345 DownloadManager* DownloadFileManager::DownloadManagerFromRenderIds( | |
| 346 int render_process_id, int render_view_id) { | |
| 347 TabContents* contents = tab_util::GetTabContentsByID(render_process_id, | |
| 348 render_view_id); | |
| 349 if (contents) { | |
| 350 Profile* profile = contents->profile(); | |
| 351 if (profile) | |
| 352 return profile->GetDownloadManager(); | |
| 353 } | |
| 354 | |
| 355 return NULL; | |
| 356 } | |
| 357 | |
| 358 // Called by DownloadManagers in their destructor, and only on the UI thread. | |
| 359 void DownloadFileManager::RemoveDownloadManager(DownloadManager* manager) { | |
| 360 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); | |
| 361 DCHECK(manager); | |
| 362 RequestMap::iterator it = requests_.find(manager); | |
| 363 if (it == requests_.end()) | |
| 364 return; | |
| 365 | |
| 366 const DownloadRequests& requests = it->second; | |
| 367 DownloadRequests::const_iterator i = requests.begin(); | |
| 368 for (; i != requests.end(); ++i) { | |
| 369 DownloadManagerMap::iterator dit = managers_.find(*i); | |
| 370 if (dit != managers_.end()) { | |
| 371 DCHECK(dit->second == manager); | |
| 372 managers_.erase(dit); | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 requests_.erase(it); | |
| 377 } | |
| 378 | |
| 379 // Actions from the UI thread and run on the download thread | 266 // Actions from the UI thread and run on the download thread |
| 380 | 267 |
| 381 // Open a download, or show it in a file explorer window. We run on this | 268 // Open a download, or show it in a file explorer window. We run on this |
| 382 // thread to avoid blocking the UI with (potentially) slow Shell operations. | 269 // thread to avoid blocking the UI with (potentially) slow Shell operations. |
| 383 // TODO(paulg): File 'stat' operations. | 270 // TODO(paulg): File 'stat' operations. |
| 384 #if !defined(OS_MACOSX) | 271 #if !defined(OS_MACOSX) |
| 385 void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { | 272 void DownloadFileManager::OnShowDownloadInShell(const FilePath& full_path) { |
| 386 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 273 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 387 platform_util::ShowItemInFolder(full_path); | 274 platform_util::ShowItemInFolder(full_path); |
| 388 } | 275 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 465 if (need_delete_crdownload) | 352 if (need_delete_crdownload) |
| 466 download->DeleteCrDownload(); | 353 download->DeleteCrDownload(); |
| 467 | 354 |
| 468 // If the download has completed before we got this final name, we remove it | 355 // If the download has completed before we got this final name, we remove it |
| 469 // from our in progress map. | 356 // from our in progress map. |
| 470 if (!download->in_progress()) { | 357 if (!download->in_progress()) { |
| 471 downloads_.erase(id); | 358 downloads_.erase(id); |
| 472 delete download; | 359 delete download; |
| 473 } | 360 } |
| 474 | 361 |
| 475 if (downloads_.empty()) { | 362 if (downloads_.empty()) |
| 476 ChromeThread::PostTask( | 363 StopUpdateTimer(); |
| 477 ChromeThread::UI, FROM_HERE, | |
| 478 NewRunnableMethod(this, &DownloadFileManager::StopUpdateTimer)); | |
| 479 } | |
| 480 } | 364 } |
| 481 | 365 |
| 482 // Called only from OnFinalDownloadName or OnIntermediateDownloadName | 366 // Called only from OnFinalDownloadName or OnIntermediateDownloadName |
| 483 // on the FILE thread. | 367 // on the FILE thread. |
| 484 void DownloadFileManager::CancelDownloadOnRename(int id) { | 368 void DownloadFileManager::CancelDownloadOnRename(int id) { |
| 485 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); | 369 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| 486 | 370 |
| 487 DownloadFile* download = GetDownloadFile(id); | 371 DownloadFile* download = GetDownloadFile(id); |
| 488 if (!download) | 372 if (!download) |
| 489 return; | 373 return; |
| 490 | 374 |
| 491 DownloadManagerMap::iterator dmit = managers_.find(download->id()); | 375 DownloadManager* download_manager = download->GetDownloadManager(); |
| 492 if (dmit != managers_.end()) { | 376 if (!download_manager) { |
| 493 DownloadManager* dlm = dmit->second; | |
| 494 ChromeThread::PostTask( | |
| 495 ChromeThread::UI, FROM_HERE, | |
| 496 NewRunnableMethod(dlm, &DownloadManager::DownloadCancelled, id)); | |
| 497 } else { | |
| 498 download->CancelDownloadRequest(resource_dispatcher_host_); | 377 download->CancelDownloadRequest(resource_dispatcher_host_); |
| 378 return; |
| 499 } | 379 } |
| 380 |
| 381 ChromeThread::PostTask( |
| 382 ChromeThread::UI, FROM_HERE, |
| 383 NewRunnableMethod(download_manager, |
| 384 &DownloadManager::DownloadCancelled, id)); |
| 500 } | 385 } |
| OLD | NEW |