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
3 // found in the LICENSE file.
4
5 #include "pnacl_translation_resource_host.h"
6
7 #include "components/nacl/common/nacl_host_messages.h"
8 #include "ppapi/c/pp_errors.h"
9 #include "ppapi/shared_impl/ppapi_globals.h"
10
11 using ppapi::TrackedCallback;
12 using ppapi::PpapiGlobals;
13
CacheRequestInfo(PP_Bool * hit,PP_FileHandle * handle,scoped_refptr<TrackedCallback> cb)14 PnaclTranslationResourceHost::CacheRequestInfo::CacheRequestInfo(
15 PP_Bool* hit,
16 PP_FileHandle* handle,
17 scoped_refptr<TrackedCallback> cb)
18 : is_hit(hit), file_handle(handle), callback(cb) {}
19
~CacheRequestInfo()20 PnaclTranslationResourceHost::CacheRequestInfo::~CacheRequestInfo() {}
21
PnaclTranslationResourceHost(const scoped_refptr<base::MessageLoopProxy> & io_message_loop)22 PnaclTranslationResourceHost::PnaclTranslationResourceHost(
23 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
24 : io_message_loop_(io_message_loop), sender_(NULL) {}
25
~PnaclTranslationResourceHost()26 PnaclTranslationResourceHost::~PnaclTranslationResourceHost() {
27 DCHECK(io_message_loop_->BelongsToCurrentThread());
28 CleanupCacheRequests();
29 }
30
OnFilterAdded(IPC::Sender * sender)31 void PnaclTranslationResourceHost::OnFilterAdded(IPC::Sender* sender) {
32 DCHECK(io_message_loop_->BelongsToCurrentThread());
33 sender_ = sender;
34 }
35
OnFilterRemoved()36 void PnaclTranslationResourceHost::OnFilterRemoved() {
37 DCHECK(io_message_loop_->BelongsToCurrentThread());
38 sender_ = NULL;
39 }
40
OnChannelClosing()41 void PnaclTranslationResourceHost::OnChannelClosing() {
42 DCHECK(io_message_loop_->BelongsToCurrentThread());
43 sender_ = NULL;
44 }
45
OnMessageReceived(const IPC::Message & message)46 bool PnaclTranslationResourceHost::OnMessageReceived(
47 const IPC::Message& message) {
48 DCHECK(io_message_loop_->BelongsToCurrentThread());
49 bool handled = true;
50 IPC_BEGIN_MESSAGE_MAP(PnaclTranslationResourceHost, message)
51 IPC_MESSAGE_HANDLER(NaClViewMsg_NexeTempFileReply, OnNexeTempFileReply)
52 IPC_MESSAGE_UNHANDLED(handled = false)
53 IPC_END_MESSAGE_MAP()
54 return handled;
55 }
56
RequestNexeFd(int render_view_id,PP_Instance instance,const nacl::PnaclCacheInfo & cache_info,PP_Bool * is_hit,PP_FileHandle * file_handle,scoped_refptr<TrackedCallback> callback)57 void PnaclTranslationResourceHost::RequestNexeFd(
58 int render_view_id,
59 PP_Instance instance,
60 const nacl::PnaclCacheInfo& cache_info,
61 PP_Bool* is_hit,
62 PP_FileHandle* file_handle,
63 scoped_refptr<TrackedCallback> callback) {
64 DCHECK(PpapiGlobals::Get()->
65 GetMainThreadMessageLoop()->BelongsToCurrentThread());
66 io_message_loop_->PostTask(
67 FROM_HERE,
68 base::Bind(&PnaclTranslationResourceHost::SendRequestNexeFd,
69 this,
70 render_view_id,
71 instance,
72 cache_info,
73 is_hit,
74 file_handle,
75 callback));
76 return;
77 }
78
SendRequestNexeFd(int render_view_id,PP_Instance instance,const nacl::PnaclCacheInfo & cache_info,PP_Bool * is_hit,PP_FileHandle * file_handle,scoped_refptr<TrackedCallback> callback)79 void PnaclTranslationResourceHost::SendRequestNexeFd(
80 int render_view_id,
81 PP_Instance instance,
82 const nacl::PnaclCacheInfo& cache_info,
83 PP_Bool* is_hit,
84 PP_FileHandle* file_handle,
85 scoped_refptr<TrackedCallback> callback) {
86 DCHECK(io_message_loop_->BelongsToCurrentThread());
87 if (!sender_ || !sender_->Send(new NaClHostMsg_NexeTempFileRequest(
88 render_view_id, instance, cache_info))) {
89 PpapiGlobals::Get()->GetMainThreadMessageLoop()
90 ->PostTask(FROM_HERE,
91 base::Bind(&TrackedCallback::Run,
92 callback,
93 static_cast<int32_t>(PP_ERROR_FAILED)));
94 return;
95 }
96 pending_cache_requests_.insert(std::make_pair(
97 instance, CacheRequestInfo(is_hit, file_handle, callback)));
98 }
99
ReportTranslationFinished(PP_Instance instance,PP_Bool success)100 void PnaclTranslationResourceHost::ReportTranslationFinished(
101 PP_Instance instance,
102 PP_Bool success) {
103 DCHECK(PpapiGlobals::Get()->
104 GetMainThreadMessageLoop()->BelongsToCurrentThread());
105 io_message_loop_->PostTask(
106 FROM_HERE,
107 base::Bind(&PnaclTranslationResourceHost::SendReportTranslationFinished,
108 this,
109 instance,
110 success));
111 return;
112 }
113
SendReportTranslationFinished(PP_Instance instance,PP_Bool success)114 void PnaclTranslationResourceHost::SendReportTranslationFinished(
115 PP_Instance instance,
116 PP_Bool success) {
117 DCHECK(io_message_loop_->BelongsToCurrentThread());
118 // If the sender is closed or we have been detached, we are probably shutting
119 // down, so just don't send anything.
120 if (!sender_)
121 return;
122 DCHECK(pending_cache_requests_.count(instance) == 0);
123 sender_->Send(new NaClHostMsg_ReportTranslationFinished(instance,
124 PP_ToBool(success)));
125 }
126
OnNexeTempFileReply(PP_Instance instance,bool is_hit,IPC::PlatformFileForTransit file)127 void PnaclTranslationResourceHost::OnNexeTempFileReply(
128 PP_Instance instance,
129 bool is_hit,
130 IPC::PlatformFileForTransit file) {
131 DCHECK(io_message_loop_->BelongsToCurrentThread());
132 base::File base_file = IPC::PlatformFileForTransitToFile(file);
133 CacheRequestInfoMap::iterator it = pending_cache_requests_.find(instance);
134 int32_t status = PP_ERROR_FAILED;
135 // Handle the expected successful case first.
136 if (it != pending_cache_requests_.end() && base_file.IsValid() &&
137 TrackedCallback::IsPending(it->second.callback)) {
138 *it->second.is_hit = PP_FromBool(is_hit);
139 *it->second.file_handle = base_file.TakePlatformFile();
140 status = PP_OK;
141 }
142 if (it == pending_cache_requests_.end()) {
143 DLOG(ERROR) << "Could not find pending request for reply";
144 } else {
145 PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostTask(
146 FROM_HERE,
147 base::Bind(&TrackedCallback::Run, it->second.callback, status));
148 pending_cache_requests_.erase(it);
149 }
150 if (!base_file.IsValid()) {
151 DLOG(ERROR) << "Got invalid platformfilefortransit";
152 }
153 }
154
CleanupCacheRequests()155 void PnaclTranslationResourceHost::CleanupCacheRequests() {
156 DCHECK(io_message_loop_->BelongsToCurrentThread());
157 for (CacheRequestInfoMap::iterator it = pending_cache_requests_.begin();
158 it != pending_cache_requests_.end();
159 ++it) {
160 it->second.callback->PostAbort();
161 }
162 pending_cache_requests_.clear();
163 }
164