Commit 9b4bddfd authored by Scott Graham's avatar Scott Graham Committed by Commit Bot

Fuchsia: Implement handle passing in FIDL/JS

Bug: 883496
Change-Id: Ia5a0e88ca4a1d41c6be4f81a4dc4cc46b74930a7
Reviewed-on: https://chromium-review.googlesource.com/c/1311082
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#605405}
parent 69d9e273
...@@ -225,6 +225,8 @@ function %(name)s(%(param_names)s) { ...@@ -225,6 +225,8 @@ function %(name)s(%(param_names)s) {
compound = _ParseCompoundIdentifier(t.identifier) compound = _ParseCompoundIdentifier(t.identifier)
name = _CompileCompoundIdentifier(compound) name = _CompileCompoundIdentifier(compound)
return name return name
elif t.kind == fidl.TypeKind.HANDLE:
return 'Handle'
elif t.kind == fidl.TypeKind.VECTOR: elif t.kind == fidl.TypeKind.VECTOR:
element_ttname = self._CompileType(t.element_type) element_ttname = self._CompileType(t.element_type)
ttname = ( ttname = (
...@@ -400,7 +402,7 @@ function %(proxy_name)s() { ...@@ -400,7 +402,7 @@ function %(proxy_name)s() {
var $view = new DataView($readResult.data); var $view = new DataView($readResult.data);
var $decoder = new $fidl_Decoder($view, []); var $decoder = new $fidl_Decoder($view, $readResult.handles);
$decoder.claimMemory(%(size)s - $fidl_kMessageHeaderSize); $decoder.claimMemory(%(size)s - $fidl_kMessageHeaderSize);
''' % {'size': method.maybe_response_size}) ''' % {'size': method.maybe_response_size})
for param, ttname in zip(method.maybe_response, type_tables): for param, ttname in zip(method.maybe_response, type_tables):
......
...@@ -18,6 +18,7 @@ const $fidl__kAlignmentMask = 0x7; ...@@ -18,6 +18,7 @@ const $fidl__kAlignmentMask = 0x7;
const $fidl__kLE = true; const $fidl__kLE = true;
const $fidl__kUserspaceTxidMask = 0x7fffffff; const $fidl__kUserspaceTxidMask = 0x7fffffff;
const $fidl__kHandlePresent = 0xffffffff;
var $fidl__nextTxid = 1; var $fidl__nextTxid = 1;
function $fidl__align(size) { function $fidl__align(size) {
...@@ -78,6 +79,13 @@ $fidl_Encoder.prototype._grow = function(newSize) { ...@@ -78,6 +79,13 @@ $fidl_Encoder.prototype._grow = function(newSize) {
this.data = new DataView(newBuffer); this.data = new DataView(newBuffer);
}; };
/**
* @param {number} handle
*/
$fidl_Encoder.prototype.addHandle = function(handle) {
this.handles.push(handle);
};
$fidl_Encoder.prototype.messageData = function() { $fidl_Encoder.prototype.messageData = function() {
// Add all out of line data. // Add all out of line data.
var len = this.outOfLine.length; var len = this.outOfLine.length;
...@@ -117,6 +125,8 @@ $fidl_Decoder.prototype.claimMemory = function(size) { ...@@ -117,6 +125,8 @@ $fidl_Decoder.prototype.claimMemory = function(size) {
} }
$fidl_Decoder.prototype.claimHandle = function() { $fidl_Decoder.prototype.claimHandle = function() {
if (this.nextHandle >= this.handles.length)
throw "Attempt to claim more handles than are available";
return this.handles[this.nextHandle++]; return this.handles[this.nextHandle++];
} }
...@@ -157,6 +167,27 @@ const _kTT_uint32 = { ...@@ -157,6 +167,27 @@ const _kTT_uint32 = {
dec: function(d, o) { return d.data.getUint32(o, $fidl__kLE); }, dec: function(d, o) { return d.data.getUint32(o, $fidl__kLE); },
}; };
const _kTT_Handle = {
enc: function(e, o, v) {
if (v === null || v === undefined) {
e.data.setUint32(o, 0, $fidl__kLE);
} else {
e.data.setUint32(o, $fidl__kHandlePresent, $fidl__kLE);
e.addHandle(v);
}
},
dec: function(d, o) {
var $present = d.data.getUint32(o, $fidl__kLE);
if ($present === 0) {
return 0;
} else {
if ($present !== $fidl__kHandlePresent)
throw "Expected UINT32_MAX to indicate handle presence";
return d.claimHandle();
}
},
};
const _kTT_String_Nonnull = { const _kTT_String_Nonnull = {
enc: function(e, o, v) { enc: function(e, o, v) {
if (v === null || v === undefined) throw "non-null string required"; if (v === null || v === undefined) throw "non-null string required";
......
...@@ -240,7 +240,6 @@ v8::Local<v8::Object> ZxChannelRead(gin::Arguments* args) { ...@@ -240,7 +240,6 @@ v8::Local<v8::Object> ZxChannelRead(gin::Arguments* args) {
handles.data(), handles.size(), &actual_handles); handles.data(), handles.size(), &actual_handles);
DCHECK_EQ(actual_bytes, data_size); DCHECK_EQ(actual_bytes, data_size);
DCHECK_EQ(actual_handles, num_handles); DCHECK_EQ(actual_handles, num_handles);
CHECK_EQ(actual_handles, 0u) << "Handle passing untested";
if (status != ZX_OK) { if (status != ZX_OK) {
return gin::DataObjectBuilder(args->isolate()) return gin::DataObjectBuilder(args->isolate())
......
...@@ -5,8 +5,11 @@ ...@@ -5,8 +5,11 @@
#include <lib/fidl/cpp/binding.h> #include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/internal/pending_response.h> #include <lib/fidl/cpp/internal/pending_response.h>
#include <lib/fidl/cpp/internal/weak_stub_controller.h> #include <lib/fidl/cpp/internal/weak_stub_controller.h>
#include <lib/zx/log.h>
#include <zircon/syscalls/log.h>
#include "base/bind.h" #include "base/bind.h"
#include "base/fuchsia/fuchsia_logging.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
...@@ -29,6 +32,22 @@ static const char kRuntimeFile[] = ...@@ -29,6 +32,22 @@ static const char kRuntimeFile[] =
static const char kTestBindingFile[] = static const char kTestBindingFile[] =
"/pkg/build/fuchsia/fidlgen_js/fidl/fidljstest/js/fidl.js"; "/pkg/build/fuchsia/fidlgen_js/fidl/fidljstest/js/fidl.js";
namespace {
zx_koid_t GetKoidForHandle(const zx::object_base& object) {
zx_info_handle_basic_t info;
zx_status_t status =
zx_object_get_info(object.get(), ZX_INFO_HANDLE_BASIC, &info,
sizeof(info), nullptr, nullptr);
if (status != ZX_OK) {
ZX_LOG(ERROR, status) << "zx_object_get_info";
return ZX_KOID_INVALID;
}
return info.koid;
}
} // namespace
class FidlGenJsTestShellRunnerDelegate : public gin::ShellRunnerDelegate { class FidlGenJsTestShellRunnerDelegate : public gin::ShellRunnerDelegate {
public: public:
FidlGenJsTestShellRunnerDelegate() {} FidlGenJsTestShellRunnerDelegate() {}
...@@ -190,6 +209,14 @@ class TestolaImpl : public fidljstest::Testola { ...@@ -190,6 +209,14 @@ class TestolaImpl : public fidljstest::Testola {
resp(std::move(sat)); resp(std::move(sat));
} }
void PassHandles(zx::job job, PassHandlesCallback callback) override {
EXPECT_EQ(GetKoidForHandle(job), GetKoidForHandle(*zx::job::default_job()));
zx::log log;
EXPECT_EQ(zx::log::create(ZX_LOG_FLAG_READABLE, &log), ZX_OK);
unowned_log_handle_ = log.get();
callback(std::move(log));
}
bool was_do_something_called() const { return was_do_something_called_; } bool was_do_something_called() const { return was_do_something_called_; }
int32_t received_int() const { return received_int_; } int32_t received_int() const { return received_int_; }
const std::string& received_msg() const { return received_msg_; } const std::string& received_msg() const { return received_msg_; }
...@@ -198,6 +225,8 @@ class TestolaImpl : public fidljstest::Testola { ...@@ -198,6 +225,8 @@ class TestolaImpl : public fidljstest::Testola {
const std::string& various_msg() const { return various_msg_; } const std::string& various_msg() const { return various_msg_; }
const std::vector<uint32_t>& various_stuff() const { return various_stuff_; } const std::vector<uint32_t>& various_stuff() const { return various_stuff_; }
zx_handle_t unowned_log_handle() const { return unowned_log_handle_; }
fidljstest::BasicStruct GetReceivedStruct() const { return basic_struct_; } fidljstest::BasicStruct GetReceivedStruct() const { return basic_struct_; }
void CallResponseCallbacks() { void CallResponseCallbacks() {
...@@ -216,6 +245,7 @@ class TestolaImpl : public fidljstest::Testola { ...@@ -216,6 +245,7 @@ class TestolaImpl : public fidljstest::Testola {
std::vector<uint32_t> various_stuff_; std::vector<uint32_t> various_stuff_;
fidljstest::BasicStruct basic_struct_; fidljstest::BasicStruct basic_struct_;
std::vector<base::OnceClosure> response_callbacks_; std::vector<base::OnceClosure> response_callbacks_;
zx_handle_t unowned_log_handle_;
DISALLOW_COPY_AND_ASSIGN(TestolaImpl); DISALLOW_COPY_AND_ASSIGN(TestolaImpl);
}; };
...@@ -369,7 +399,7 @@ TEST_F(FidlGenJsTest, RawWithResponse) { ...@@ -369,7 +399,7 @@ TEST_F(FidlGenJsTest, RawWithResponse) {
.then(sum => { .then(sum => {
this.sum_result = sum; this.sum_result = sum;
}) })
.catch((e) => log('HOT GARBAGE: ' + e)); .catch((e) => log('FAILED: ' + e));
)"; )";
helper.runner().Run(source, "test.js"); helper.runner().Run(source, "test.js");
...@@ -407,7 +437,7 @@ TEST_F(FidlGenJsTest, NoResponseBeforeTearDown) { ...@@ -407,7 +437,7 @@ TEST_F(FidlGenJsTest, NoResponseBeforeTearDown) {
this.rejected = true; this.rejected = true;
}) })
.catch((e) => { .catch((e) => {
log('HOT GARBAGE: ' + e); log('FAILED: ' + e);
this.excepted = true; this.excepted = true;
}) })
)"; )";
...@@ -484,7 +514,7 @@ TEST_F(FidlGenJsTest, RawReceiveFidlNestedStructsAndRespond) { ...@@ -484,7 +514,7 @@ TEST_F(FidlGenJsTest, RawReceiveFidlNestedStructsAndRespond) {
this.result_basic_u32 = sat.basic.u32; this.result_basic_u32 = sat.basic.u32;
this.result_later_string = sat.later_string; this.result_later_string = sat.later_string;
}) })
.catch((e) => log('HOT GARBAGE: ' + e)); .catch((e) => log('FAILED: ' + e));
)"; )";
helper.runner().Run(source, "test.js"); helper.runner().Run(source, "test.js");
...@@ -509,6 +539,49 @@ TEST_F(FidlGenJsTest, RawReceiveFidlNestedStructsAndRespond) { ...@@ -509,6 +539,49 @@ TEST_F(FidlGenJsTest, RawReceiveFidlNestedStructsAndRespond) {
EXPECT_EQ(helper.Get<std::string>("result_later_string"), "ⓣⓔⓡⓜⓘⓝⓐⓣⓞⓡ"); EXPECT_EQ(helper.Get<std::string>("result_later_string"), "ⓣⓔⓡⓜⓘⓝⓐⓣⓞⓡ");
} }
TEST_F(FidlGenJsTest, HandlePassing) {
v8::Isolate* isolate = instance_->isolate();
BindingsSetupHelper helper(isolate);
TestolaImpl testola_impl;
fidl::Binding<fidljstest::Testola> binding(&testola_impl);
binding.Bind(std::move(helper.server()));
zx::job default_job_copy;
ASSERT_EQ(zx::job::default_job()->duplicate(ZX_RIGHT_SAME_RIGHTS,
&default_job_copy),
ZX_OK);
helper.runner().global()->Set(
gin::StringToSymbol(isolate, "testJobHandle"),
gin::ConvertToV8(isolate, default_job_copy.get()));
// TODO(crbug.com/883496): Handles wrapped in Transferrable once MessagePort
// is sorted out, and then stop treating handles as unmanaged |uint32_t|s.
std::string source = R"(
var proxy = new TestolaProxy();
proxy.$bind(testHandle);
proxy.PassHandles(testJobHandle).then(h => {
this.debuglogHandle = h;
}).catch((e) => log('FAILED: ' + e));
)";
helper.runner().Run(source, "test.js");
// Run the message loop to send the request and receive a response.
base::RunLoop().RunUntilIdle();
zx_handle_t debug_handle_back_from_js =
helper.Get<uint32_t>("debuglogHandle");
EXPECT_EQ(debug_handle_back_from_js, testola_impl.unowned_log_handle());
// Make sure we received the valid handle back correctly, and close it. Not
// stored into a zx::log in case it isn't valid, and to check the return value
// from closing it.
EXPECT_EQ(zx_handle_close(debug_handle_back_from_js), ZX_OK);
// Ensure we didn't pass away our default job.
EXPECT_NE(GetKoidForHandle(*zx::job::default_job()), ZX_KOID_INVALID);
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
base::TestSuite test_suite(argc, argv); base::TestSuite test_suite(argc, argv);
......
...@@ -44,4 +44,6 @@ interface Testola { ...@@ -44,4 +44,6 @@ interface Testola {
6: SendAStruct(BasicStruct basic); 6: SendAStruct(BasicStruct basic);
7: NestedStructsWithResponse(BasicStruct basic) -> (StuffAndThings resp); 7: NestedStructsWithResponse(BasicStruct basic) -> (StuffAndThings resp);
8: PassHandles(handle<job> job) -> (handle<debuglog> debuglog);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment