Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(76)

Side by Side Diff: chrome/browser/extensions/platform_app_launcher.cc

Issue 10834383: Chrome OS "open with" picker allowing Web Intents (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: TaskType enum Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/extensions/platform_app_launcher.h" 5 #include "chrome/browser/extensions/platform_app_launcher.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/file_path.h" 8 #include "base/file_path.h"
9 #include "base/file_util.h" 9 #include "base/file_util.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 if (current_directory.empty()) 46 if (current_directory.empty())
47 return file_util::AbsolutePath(file_path); 47 return file_util::AbsolutePath(file_path);
48 48
49 if (!current_directory.IsAbsolute()) 49 if (!current_directory.IsAbsolute())
50 return false; 50 return false;
51 51
52 *file_path = current_directory.Append(*file_path); 52 *file_path = current_directory.Append(*file_path);
53 return true; 53 return true;
54 } 54 }
55 55
56 // Class to handle launching of platform apps with command line information. 56 // Class to handle launching of platform apps to open a specific path.
57 // An instance of this class is created for each launch. The lifetime of these 57 // An instance of this class is created for each launch. The lifetime of these
58 // instances is managed by reference counted pointers. As long as an instance 58 // instances is managed by reference counted pointers. As long as an instance
59 // has outstanding tasks on a message queue it will be retained; once all 59 // has outstanding tasks on a message queue it will be retained; once all
60 // outstanding tasks are completed it will be deleted. 60 // outstanding tasks are completed it will be deleted.
61 class PlatformAppCommandLineLauncher 61 class PlatformAppPathLauncher
62 : public base::RefCountedThreadSafe<PlatformAppCommandLineLauncher> { 62 : public base::RefCountedThreadSafe<PlatformAppPathLauncher> {
63 public: 63 public:
64 PlatformAppCommandLineLauncher(Profile* profile, 64 PlatformAppPathLauncher(Profile* profile,
65 const Extension* extension, 65 const Extension* extension,
66 const CommandLine* command_line, 66 const FilePath& file_path)
67 const FilePath& current_directory)
68 : profile_(profile), 67 : profile_(profile),
69 extension_(extension), 68 extension_(extension),
70 command_line_(command_line), 69 file_path_(file_path) {}
71 current_directory_(current_directory) {}
72 70
73 void Launch() { 71 void Launch() {
74 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
75 if (!command_line_ || !command_line_->GetArgs().size()) { 73 if (file_path_.empty()) {
76 LaunchWithNoLaunchData(); 74 LaunchWithNoLaunchData();
77 return; 75 return;
78 } 76 }
79 77
80 FilePath file_path(command_line_->GetArgs()[0]); 78 DCHECK(file_path_.IsAbsolute());
81 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind( 79 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
82 &PlatformAppCommandLineLauncher::GetMimeTypeAndLaunch, 80 &PlatformAppPathLauncher::GetMimeTypeAndLaunch, this));
83 this, file_path));
84 } 81 }
85 82
86 private: 83 private:
87 friend class base::RefCountedThreadSafe<PlatformAppCommandLineLauncher>; 84 friend class base::RefCountedThreadSafe<PlatformAppPathLauncher>;
88 85
89 virtual ~PlatformAppCommandLineLauncher() {} 86 virtual ~PlatformAppPathLauncher() {}
90 87
91 void LaunchWithNoLaunchData() { 88 void LaunchWithNoLaunchData() {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
93 extensions::AppEventRouter::DispatchOnLaunchedEvent(profile_, extension_); 90 extensions::AppEventRouter::DispatchOnLaunchedEvent(profile_, extension_);
94 } 91 }
95 92
96 void GetMimeTypeAndLaunch(const FilePath& file_path) { 93 void GetMimeTypeAndLaunch() {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
98 95
99 // If we cannot construct an absolute path, launch with no launch data. 96 // If the file doesn't exist, or is a directory, launch with no launch data.
100 FilePath absolute_path(file_path); 97 if (!file_util::PathExists(file_path_) ||
101 if (!MakePathAbsolute(current_directory_, &absolute_path)) { 98 file_util::DirectoryExists(file_path_)) {
102 LOG(WARNING) << "Cannot make absolute path from " << file_path.value(); 99 LOG(WARNING) << "No file exists with path " << file_path_.value();
103 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 100 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
104 &PlatformAppCommandLineLauncher::LaunchWithNoLaunchData, this)); 101 &PlatformAppPathLauncher::LaunchWithNoLaunchData, this));
105 return;
106 }
107
108 // If the file doesn't exist, or is a directory, launch with no launch data.
109 if (!file_util::PathExists(absolute_path) ||
110 file_util::DirectoryExists(absolute_path)) {
111 LOG(WARNING) << "No file exists with path " << absolute_path.value();
112 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
113 &PlatformAppCommandLineLauncher::LaunchWithNoLaunchData, this));
114 return; 102 return;
115 } 103 }
116 104
117 std::string mime_type; 105 std::string mime_type;
118 // If we cannot obtain the MIME type, launch with no launch data. 106 // If we cannot obtain the MIME type, launch with no launch data.
119 if (!net::GetMimeTypeFromFile(absolute_path, &mime_type)) { 107 if (!net::GetMimeTypeFromFile(file_path_, &mime_type)) {
120 LOG(WARNING) << "Could not obtain MIME type for " 108 LOG(WARNING) << "Could not obtain MIME type for "
121 << absolute_path.value(); 109 << file_path_.value();
122 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 110 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
123 &PlatformAppCommandLineLauncher::LaunchWithNoLaunchData, this)); 111 &PlatformAppPathLauncher::LaunchWithNoLaunchData, this));
124 return; 112 return;
125 } 113 }
126 114
127 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind( 115 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
128 &PlatformAppCommandLineLauncher::LaunchWithMimeTypeAndPath, 116 &PlatformAppPathLauncher::LaunchWithMimeType, this, mime_type));
129 this, absolute_path, mime_type));
130 } 117 }
131 118
132 void LaunchWithMimeTypeAndPath(const FilePath& file_path, 119 void LaunchWithMimeType(const std::string& mime_type) {
133 const std::string& mime_type) {
134 // Find the intent service from the platform app for the file being opened. 120 // Find the intent service from the platform app for the file being opened.
135 webkit_glue::WebIntentServiceData service; 121 webkit_glue::WebIntentServiceData service;
136 bool found_service = false; 122 bool found_service = false;
137 123
138 std::vector<webkit_glue::WebIntentServiceData> services = 124 std::vector<webkit_glue::WebIntentServiceData> services =
139 extension_->intents_services(); 125 extension_->intents_services();
140 for (size_t i = 0; i < services.size(); i++) { 126 for (size_t i = 0; i < services.size(); i++) {
141 std::string service_type_ascii = UTF16ToASCII(services[i].type); 127 std::string service_type_ascii = UTF16ToASCII(services[i].type);
142 if (services[i].action == ASCIIToUTF16(kViewIntent) && 128 if (services[i].action == ASCIIToUTF16(kViewIntent) &&
143 net::MatchesMimeType(service_type_ascii, mime_type)) { 129 net::MatchesMimeType(service_type_ascii, mime_type)) {
144 service = services[i]; 130 service = services[i];
145 found_service = true; 131 found_service = true;
146 break; 132 break;
147 } 133 }
148 } 134 }
149 135
150 // If this app doesn't have an intent that supports the file, launch with 136 // If this app doesn't have an intent that supports the file, launch with
151 // no launch data. 137 // no launch data.
152 if (!found_service) { 138 if (!found_service) {
153 LOG(WARNING) << "Extension does not provide a valid intent for " 139 LOG(WARNING) << "Extension does not provide a valid intent for "
154 << file_path.value(); 140 << file_path_.value();
155 LaunchWithNoLaunchData(); 141 LaunchWithNoLaunchData();
156 return; 142 return;
157 } 143 }
158 144
159 // Access needs to be granted to the file for the process associated with 145 // Access needs to be granted to the file for the process associated with
160 // the extension. To do this the ExtensionHost is needed. This might not be 146 // the extension. To do this the ExtensionHost is needed. This might not be
161 // available, or it might be in the process of being unloaded, in which case 147 // available, or it might be in the process of being unloaded, in which case
162 // the lazy background task queue is used to load the extension and then 148 // the lazy background task queue is used to load the extension and then
163 // call back to us. 149 // call back to us.
164 extensions::LazyBackgroundTaskQueue* queue = 150 extensions::LazyBackgroundTaskQueue* queue =
165 ExtensionSystem::Get(profile_)->lazy_background_task_queue(); 151 ExtensionSystem::Get(profile_)->lazy_background_task_queue();
166 if (queue->ShouldEnqueueTask(profile_, extension_)) { 152 if (queue->ShouldEnqueueTask(profile_, extension_)) {
167 queue->AddPendingTask(profile_, extension_->id(), base::Bind( 153 queue->AddPendingTask(profile_, extension_->id(), base::Bind(
168 &PlatformAppCommandLineLauncher::GrantAccessToFileAndLaunch, 154 &PlatformAppPathLauncher::GrantAccessToFileAndLaunch,
169 this, file_path, mime_type)); 155 this, mime_type));
170 return; 156 return;
171 } 157 }
172 158
173 ExtensionProcessManager* process_manager = 159 ExtensionProcessManager* process_manager =
174 ExtensionSystem::Get(profile_)->process_manager(); 160 ExtensionSystem::Get(profile_)->process_manager();
175 extensions::ExtensionHost* host = 161 extensions::ExtensionHost* host =
176 process_manager->GetBackgroundHostForExtension(extension_->id()); 162 process_manager->GetBackgroundHostForExtension(extension_->id());
177 DCHECK(host); 163 DCHECK(host);
178 GrantAccessToFileAndLaunch(file_path, mime_type, host); 164 GrantAccessToFileAndLaunch(mime_type, host);
179 } 165 }
180 166
181 void GrantAccessToFileAndLaunch(const FilePath& file_path, 167 void GrantAccessToFileAndLaunch(const std::string& mime_type,
182 const std::string& mime_type,
183 extensions::ExtensionHost* host) { 168 extensions::ExtensionHost* host) {
184 // If there was an error loading the app page, |host| will be NULL. 169 // If there was an error loading the app page, |host| will be NULL.
185 if (!host) { 170 if (!host) {
186 LOG(ERROR) << "Could not load app page for " << extension_->id(); 171 LOG(ERROR) << "Could not load app page for " << extension_->id();
187 return; 172 return;
188 } 173 }
189 174
190 content::ChildProcessSecurityPolicy* policy = 175 content::ChildProcessSecurityPolicy* policy =
191 content::ChildProcessSecurityPolicy::GetInstance(); 176 content::ChildProcessSecurityPolicy::GetInstance();
192 int renderer_id = host->render_process_host()->GetID(); 177 int renderer_id = host->render_process_host()->GetID();
193 178
194 // Granting read file permission to allow reading file content. 179 // Granting read file permission to allow reading file content.
195 // If the renderer already has permission to read these paths, it is not 180 // If the renderer already has permission to read these paths, it is not
196 // regranted, as this would overwrite any other permissions which the 181 // regranted, as this would overwrite any other permissions which the
197 // renderer may already have. 182 // renderer may already have.
198 if (!policy->CanReadFile(renderer_id, file_path)) 183 if (!policy->CanReadFile(renderer_id, file_path_))
199 policy->GrantReadFile(renderer_id, file_path); 184 policy->GrantReadFile(renderer_id, file_path_);
200 185
201 std::string registered_name; 186 std::string registered_name;
202 fileapi::IsolatedContext* isolated_context = 187 fileapi::IsolatedContext* isolated_context =
203 fileapi::IsolatedContext::GetInstance(); 188 fileapi::IsolatedContext::GetInstance();
204 DCHECK(isolated_context); 189 DCHECK(isolated_context);
205 std::string filesystem_id = isolated_context->RegisterFileSystemForPath( 190 std::string filesystem_id = isolated_context->RegisterFileSystemForPath(
206 fileapi::kFileSystemTypeIsolated, file_path, &registered_name); 191 fileapi::kFileSystemTypeIsolated, file_path_, &registered_name);
207 // Granting read file system permission as well to allow file-system 192 // Granting read file system permission as well to allow file-system
208 // read operations. 193 // read operations.
209 policy->GrantReadFileSystem(renderer_id, filesystem_id); 194 policy->GrantReadFileSystem(renderer_id, filesystem_id);
210 195
211 extensions::AppEventRouter::DispatchOnLaunchedEventWithFileEntry( 196 extensions::AppEventRouter::DispatchOnLaunchedEventWithFileEntry(
212 profile_, extension_, ASCIIToUTF16(kViewIntent), filesystem_id, 197 profile_, extension_, ASCIIToUTF16(kViewIntent), filesystem_id,
213 registered_name); 198 registered_name);
214 } 199 }
215 200
216 // The profile the app should be run in. 201 // The profile the app should be run in.
217 Profile* profile_; 202 Profile* profile_;
218 // The extension providing the app. 203 // The extension providing the app.
219 const Extension* extension_; 204 const Extension* extension_;
220 // The command line to be passed through to the app, or NULL. 205 // The path to be passed through to the app. This may be the empty path.
221 const CommandLine* command_line_; 206 const FilePath file_path_;
222 // If non-empty, this is used to expand relative paths.
223 const FilePath current_directory_;
224 207
225 DISALLOW_COPY_AND_ASSIGN(PlatformAppCommandLineLauncher); 208 DISALLOW_COPY_AND_ASSIGN(PlatformAppPathLauncher);
226 }; 209 };
227 210
228 // Class to handle launching of platform apps with WebIntent data that is being 211 // Class to handle launching of platform apps with WebIntent data that is being
229 // passed in a a blob. 212 // passed in a a blob.
230 // An instance of this class is created for each launch. The lifetime of these 213 // An instance of this class is created for each launch. The lifetime of these
231 // instances is managed by reference counted pointers. As long as an instance 214 // instances is managed by reference counted pointers. As long as an instance
232 // has outstanding tasks on a message queue it will be retained; once all 215 // has outstanding tasks on a message queue it will be retained; once all
233 // outstanding tasks are completed it will be deleted. 216 // outstanding tasks are completed it will be deleted.
234 class PlatformAppBlobIntentLauncher 217 class PlatformAppBlobIntentLauncher
235 : public base::RefCountedThreadSafe<PlatformAppBlobIntentLauncher> { 218 : public base::RefCountedThreadSafe<PlatformAppBlobIntentLauncher> {
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 285
303 DISALLOW_COPY_AND_ASSIGN(PlatformAppBlobIntentLauncher); 286 DISALLOW_COPY_AND_ASSIGN(PlatformAppBlobIntentLauncher);
304 }; 287 };
305 288
306 } // namespace 289 } // namespace
307 290
308 void LaunchPlatformApp(Profile* profile, 291 void LaunchPlatformApp(Profile* profile,
309 const Extension* extension, 292 const Extension* extension,
310 const CommandLine* command_line, 293 const CommandLine* command_line,
311 const FilePath& current_directory) { 294 const FilePath& current_directory) {
295 // Optionally resolve the file_path from the first command-line argument.
benwells 2012/08/30 08:09:03 I really like these refactorings as the role of th
thorogood 2012/08/31 01:27:32 These are great suggestions! The code feels much n
296 FilePath file_path;
297 if (command_line && command_line->GetArgs().size()) {
298 file_path = FilePath(command_line->GetArgs()[0]);
299
300 // If we cannot construct an absolute path, launch with no launch data.
301 FilePath absolute_path(file_path);
302 if (!MakePathAbsolute(current_directory, &absolute_path)) {
303 LOG(WARNING) << "Cannot make absolute path from " << file_path.value();
304 file_path = FilePath();
305 } else {
306 file_path = absolute_path;
307 }
308 }
309 LaunchPlatformAppWithPath(profile, extension, file_path);
310 }
311
312 void LaunchPlatformAppWithPath(Profile* profile,
313 const Extension* extension,
314 const FilePath& file_path) {
312 // launcher will be freed when nothing has a reference to it. The message 315 // launcher will be freed when nothing has a reference to it. The message
313 // queue will retain a reference for any outstanding task, so when the 316 // queue will retain a reference for any outstanding task, so when the
314 // launcher has finished it will be freed. 317 // launcher has finished it will be freed.
315 scoped_refptr<PlatformAppCommandLineLauncher> launcher = 318 scoped_refptr<PlatformAppPathLauncher> launcher =
316 new PlatformAppCommandLineLauncher(profile, extension, command_line, 319 new PlatformAppPathLauncher(profile, extension, file_path);
317 current_directory);
318 launcher->Launch(); 320 launcher->Launch();
319 } 321 }
320 322
321 void LaunchPlatformAppWithWebIntent( 323 void LaunchPlatformAppWithWebIntent(
322 Profile* profile, 324 Profile* profile,
323 const Extension* extension, 325 const Extension* extension,
324 const webkit_glue::WebIntentData& web_intent_data) { 326 const webkit_glue::WebIntentData& web_intent_data) {
325 if (web_intent_data.data_type == webkit_glue::WebIntentData::BLOB) { 327 if (web_intent_data.data_type == webkit_glue::WebIntentData::BLOB) {
326 scoped_refptr<PlatformAppBlobIntentLauncher> launcher = 328 scoped_refptr<PlatformAppBlobIntentLauncher> launcher =
327 new PlatformAppBlobIntentLauncher(profile, extension, web_intent_data); 329 new PlatformAppBlobIntentLauncher(profile, extension, web_intent_data);
328 launcher->Launch(); 330 launcher->Launch();
329 return; 331 return;
330 } 332 }
331 333
332 extensions::AppEventRouter::DispatchOnLaunchedEventWithWebIntent( 334 extensions::AppEventRouter::DispatchOnLaunchedEventWithWebIntent(
333 profile, extension, web_intent_data); 335 profile, extension, web_intent_data);
334 } 336 }
335 337
336 } // namespace extensions 338 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698