OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "apps/launcher.h" | 5 #include "apps/launcher.h" |
6 | 6 |
7 #include "apps/browser/api/app_runtime/app_runtime_api.h" | 7 #include "apps/browser/api/app_runtime/app_runtime_api.h" |
8 #include "apps/browser/file_handler_util.h" | 8 #include "apps/browser/file_handler_util.h" |
9 #include "apps/common/api/app_runtime.h" | 9 #include "apps/common/api/app_runtime.h" |
10 #include "base/command_line.h" | 10 #include "base/command_line.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 using extensions::Extension; | 56 using extensions::Extension; |
57 using extensions::ExtensionHost; | 57 using extensions::ExtensionHost; |
58 using extensions::ExtensionSystem; | 58 using extensions::ExtensionSystem; |
59 | 59 |
60 namespace apps { | 60 namespace apps { |
61 | 61 |
62 namespace { | 62 namespace { |
63 | 63 |
64 const char kFallbackMimeType[] = "application/octet-stream"; | 64 const char kFallbackMimeType[] = "application/octet-stream"; |
65 | 65 |
66 bool MakePathAbsolute(const base::FilePath& current_directory, | 66 bool DoMakePathAbsolute(const base::FilePath& current_directory, |
67 base::FilePath* file_path) { | 67 base::FilePath* file_path) { |
68 DCHECK(file_path); | 68 DCHECK(file_path); |
69 if (file_path->IsAbsolute()) | 69 if (file_path->IsAbsolute()) |
70 return true; | 70 return true; |
71 | 71 |
72 if (current_directory.empty()) { | 72 if (current_directory.empty()) { |
73 *file_path = base::MakeAbsoluteFilePath(*file_path); | 73 *file_path = base::MakeAbsoluteFilePath(*file_path); |
74 return !file_path->empty(); | 74 return !file_path->empty(); |
75 } | 75 } |
76 | 76 |
77 if (!current_directory.IsAbsolute()) | 77 if (!current_directory.IsAbsolute()) |
78 return false; | 78 return false; |
79 | 79 |
80 *file_path = current_directory.Append(*file_path); | 80 *file_path = current_directory.Append(*file_path); |
81 return true; | 81 return true; |
82 } | 82 } |
83 | 83 |
84 bool GetAbsolutePathFromCommandLine(const CommandLine& command_line, | |
85 const base::FilePath& current_directory, | |
86 base::FilePath* path) { | |
87 if (!command_line.GetArgs().size()) | |
88 return false; | |
89 | |
90 base::FilePath relative_path(command_line.GetArgs()[0]); | |
91 base::FilePath absolute_path(relative_path); | |
92 if (!MakePathAbsolute(current_directory, &absolute_path)) { | |
93 LOG(WARNING) << "Cannot make absolute path from " << relative_path.value(); | |
94 return false; | |
95 } | |
96 *path = absolute_path; | |
97 return true; | |
98 } | |
99 | |
100 // Helper method to launch the platform app |extension| with no data. This | 84 // Helper method to launch the platform app |extension| with no data. This |
101 // should be called in the fallback case, where it has been impossible to | 85 // should be called in the fallback case, where it has been impossible to |
102 // load or obtain file launch data. | 86 // load or obtain file launch data. |
103 void LaunchPlatformAppWithNoData(Profile* profile, const Extension* extension) { | 87 void LaunchPlatformAppWithNoData(Profile* profile, const Extension* extension) { |
104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 88 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
105 AppEventRouter::DispatchOnLaunchedEvent(profile, extension); | 89 AppEventRouter::DispatchOnLaunchedEvent(profile, extension); |
106 } | 90 } |
107 | 91 |
108 // Class to handle launching of platform apps to open a specific path. | 92 // Class to handle launching of platform apps to open a specific path. |
109 // An instance of this class is created for each launch. The lifetime of these | 93 // An instance of this class is created for each launch. The lifetime of these |
110 // instances is managed by reference counted pointers. As long as an instance | 94 // instances is managed by reference counted pointers. As long as an instance |
111 // has outstanding tasks on a message queue it will be retained; once all | 95 // has outstanding tasks on a message queue it will be retained; once all |
112 // outstanding tasks are completed it will be deleted. | 96 // outstanding tasks are completed it will be deleted. |
113 class PlatformAppPathLauncher | 97 class PlatformAppPathLauncher |
114 : public base::RefCountedThreadSafe<PlatformAppPathLauncher> { | 98 : public base::RefCountedThreadSafe<PlatformAppPathLauncher> { |
115 public: | 99 public: |
116 PlatformAppPathLauncher(Profile* profile, | 100 PlatformAppPathLauncher(Profile* profile, |
117 const Extension* extension, | 101 const Extension* extension, |
118 const base::FilePath& file_path) | 102 const base::FilePath& file_path) |
119 : profile_(profile), extension_(extension), file_path_(file_path) {} | 103 : profile_(profile), extension_(extension), file_path_(file_path) {} |
120 | 104 |
121 void Launch() { | 105 void Launch() { |
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 106 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
123 if (file_path_.empty()) { | 107 if (file_path_.empty()) { |
124 LaunchPlatformAppWithNoData(profile_, extension_); | 108 LaunchPlatformAppWithNoData(profile_, extension_); |
125 return; | 109 return; |
126 } | 110 } |
127 | 111 |
128 DCHECK(file_path_.IsAbsolute()); | 112 DCHECK(file_path_.IsAbsolute()); |
129 | 113 |
130 if (HasFileSystemWritePermission(extension_)) { | 114 if (HasFileSystemWritePermission(extension_)) { |
131 std::vector<base::FilePath> paths; | 115 std::vector<base::FilePath> paths; |
132 paths.push_back(file_path_); | 116 paths.push_back(file_path_); |
133 CheckWritableFiles( | 117 CheckWritableFiles( |
134 paths, | 118 paths, |
135 profile_, | 119 profile_, |
136 false, | 120 false, |
137 base::Bind(&PlatformAppPathLauncher::OnFileValid, this), | 121 base::Bind(&PlatformAppPathLauncher::OnFileValid, this), |
138 base::Bind(&PlatformAppPathLauncher::OnFileInvalid, this)); | 122 base::Bind(&PlatformAppPathLauncher::OnFileInvalid, this)); |
139 return; | 123 return; |
140 } | 124 } |
141 | 125 |
142 OnFileValid(); | 126 OnFileValid(); |
143 } | 127 } |
144 | 128 |
145 void LaunchWithHandler(const std::string& handler_id) { | 129 void LaunchWithHandler(const std::string& handler_id) { |
146 handler_id_ = handler_id; | 130 handler_id_ = handler_id; |
147 Launch(); | 131 Launch(); |
148 } | 132 } |
149 | 133 |
| 134 void LaunchWithRelativePath(const base::FilePath& current_directory) { |
| 135 BrowserThread::PostTask( |
| 136 BrowserThread::FILE, |
| 137 FROM_HERE, |
| 138 base::Bind(&PlatformAppPathLauncher::MakePathAbsolute, |
| 139 this, |
| 140 current_directory)); |
| 141 } |
| 142 |
150 private: | 143 private: |
151 friend class base::RefCountedThreadSafe<PlatformAppPathLauncher>; | 144 friend class base::RefCountedThreadSafe<PlatformAppPathLauncher>; |
152 | 145 |
153 virtual ~PlatformAppPathLauncher() {} | 146 virtual ~PlatformAppPathLauncher() {} |
154 | 147 |
| 148 void MakePathAbsolute(const base::FilePath& current_directory) { |
| 149 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 150 |
| 151 if (!DoMakePathAbsolute(current_directory, &file_path_)) { |
| 152 LOG(WARNING) << "Cannot make absolute path from " << file_path_.value(); |
| 153 file_path_ = base::FilePath(); |
| 154 } |
| 155 |
| 156 BrowserThread::PostTask(BrowserThread::UI, |
| 157 FROM_HERE, |
| 158 base::Bind(&PlatformAppPathLauncher::Launch, this)); |
| 159 } |
| 160 |
155 void OnFileValid() { | 161 void OnFileValid() { |
156 #if defined(OS_CHROMEOS) | 162 #if defined(OS_CHROMEOS) |
157 if (drive::util::IsUnderDriveMountPoint(file_path_)) { | 163 if (drive::util::IsUnderDriveMountPoint(file_path_)) { |
158 PlatformAppPathLauncher::GetMimeTypeAndLaunchForDriveFile(); | 164 PlatformAppPathLauncher::GetMimeTypeAndLaunchForDriveFile(); |
159 return; | 165 return; |
160 } | 166 } |
161 #endif | 167 #endif |
162 | 168 |
163 BrowserThread::PostTask( | 169 BrowserThread::PostTask( |
164 BrowserThread::FILE, | 170 BrowserThread::FILE, |
165 FROM_HERE, | 171 FROM_HERE, |
166 base::Bind(&PlatformAppPathLauncher::GetMimeTypeAndLaunch, this)); | 172 base::Bind(&PlatformAppPathLauncher::GetMimeTypeAndLaunch, this)); |
167 } | 173 } |
168 | 174 |
169 void OnFileInvalid(const base::FilePath& /* error_path */) { | 175 void OnFileInvalid(const base::FilePath& /* error_path */) { |
170 LaunchWithNoLaunchData(); | 176 LaunchWithNoLaunchData(); |
171 } | 177 } |
172 | 178 |
173 void GetMimeTypeAndLaunch() { | 179 void GetMimeTypeAndLaunch() { |
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 180 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
175 | 181 |
176 // If the file doesn't exist, or is a directory, launch with no launch data. | 182 // If the file doesn't exist, or is a directory, launch with no launch data. |
177 if (!base::PathExists(file_path_) || | 183 if (!base::PathExists(file_path_) || |
178 base::DirectoryExists(file_path_)) { | 184 base::DirectoryExists(file_path_)) { |
179 LOG(WARNING) << "No file exists with path " << file_path_.value(); | 185 LOG(WARNING) << "No file exists with path " << file_path_.value(); |
180 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 186 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
181 &PlatformAppPathLauncher::LaunchWithNoLaunchData, this)); | 187 &PlatformAppPathLauncher::LaunchWithNoLaunchData, this)); |
182 return; | 188 return; |
183 } | 189 } |
184 | 190 |
(...skipping 13 matching lines...) Expand all Loading... |
198 if (mime_type.empty()) | 204 if (mime_type.empty()) |
199 mime_type = kFallbackMimeType; | 205 mime_type = kFallbackMimeType; |
200 } | 206 } |
201 | 207 |
202 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( | 208 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( |
203 &PlatformAppPathLauncher::LaunchWithMimeType, this, mime_type)); | 209 &PlatformAppPathLauncher::LaunchWithMimeType, this, mime_type)); |
204 } | 210 } |
205 | 211 |
206 #if defined(OS_CHROMEOS) | 212 #if defined(OS_CHROMEOS) |
207 void GetMimeTypeAndLaunchForDriveFile() { | 213 void GetMimeTypeAndLaunchForDriveFile() { |
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 214 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
209 | 215 |
210 drive::FileSystemInterface* file_system = | 216 drive::FileSystemInterface* file_system = |
211 drive::util::GetFileSystemByProfile(profile_); | 217 drive::util::GetFileSystemByProfile(profile_); |
212 if (!file_system) { | 218 if (!file_system) { |
213 LaunchWithNoLaunchData(); | 219 LaunchWithNoLaunchData(); |
214 return; | 220 return; |
215 } | 221 } |
216 | 222 |
217 file_system->GetFile( | 223 file_system->GetFile( |
218 drive::util::ExtractDrivePath(file_path_), | 224 drive::util::ExtractDrivePath(file_path_), |
219 base::Bind(&PlatformAppPathLauncher::OnGotDriveFile, this)); | 225 base::Bind(&PlatformAppPathLauncher::OnGotDriveFile, this)); |
220 } | 226 } |
221 | 227 |
222 void OnGotDriveFile(drive::FileError error, | 228 void OnGotDriveFile(drive::FileError error, |
223 const base::FilePath& file_path, | 229 const base::FilePath& file_path, |
224 scoped_ptr<drive::ResourceEntry> entry) { | 230 scoped_ptr<drive::ResourceEntry> entry) { |
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 231 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
226 | 232 |
227 if (error != drive::FILE_ERROR_OK || | 233 if (error != drive::FILE_ERROR_OK || |
228 !entry || entry->file_specific_info().is_hosted_document()) { | 234 !entry || entry->file_specific_info().is_hosted_document()) { |
229 LaunchWithNoLaunchData(); | 235 LaunchWithNoLaunchData(); |
230 return; | 236 return; |
231 } | 237 } |
232 | 238 |
233 const std::string& mime_type = | 239 const std::string& mime_type = |
234 entry->file_specific_info().content_mime_type(); | 240 entry->file_specific_info().content_mime_type(); |
235 LaunchWithMimeType(mime_type.empty() ? kFallbackMimeType : mime_type); | 241 LaunchWithMimeType(mime_type.empty() ? kFallbackMimeType : mime_type); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 host->render_process_host()->GetID(), | 309 host->render_process_host()->GetID(), |
304 file_path_, | 310 file_path_, |
305 false); | 311 false); |
306 AppEventRouter::DispatchOnLaunchedEventWithFileEntry( | 312 AppEventRouter::DispatchOnLaunchedEventWithFileEntry( |
307 profile_, extension_, handler_id_, mime_type, file_entry); | 313 profile_, extension_, handler_id_, mime_type, file_entry); |
308 } | 314 } |
309 | 315 |
310 // The profile the app should be run in. | 316 // The profile the app should be run in. |
311 Profile* profile_; | 317 Profile* profile_; |
312 // The extension providing the app. | 318 // The extension providing the app. |
| 319 // TODO(benwells): Hold onto the extension ID instead of a pointer as it |
| 320 // is possible the extension will be unloaded while we're doing our thing. |
| 321 // See http://crbug.com/372270 for details. |
313 const Extension* extension_; | 322 const Extension* extension_; |
314 // The path to be passed through to the app. | 323 // The path to be passed through to the app. |
315 const base::FilePath file_path_; | 324 base::FilePath file_path_; |
316 // The ID of the file handler used to launch the app. | 325 // The ID of the file handler used to launch the app. |
317 std::string handler_id_; | 326 std::string handler_id_; |
318 | 327 |
319 DISALLOW_COPY_AND_ASSIGN(PlatformAppPathLauncher); | 328 DISALLOW_COPY_AND_ASSIGN(PlatformAppPathLauncher); |
320 }; | 329 }; |
321 | 330 |
322 } // namespace | 331 } // namespace |
323 | 332 |
324 void LaunchPlatformAppWithCommandLine(Profile* profile, | 333 void LaunchPlatformAppWithCommandLine(Profile* profile, |
325 const Extension* extension, | 334 const Extension* extension, |
326 const CommandLine& command_line, | 335 const CommandLine& command_line, |
327 const base::FilePath& current_directory) { | 336 const base::FilePath& current_directory) { |
328 // An app with "kiosk_only" should not be installed and launched | 337 // An app with "kiosk_only" should not be installed and launched |
329 // outside of ChromeOS kiosk mode in the first place. This is a defensive | 338 // outside of ChromeOS kiosk mode in the first place. This is a defensive |
330 // check in case this scenario does occur. | 339 // check in case this scenario does occur. |
331 if (extensions::KioskModeInfo::IsKioskOnly(extension)) { | 340 if (extensions::KioskModeInfo::IsKioskOnly(extension)) { |
332 bool in_kiosk_mode = false; | 341 bool in_kiosk_mode = false; |
333 #if defined(OS_CHROMEOS) | 342 #if defined(OS_CHROMEOS) |
334 chromeos::UserManager* user_manager = chromeos::UserManager::Get(); | 343 chromeos::UserManager* user_manager = chromeos::UserManager::Get(); |
335 in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp(); | 344 in_kiosk_mode = user_manager && user_manager->IsLoggedInAsKioskApp(); |
336 #endif | 345 #endif |
337 if (!in_kiosk_mode) { | 346 if (!in_kiosk_mode) { |
338 LOG(ERROR) << "App with 'kiosk_only' attribute must be run in " | 347 LOG(ERROR) << "App with 'kiosk_only' attribute must be run in " |
339 << " ChromeOS kiosk mode."; | 348 << " ChromeOS kiosk mode."; |
340 NOTREACHED(); | 349 NOTREACHED(); |
341 return; | 350 return; |
342 } | 351 } |
343 } | 352 } |
344 | 353 |
345 base::FilePath path; | 354 if (command_line.GetArgs().empty()) { |
346 if (!GetAbsolutePathFromCommandLine(command_line, current_directory, &path)) { | |
347 LaunchPlatformAppWithNoData(profile, extension); | 355 LaunchPlatformAppWithNoData(profile, extension); |
348 return; | 356 return; |
349 } | 357 } |
350 | 358 |
351 // TODO(benwells): add a command-line argument to provide a handler ID. | 359 base::FilePath file_path(command_line.GetArgs()[0]); |
352 LaunchPlatformAppWithPath(profile, extension, path); | 360 scoped_refptr<PlatformAppPathLauncher> launcher = |
| 361 new PlatformAppPathLauncher(profile, extension, file_path); |
| 362 launcher->LaunchWithRelativePath(current_directory); |
353 } | 363 } |
354 | 364 |
355 void LaunchPlatformAppWithPath(Profile* profile, | 365 void LaunchPlatformAppWithPath(Profile* profile, |
356 const Extension* extension, | 366 const Extension* extension, |
357 const base::FilePath& file_path) { | 367 const base::FilePath& file_path) { |
358 // launcher will be freed when nothing has a reference to it. The message | |
359 // queue will retain a reference for any outstanding task, so when the | |
360 // launcher has finished it will be freed. | |
361 scoped_refptr<PlatformAppPathLauncher> launcher = | 368 scoped_refptr<PlatformAppPathLauncher> launcher = |
362 new PlatformAppPathLauncher(profile, extension, file_path); | 369 new PlatformAppPathLauncher(profile, extension, file_path); |
363 launcher->Launch(); | 370 launcher->Launch(); |
364 } | 371 } |
365 | 372 |
366 void LaunchPlatformApp(Profile* profile, const Extension* extension) { | 373 void LaunchPlatformApp(Profile* profile, const Extension* extension) { |
367 LaunchPlatformAppWithCommandLine(profile, | 374 LaunchPlatformAppWithCommandLine(profile, |
368 extension, | 375 extension, |
369 CommandLine(CommandLine::NO_PROGRAM), | 376 CommandLine(CommandLine::NO_PROGRAM), |
370 base::FilePath()); | 377 base::FilePath()); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 void LaunchPlatformAppWithUrl(Profile* profile, | 412 void LaunchPlatformAppWithUrl(Profile* profile, |
406 const Extension* extension, | 413 const Extension* extension, |
407 const std::string& handler_id, | 414 const std::string& handler_id, |
408 const GURL& url, | 415 const GURL& url, |
409 const GURL& referrer_url) { | 416 const GURL& referrer_url) { |
410 AppEventRouter::DispatchOnLaunchedEventWithUrl( | 417 AppEventRouter::DispatchOnLaunchedEventWithUrl( |
411 profile, extension, handler_id, url, referrer_url); | 418 profile, extension, handler_id, url, referrer_url); |
412 } | 419 } |
413 | 420 |
414 } // namespace apps | 421 } // namespace apps |
OLD | NEW |