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) {
compound = _ParseCompoundIdentifier(t.identifier)
name = _CompileCompoundIdentifier(compound)
return name
elif t.kind == fidl.TypeKind.HANDLE:
return 'Handle'
elif t.kind == fidl.TypeKind.VECTOR:
element_ttname = self._CompileType(t.element_type)
ttname = (
......@@ -400,7 +402,7 @@ function %(proxy_name)s() {
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);
''' % {'size': method.maybe_response_size})
for param, ttname in zip(method.maybe_response, type_tables):
......
......@@ -18,6 +18,7 @@ const $fidl__kAlignmentMask = 0x7;
const $fidl__kLE = true;
const $fidl__kUserspaceTxidMask = 0x7fffffff;
const $fidl__kHandlePresent = 0xffffffff;
var $fidl__nextTxid = 1;
function $fidl__align(size) {
......@@ -78,6 +79,13 @@ $fidl_Encoder.prototype._grow = function(newSize) {
this.data = new DataView(newBuffer);
};
/**
* @param {number} handle
*/
$fidl_Encoder.prototype.addHandle = function(handle) {
this.handles.push(handle);
};
$fidl_Encoder.prototype.messageData = function() {
// Add all out of line data.
var len = this.outOfLine.length;
......@@ -117,6 +125,8 @@ $fidl_Decoder.prototype.claimMemory = function(size) {
}
$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++];
}
......@@ -157,6 +167,27 @@ const _kTT_uint32 = {
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 = {
enc: function(e, o, v) {
if (v === null || v === undefined) throw "non-null string required";
......
......@@ -240,7 +240,6 @@ v8::Local<v8::Object> ZxChannelRead(gin::Arguments* args) {
handles.data(), handles.size(), &actual_handles);
DCHECK_EQ(actual_bytes, data_size);
DCHECK_EQ(actual_handles, num_handles);
CHECK_EQ(actual_handles, 0u) << "Handle passing untested";
if (status != ZX_OK) {
return gin::DataObjectBuilder(args->isolate())
......
......@@ -5,8 +5,11 @@
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/internal/pending_response.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/fuchsia/fuchsia_logging.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
......@@ -29,6 +32,22 @@ static const char kRuntimeFile[] =
static const char kTestBindingFile[] =
"/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 {
public:
FidlGenJsTestShellRunnerDelegate() {}
......@@ -190,6 +209,14 @@ class TestolaImpl : public fidljstest::Testola {
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_; }
int32_t received_int() const { return received_int_; }
const std::string& received_msg() const { return received_msg_; }
......@@ -198,6 +225,8 @@ class TestolaImpl : public fidljstest::Testola {
const std::string& various_msg() const { return various_msg_; }
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_; }
void CallResponseCallbacks() {
......@@ -216,6 +245,7 @@ class TestolaImpl : public fidljstest::Testola {
std::vector<uint32_t> various_stuff_;
fidljstest::BasicStruct basic_struct_;
std::vector<base::OnceClosure> response_callbacks_;
zx_handle_t unowned_log_handle_;
DISALLOW_COPY_AND_ASSIGN(TestolaImpl);
};
......@@ -369,7 +399,7 @@ TEST_F(FidlGenJsTest, RawWithResponse) {
.then(sum => {
this.sum_result = sum;
})
.catch((e) => log('HOT GARBAGE: ' + e));
.catch((e) => log('FAILED: ' + e));
)";
helper.runner().Run(source, "test.js");
......@@ -407,7 +437,7 @@ TEST_F(FidlGenJsTest, NoResponseBeforeTearDown) {
this.rejected = true;
})
.catch((e) => {
log('HOT GARBAGE: ' + e);
log('FAILED: ' + e);
this.excepted = true;
})
)";
......@@ -484,7 +514,7 @@ TEST_F(FidlGenJsTest, RawReceiveFidlNestedStructsAndRespond) {
this.result_basic_u32 = sat.basic.u32;
this.result_later_string = sat.later_string;
})
.catch((e) => log('HOT GARBAGE: ' + e));
.catch((e) => log('FAILED: ' + e));
)";
helper.runner().Run(source, "test.js");
......@@ -509,6 +539,49 @@ TEST_F(FidlGenJsTest, RawReceiveFidlNestedStructsAndRespond) {
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) {
base::TestSuite test_suite(argc, argv);
......
......@@ -44,4 +44,6 @@ interface Testola {
6: SendAStruct(BasicStruct basic);
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