summaryrefslogtreecommitdiffstats
path: root/content/ppapi_plugin/ppapi_thread.cc
blob: cab4d937c5779d1979f8e0cc8013a96f199d7653 (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
// Copyright (c) 2011 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/ppapi_plugin/ppapi_thread.h"

#include <limits>

#include "base/process_util.h"
#include "base/rand_util.h"
#include "content/common/child_process.h"
#include "content/ppapi_plugin/plugin_process_dispatcher.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_sync_channel.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppp.h"
#include "ppapi/proxy/ppapi_messages.h"

typedef int32_t (*InitializeBrokerFunc)
    (PP_ConnectInstance_Func* connect_instance_func);

PpapiThread::PpapiThread(bool is_broker)
    : is_broker_(is_broker),
      get_plugin_interface_(NULL),
      connect_instance_func_(NULL),
      local_pp_module_(
          base::RandInt(0, std::numeric_limits<PP_Module>::max())) {
}

PpapiThread::~PpapiThread() {
  if (!library_.is_valid())
    return;

  // The ShutdownModule/ShutdownBroker function is optional.
  pp::proxy::Dispatcher::ShutdownModuleFunc shutdown_function =
      is_broker_ ?
      reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>(
          library_.GetFunctionPointer("PPP_ShutdownBroker")) :
      reinterpret_cast<pp::proxy::Dispatcher::ShutdownModuleFunc>(
          library_.GetFunctionPointer("PPP_ShutdownModule"));
  if (shutdown_function)
    shutdown_function();
}

// The "regular" ChildThread implements this function and does some standard
// dispatching, then uses the message router. We don't actually need any of
// this so this function just overrides that one.
//
// Note that this function is called only for messages from the channel to the
// browser process. Messages from the renderer process are sent via a different
// channel that ends up at Dispatcher::OnMessageReceived.
bool PpapiThread::OnMessageReceived(const IPC::Message& msg) {
  IPC_BEGIN_MESSAGE_MAP(PpapiThread, msg)
    IPC_MESSAGE_HANDLER(PpapiMsg_LoadPlugin, OnMsgLoadPlugin)
    IPC_MESSAGE_HANDLER(PpapiMsg_CreateChannel, OnMsgCreateChannel)
  IPC_END_MESSAGE_MAP()
  return true;
}

MessageLoop* PpapiThread::GetIPCMessageLoop() {
  return ChildProcess::current()->io_message_loop();
}

base::WaitableEvent* PpapiThread::GetShutdownEvent() {
  return ChildProcess::current()->GetShutDownEvent();
}

std::set<PP_Instance>* PpapiThread::GetGloballySeenInstanceIDSet() {
  return &globally_seen_instance_ids_;
}

void PpapiThread::OnMsgLoadPlugin(const FilePath& path) {
  base::ScopedNativeLibrary library(base::LoadNativeLibrary(path));
  if (!library.is_valid())
    return;

  if (is_broker_) {
    // Get the InitializeBroker function (required).
    InitializeBrokerFunc init_broker =
        reinterpret_cast<InitializeBrokerFunc>(
            library.GetFunctionPointer("PPP_InitializeBroker"));
    if (!init_broker) {
      LOG(WARNING) << "No PPP_InitializeBroker in plugin library";
      return;
    }

    int32_t init_error = init_broker(&connect_instance_func_);
    if (init_error != PP_OK) {
      LOG(WARNING) << "InitBroker failed with error " << init_error;
      return;
    }
    if (!connect_instance_func_) {
      LOG(WARNING) << "InitBroker did not provide PP_ConnectInstance_Func";
      return;
    }
  } else {
    // Get the GetInterface function (required).
    get_plugin_interface_ =
        reinterpret_cast<pp::proxy::Dispatcher::GetInterfaceFunc>(
            library.GetFunctionPointer("PPP_GetInterface"));
    if (!get_plugin_interface_) {
      LOG(WARNING) << "No PPP_GetInterface in plugin library";
      return;
    }

    // Get the InitializeModule function (required).
    pp::proxy::Dispatcher::InitModuleFunc init_module =
        reinterpret_cast<pp::proxy::Dispatcher::InitModuleFunc>(
            library.GetFunctionPointer("PPP_InitializeModule"));
    if (!init_module) {
      LOG(WARNING) << "No PPP_InitializeModule in plugin library";
      return;
    }
    int32_t init_error = init_module(
        local_pp_module_,
        &pp::proxy::PluginDispatcher::GetInterfaceFromDispatcher);
    if (init_error != PP_OK) {
      LOG(WARNING) << "InitModule failed with error " << init_error;
      return;
    }
  }

  library_.Reset(library.Release());
}

void PpapiThread::OnMsgCreateChannel(base::ProcessHandle host_process_handle,
                                     int renderer_id) {
  IPC::ChannelHandle channel_handle;
  if (!library_.is_valid() ||  // Plugin couldn't be loaded.
      !SetupRendererChannel(host_process_handle, renderer_id,
                            &channel_handle)) {
    Send(new PpapiHostMsg_ChannelCreated(IPC::ChannelHandle()));
    return;
  }

  Send(new PpapiHostMsg_ChannelCreated(channel_handle));
}

bool PpapiThread::SetupRendererChannel(base::ProcessHandle host_process_handle,
                                       int renderer_id,
                                       IPC::ChannelHandle* handle) {
  // TODO(ddorwin): PluginProcessDispatcher is overkill for the broker. TBD
  // whether to create separate dispatcher classes for the broker.
  // TODO(ddorwin): Provide connect_instance_func_ when is_broker_.
  DCHECK(is_broker_ == (connect_instance_func_ != NULL));
  DCHECK(is_broker_ == (get_plugin_interface_ == NULL));
  PluginProcessDispatcher* dispatcher(new PluginProcessDispatcher(
      host_process_handle, get_plugin_interface_));

  IPC::ChannelHandle plugin_handle;
  plugin_handle.name = StringPrintf("%d.r%d", base::GetCurrentProcId(),
                                    renderer_id);
  if (!dispatcher->InitWithChannel(this, plugin_handle, false)) {
    delete dispatcher;
    return false;
  }

  handle->name = plugin_handle.name;
#if defined(OS_POSIX)
  // On POSIX, pass the renderer-side FD.
  handle->socket = base::FileDescriptor(::dup(dispatcher->GetRendererFD()),
                                        true);
#endif

  // From here, the dispatcher will manage its own lifetime according to the
  // lifetime of the attached channel.
  return true;
}