summaryrefslogtreecommitdiffstats
path: root/content/browser/mojo/mojo_shell_context.cc
blob: aee1a2eb17d4b3fd87d5e4577420989fdf60ed2b (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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// Copyright 2015 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.

#include "content/browser/mojo/mojo_shell_context.h"

#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
#include "content/common/process_control.mojom.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/utility_process_host.h"
#include "content/public/browser/utility_process_host_client.h"
#include "content/public/common/content_client.h"
#include "content/public/common/service_registry.h"
#include "mojo/application/public/cpp/application_delegate.h"
#include "mojo/common/url_type_converters.h"
#include "mojo/services/network/public/interfaces/url_loader.mojom.h"
#include "mojo/shell/application_loader.h"
#include "mojo/shell/static_application_loader.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/string.h"

#if defined(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
#include "media/mojo/services/mojo_media_application.h"
#endif

namespace content {

namespace {

// An extra set of apps to register on initialization, if set by a test.
const MojoShellContext::StaticApplicationMap* g_applications_for_test;

void StartProcessOnIOThread(mojo::InterfaceRequest<ProcessControl> request,
                            bool use_sandbox) {
  UtilityProcessHost* process_host =
      UtilityProcessHost::Create(nullptr, nullptr);
  // TODO(rockot): Make it possible for the embedder to associate app URLs with
  // app names so we can have more meaningful process names here.
  process_host->SetName(base::UTF8ToUTF16("Mojo Application"));
  if (!use_sandbox)
    process_host->DisableSandbox();
  process_host->StartMojoMode();

  ServiceRegistry* services = process_host->GetServiceRegistry();
  services->ConnectToRemoteService(request.Pass());
}

void OnApplicationLoaded(const GURL& url, bool success) {
  if (!success)
    LOG(ERROR) << "Failed to launch Mojo application for " << url.spec();
}

// The default loader to use for all applications. This launches a utility
// process and forwards the Load request the ProcessControl service there.
// The utility process is sandboxed if |use_sandbox| is true and vice versa.
class UtilityProcessLoader : public mojo::shell::ApplicationLoader {
 public:
  explicit UtilityProcessLoader(bool use_sandbox) : use_sandbox_(use_sandbox) {}
  ~UtilityProcessLoader() override {}

 private:
  // mojo::shell::ApplicationLoader:
  void Load(
      const GURL& url,
      mojo::InterfaceRequest<mojo::Application> application_request) override {
    ProcessControlPtr process_control;
    auto process_request = mojo::GetProxy(&process_control);
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        base::Bind(&StartProcessOnIOThread, base::Passed(&process_request),
                   use_sandbox_));
    process_control->LoadApplication(url.spec(), application_request.Pass(),
                                     base::Bind(&OnApplicationLoaded, url));
  }

  const bool use_sandbox_;

  DISALLOW_COPY_AND_ASSIGN(UtilityProcessLoader);
};

}  // namespace

// Thread-safe proxy providing access to the shell context from any thread.
class MojoShellContext::Proxy {
 public:
  Proxy(MojoShellContext* shell_context)
      : shell_context_(shell_context),
        task_runner_(base::ThreadTaskRunnerHandle::Get()) {}

  ~Proxy() {}

  void ConnectToApplication(
      const GURL& url,
      const GURL& requestor_url,
      mojo::InterfaceRequest<mojo::ServiceProvider> request,
      mojo::ServiceProviderPtr exposed_services,
      const mojo::shell::CapabilityFilter& filter) {
    if (task_runner_ == base::ThreadTaskRunnerHandle::Get()) {
      if (shell_context_) {
        shell_context_->ConnectToApplicationOnOwnThread(
            url, requestor_url, request.Pass(), exposed_services.Pass(),
            filter);
      }
    } else {
      // |shell_context_| outlives the main MessageLoop, so it's safe for it to
      // be unretained here.
      task_runner_->PostTask(
          FROM_HERE,
          base::Bind(&MojoShellContext::ConnectToApplicationOnOwnThread,
                     base::Unretained(shell_context_), url, requestor_url,
                     base::Passed(&request), base::Passed(&exposed_services),
                     filter));
    }
  }

 private:
  MojoShellContext* shell_context_;
  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;

  DISALLOW_COPY_AND_ASSIGN(Proxy);
};

// static
base::LazyInstance<scoped_ptr<MojoShellContext::Proxy>>
    MojoShellContext::proxy_ = LAZY_INSTANCE_INITIALIZER;

void MojoShellContext::SetApplicationsForTest(
    const StaticApplicationMap* apps) {
  g_applications_for_test = apps;
}

MojoShellContext::MojoShellContext()
    : application_manager_(new mojo::shell::ApplicationManager(this)) {
  proxy_.Get().reset(new Proxy(this));

  application_manager_->set_default_loader(
      scoped_ptr<mojo::shell::ApplicationLoader>(
          new UtilityProcessLoader(true /* use_sandbox */)));

  StaticApplicationMap apps;
  GetContentClient()->browser()->RegisterInProcessMojoApplications(&apps);
  if (g_applications_for_test) {
    // Add testing apps to the map, potentially overwriting whatever the
    // browser client registered.
    for (const auto& entry : *g_applications_for_test)
      apps[entry.first] = entry.second;
  }
  for (const auto& entry : apps) {
    application_manager_->SetLoaderForURL(
        scoped_ptr<mojo::shell::ApplicationLoader>(
            new mojo::shell::StaticApplicationLoader(entry.second)),
        entry.first);
  }

  std::vector<GURL> urls;
  GetContentClient()
      ->browser()
      ->RegisterUnsandboxedOutOfProcessMojoApplications(&urls);
  for (const auto& url : urls) {
    application_manager_->SetLoaderForURL(
        scoped_ptr<mojo::shell::ApplicationLoader>(
            new UtilityProcessLoader(false /* use_sandbox */)),
        url);
  }

#if (ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
  application_manager_->SetLoaderForURL(
      scoped_ptr<mojo::shell::ApplicationLoader>(
          new mojo::shell::StaticApplicationLoader(
              base::Bind(&media::MojoMediaApplication::CreateApp))),
      media::MojoMediaApplication::AppUrl());
#endif
}

MojoShellContext::~MojoShellContext() {
}

// static
void MojoShellContext::ConnectToApplication(
    const GURL& url,
    const GURL& requestor_url,
    mojo::InterfaceRequest<mojo::ServiceProvider> request,
    mojo::ServiceProviderPtr exposed_services,
    const mojo::shell::CapabilityFilter& filter) {
  proxy_.Get()->ConnectToApplication(url, requestor_url, request.Pass(),
                                     exposed_services.Pass(), filter);
}

void MojoShellContext::ConnectToApplicationOnOwnThread(
    const GURL& url,
    const GURL& requestor_url,
    mojo::InterfaceRequest<mojo::ServiceProvider> request,
    mojo::ServiceProviderPtr exposed_services,
    const mojo::shell::CapabilityFilter& filter) {
  mojo::URLRequestPtr url_request = mojo::URLRequest::New();
  url_request->url = mojo::String::From(url);
  application_manager_->ConnectToApplication(
      nullptr, url_request.Pass(), std::string(), requestor_url, request.Pass(),
      exposed_services.Pass(), filter, base::Bind(&base::DoNothing));
}

GURL MojoShellContext::ResolveMappings(const GURL& url) {
  return url;
}

GURL MojoShellContext::ResolveMojoURL(const GURL& url) {
  return url;
}

bool MojoShellContext::CreateFetcher(
    const GURL& url,
    const mojo::shell::Fetcher::FetchCallback& loader_callback) {
  return false;
}

}  // namespace content