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

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

Issue 10332071: Pass command line arguments onto platform apps which provide the right intent. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments Created 8 years, 7 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/platform_app_launcher.h"
6
7 #include "base/command_line.h"
8 #include "base/file_path.h"
9 #include "base/file_util.h"
10 #include "base/logging.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/string_util.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/extensions/api/app/app_api.h"
15 #include "chrome/browser/extensions/extension_host.h"
16 #include "chrome/browser/extensions/extension_process_manager.h"
17 #include "chrome/browser/extensions/extension_system.h"
18 #include "chrome/browser/extensions/lazy_background_task_queue.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/common/extensions/extension.h"
21 #include "chrome/common/extensions/extension_messages.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/child_process_security_policy.h"
24 #include "content/public/browser/render_process_host.h"
25 #include "net/base/mime_util.h"
26 #include "net/base/net_util.h"
27 #include "webkit/fileapi/isolated_context.h"
28 #include "webkit/glue/web_intent_service_data.h"
29
30 using content::BrowserThread;
31 using extensions::Extension;
32
33 namespace {
34
35 const char kViewIntent[] = "http://webintents.org/view";
36
37 class PlatformAppLauncher
38 : public base::RefCountedThreadSafe<PlatformAppLauncher> {
39 public:
40 PlatformAppLauncher(Profile* profile,
41 const Extension* extension,
42 const CommandLine* command_line)
43 : profile_(profile),
44 extension_(extension),
45 command_line_(command_line) {}
46
47 void Launch() {
48 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
49 if (!command_line_ || !command_line_->GetArgs().size()) {
50 LaunchWithNoLaunchData();
51 return;
52 }
53
54 FilePath file_path(command_line_->GetArgs()[0]);
55 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(
56 &PlatformAppLauncher::GetMimeTypeAndLaunch, this, file_path));
57 }
58
59 private:
60 void LaunchWithNoLaunchData() {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
62 extensions::AppEventRouter::DispatchOnLaunchedEvent(profile_, extension_);
63 }
64
65 void GetMimeTypeAndLaunch(const FilePath& file_path) {
66 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
67
68 // If the file doesn't exist, or is a directory, launch with no launch data.
69 if (!file_util::PathExists(file_path) ||
70 file_util::DirectoryExists(file_path)) {
71 LOG(WARNING) << "No file exists with path " << file_path.value();
72 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
73 &PlatformAppLauncher::LaunchWithNoLaunchData, this));
74 return;
75 }
76
77 std::string mime_type;
78 // If we cannot obtain the MIME type, launch with no launch data.
79 if (!net::GetMimeTypeFromFile(file_path, &mime_type)) {
80 LOG(WARNING) << "Could not obtain MIME type for " << file_path.value();
81 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
82 &PlatformAppLauncher::LaunchWithNoLaunchData, this));
83 return;
84 }
85
86 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
87 &PlatformAppLauncher::LaunchWithMimeTypeAndPath, this, file_path,
88 mime_type));
89 }
90
91 void LaunchWithMimeTypeAndPath(const FilePath& file_path,
92 const std::string& mime_type) {
93 // Find the intent service from the platform app for the file being opened.
94 webkit_glue::WebIntentServiceData service;
95 bool found_service = false;
96
97 std::vector<webkit_glue::WebIntentServiceData> services =
98 extension_->intents_services();
99 for (size_t i = 0; i < services.size(); i++) {
100 std::string service_type_ascii = UTF16ToASCII(services[i].type);
101 if (services[i].action == ASCIIToUTF16(kViewIntent) &&
102 net::MatchesMimeType(service_type_ascii, mime_type)) {
103 service = services[i];
104 found_service = true;
105 break;
106 }
107 }
108
109 // If this app doesn't have an intent that supports the file, launch with
110 // no launch data.
111 if (!found_service) {
112 LOG(WARNING) << "Extension does not provide a valid intent for "
113 << file_path.value();
114 LaunchWithNoLaunchData();
115 return;
116 }
117
118 // We need to grant access to the file for the process associated with the
119 // extension. To do this we need the ExtensionHost. This might not be
120 // available, or it might be in the process of being unloaded, in which case
121 // we can use the lazy background task queue to load the extension and then
122 // call back to us.
123 extensions::LazyBackgroundTaskQueue* queue =
124 ExtensionSystem::Get(profile_)->lazy_background_task_queue();
125 if (queue->ShouldEnqueueTask(profile_, extension_)) {
126 queue->AddPendingTask(profile_, extension_->id(),
127 base::Bind(&PlatformAppLauncher::GrantAccessToFileAndLaunch,
128 this, file_path, mime_type));
129 return;
130 }
131
132 ExtensionProcessManager* pm =
133 ExtensionSystem::Get(profile_)->process_manager();
134 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_->id());
135 DCHECK(host);
136 GrantAccessToFileAndLaunch(file_path, mime_type, host);
137 }
138
139 void GrantAccessToFileAndLaunch(const FilePath& file_path,
140 const std::string& mime_type,
141 ExtensionHost* host) {
142 // If there was an error loading the app page, |host| will be NULL.
143 if (!host) {
144 LOG(ERROR) << "Could not load app page for " << extension_->id();
145 return;
146 }
147
148 content::ChildProcessSecurityPolicy* policy =
149 content::ChildProcessSecurityPolicy::GetInstance();
150 int renderer_id = host->render_process_host()->GetID();
151
152 // If the renderer already has permission to read these paths, we don't
153 // regrant, as this would overwrite any other permissions which the renderer
154 // may already have.
155 if (!policy->CanReadFile(renderer_id, file_path))
156 policy->GrantReadFile(renderer_id, file_path);
157
158 std::set<FilePath> filesets;
159 filesets.insert(file_path);
160
161 fileapi::IsolatedContext* isolated_context =
162 fileapi::IsolatedContext::GetInstance();
163 DCHECK(isolated_context);
164 std::string filesystem_id = isolated_context->RegisterIsolatedFileSystem(
165 filesets);
166 policy->GrantAccessFileSystem(renderer_id, filesystem_id);
167
168 extensions::AppEventRouter::DispatchOnLaunchedEventWithFileEntry(
169 profile_, extension_, ASCIIToUTF16(kViewIntent), filesystem_id,
170 file_path.BaseName());
171 }
172
173 Profile* profile_;
174 const Extension* extension_;
175 const CommandLine* command_line_;
176
177 DISALLOW_COPY_AND_ASSIGN(PlatformAppLauncher);
178 };
179
180 } // namespace
181
182 namespace extensions {
183
184 void LaunchPlatformApp(Profile* profile,
185 const Extension* extension,
186 const CommandLine* command_line) {
187 // launcher will be freed when nothing has a reference to it. The message
188 // queue will retain a reference for any outstanding task, so when the
189 // launcher has finished it will be freed.
190 scoped_refptr<PlatformAppLauncher> launcher =
191 new PlatformAppLauncher(profile, extension, command_line);
192 launcher->Launch();
193 }
194
195 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698