Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 76 additions & 23 deletions shell/platform/linux/fl_standard_method_codec.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,52 @@ static constexpr guint8 kEnvelopeTypeError = 1;
struct _FlStandardMethodCodec {
FlMethodCodec parent_instance;

FlStandardMessageCodec* codec;
FlStandardMessageCodec* message_codec;
};

enum { kPropMessageCodec = 1, kPropLast };

G_DEFINE_TYPE(FlStandardMethodCodec,
fl_standard_method_codec,
fl_method_codec_get_type())

static void fl_standard_method_codec_set_property(GObject* object,
guint prop_id,
const GValue* value,
GParamSpec* pspec) {
FlStandardMethodCodec* self = FL_STANDARD_METHOD_CODEC(object);

switch (prop_id) {
case kPropMessageCodec:
g_set_object(&self->message_codec,
FL_STANDARD_MESSAGE_CODEC(g_value_get_object(value)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}

static void fl_standard_method_codec_get_property(GObject* object,
guint prop_id,
GValue* value,
GParamSpec* pspec) {
FlStandardMethodCodec* self = FL_STANDARD_METHOD_CODEC(object);

switch (prop_id) {
case kPropMessageCodec:
g_value_set_object(value, self->message_codec);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
break;
}
}

static void fl_standard_method_codec_dispose(GObject* object) {
FlStandardMethodCodec* self = FL_STANDARD_METHOD_CODEC(object);

g_clear_object(&self->codec);
g_clear_object(&self->message_codec);

G_OBJECT_CLASS(fl_standard_method_codec_parent_class)->dispose(object);
}
Expand All @@ -42,11 +77,11 @@ static GBytes* fl_standard_method_codec_encode_method_call(FlMethodCodec* codec,

g_autoptr(GByteArray) buffer = g_byte_array_new();
g_autoptr(FlValue) name_value = fl_value_new_string(name);
if (!fl_standard_message_codec_write_value(self->codec, buffer, name_value,
error)) {
if (!fl_standard_message_codec_write_value(self->message_codec, buffer,
name_value, error)) {
return nullptr;
}
if (!fl_standard_message_codec_write_value(self->codec, buffer, args,
if (!fl_standard_message_codec_write_value(self->message_codec, buffer, args,
error)) {
return nullptr;
}
Expand All @@ -66,7 +101,7 @@ static gboolean fl_standard_method_codec_decode_method_call(

size_t offset = 0;
g_autoptr(FlValue) name_value = fl_standard_message_codec_read_value(
self->codec, message, &offset, error);
self->message_codec, message, &offset, error);
if (name_value == nullptr) {
return FALSE;
}
Expand All @@ -77,7 +112,7 @@ static gboolean fl_standard_method_codec_decode_method_call(
}

g_autoptr(FlValue) args_value = fl_standard_message_codec_read_value(
self->codec, message, &offset, error);
self->message_codec, message, &offset, error);
if (args_value == nullptr) {
return FALSE;
}
Expand All @@ -104,8 +139,8 @@ static GBytes* fl_standard_method_codec_encode_success_envelope(
g_autoptr(GByteArray) buffer = g_byte_array_new();
guint8 type = kEnvelopeTypeSuccess;
g_byte_array_append(buffer, &type, 1);
if (!fl_standard_message_codec_write_value(self->codec, buffer, result,
error)) {
if (!fl_standard_message_codec_write_value(self->message_codec, buffer,
result, error)) {
return nullptr;
}

Expand All @@ -126,18 +161,18 @@ static GBytes* fl_standard_method_codec_encode_error_envelope(
guint8 type = kEnvelopeTypeError;
g_byte_array_append(buffer, &type, 1);
g_autoptr(FlValue) code_value = fl_value_new_string(code);
if (!fl_standard_message_codec_write_value(self->codec, buffer, code_value,
error)) {
if (!fl_standard_message_codec_write_value(self->message_codec, buffer,
code_value, error)) {
return nullptr;
}
g_autoptr(FlValue) message_value =
message != nullptr ? fl_value_new_string(message) : nullptr;
if (!fl_standard_message_codec_write_value(self->codec, buffer, message_value,
error)) {
if (!fl_standard_message_codec_write_value(self->message_codec, buffer,
message_value, error)) {
return nullptr;
}
if (!fl_standard_message_codec_write_value(self->codec, buffer, details,
error)) {
if (!fl_standard_message_codec_write_value(self->message_codec, buffer,
details, error)) {
return nullptr;
}

Expand Down Expand Up @@ -167,7 +202,7 @@ static FlMethodResponse* fl_standard_method_codec_decode_response(
g_autoptr(FlMethodResponse) response = nullptr;
if (type == kEnvelopeTypeError) {
g_autoptr(FlValue) code = fl_standard_message_codec_read_value(
self->codec, message, &offset, error);
self->message_codec, message, &offset, error);
if (code == nullptr) {
return nullptr;
}
Expand All @@ -178,7 +213,7 @@ static FlMethodResponse* fl_standard_method_codec_decode_response(
}

g_autoptr(FlValue) error_message = fl_standard_message_codec_read_value(
self->codec, message, &offset, error);
self->message_codec, message, &offset, error);
if (error_message == nullptr) {
return nullptr;
}
Expand All @@ -190,7 +225,7 @@ static FlMethodResponse* fl_standard_method_codec_decode_response(
}

g_autoptr(FlValue) details = fl_standard_message_codec_read_value(
self->codec, message, &offset, error);
self->message_codec, message, &offset, error);
if (details == nullptr) {
return nullptr;
}
Expand All @@ -203,7 +238,7 @@ static FlMethodResponse* fl_standard_method_codec_decode_response(
fl_value_get_type(details) != FL_VALUE_TYPE_NULL ? details : nullptr));
} else if (type == kEnvelopeTypeSuccess) {
g_autoptr(FlValue) result = fl_standard_message_codec_read_value(
self->codec, message, &offset, error);
self->message_codec, message, &offset, error);

if (result == nullptr) {
return nullptr;
Expand All @@ -227,7 +262,10 @@ static FlMethodResponse* fl_standard_method_codec_decode_response(

static void fl_standard_method_codec_class_init(
FlStandardMethodCodecClass* klass) {
G_OBJECT_CLASS(klass)->set_property = fl_standard_method_codec_set_property;
G_OBJECT_CLASS(klass)->get_property = fl_standard_method_codec_get_property;
G_OBJECT_CLASS(klass)->dispose = fl_standard_method_codec_dispose;

FL_METHOD_CODEC_CLASS(klass)->encode_method_call =
fl_standard_method_codec_encode_method_call;
FL_METHOD_CODEC_CLASS(klass)->decode_method_call =
Expand All @@ -238,13 +276,28 @@ static void fl_standard_method_codec_class_init(
fl_standard_method_codec_encode_error_envelope;
FL_METHOD_CODEC_CLASS(klass)->decode_response =
fl_standard_method_codec_decode_response;
}

static void fl_standard_method_codec_init(FlStandardMethodCodec* self) {
self->codec = fl_standard_message_codec_new();
g_object_class_install_property(
G_OBJECT_CLASS(klass), kPropMessageCodec,
g_param_spec_object(
"message-codec", "message-codec", "Message codec to use",
fl_message_codec_get_type(),
static_cast<GParamFlags>(G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS)));
}

static void fl_standard_method_codec_init(FlStandardMethodCodec* self) {}

G_MODULE_EXPORT FlStandardMethodCodec* fl_standard_method_codec_new() {
g_autoptr(FlStandardMessageCodec) message_codec =
fl_standard_message_codec_new();
return fl_standard_method_codec_new_with_message_codec(message_codec);
}

G_MODULE_EXPORT FlStandardMethodCodec*
fl_standard_method_codec_new_with_message_codec(
FlStandardMessageCodec* message_codec) {
return FL_STANDARD_METHOD_CODEC(
g_object_new(fl_standard_method_codec_get_type(), nullptr));
g_object_new(fl_standard_method_codec_get_type(), "message-codec",
message_codec, nullptr));
}
132 changes: 132 additions & 0 deletions shell/platform/linux/fl_standard_method_codec_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,112 @@
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h"
#include "flutter/shell/platform/linux/fl_method_codec_private.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_message_codec.h"
#include "flutter/shell/platform/linux/public/flutter_linux/fl_standard_message_codec.h"
#include "flutter/shell/platform/linux/testing/fl_test.h"
#include "gtest/gtest.h"

G_DECLARE_FINAL_TYPE(FlTestMethodMessageCodec,
fl_test_method_message_codec,
FL,
TEST_METHOD_MESSAGE_CODEC,
FlStandardMessageCodec)

struct _FlTestMethodMessageCodec {
FlStandardMessageCodec parent_instance;
};

G_DEFINE_TYPE(FlTestMethodMessageCodec,
fl_test_method_message_codec,
fl_standard_message_codec_get_type())

static gboolean write_custom_value(FlStandardMessageCodec* codec,
GByteArray* buffer,
FlValue* value,
GError** error) {
const gchar* text =
static_cast<const gchar*>(fl_value_get_custom_value(value));
size_t length = strlen(text);

uint8_t type = 128;
g_byte_array_append(buffer, &type, sizeof(uint8_t));
fl_standard_message_codec_write_size(codec, buffer, length);
g_byte_array_append(buffer, reinterpret_cast<const uint8_t*>(text), length);
return TRUE;
}

static gboolean fl_test_method_message_codec_write_value(
FlStandardMessageCodec* codec,
GByteArray* buffer,
FlValue* value,
GError** error) {
if (fl_value_get_type(value) == FL_VALUE_TYPE_CUSTOM &&
fl_value_get_custom_type(value) == 128) {
return write_custom_value(codec, buffer, value, error);
} else {
return FL_STANDARD_MESSAGE_CODEC_CLASS(
fl_test_method_message_codec_parent_class)
->write_value(codec, buffer, value, error);
}
}

static FlValue* read_custom_value(FlStandardMessageCodec* codec,
GBytes* buffer,
size_t* offset,
GError** error) {
uint32_t length;
if (!fl_standard_message_codec_read_size(codec, buffer, offset, &length,
error)) {
return nullptr;
}
if (*offset + length > g_bytes_get_size(buffer)) {
g_set_error(error, FL_MESSAGE_CODEC_ERROR,
FL_MESSAGE_CODEC_ERROR_OUT_OF_DATA, "Unexpected end of data");
return nullptr;
}
FlValue* value = fl_value_new_custom(
128,
g_strndup(static_cast<const gchar*>(g_bytes_get_data(buffer, nullptr)) +
*offset,
length),
g_free);
*offset += length;

return value;
}

static FlValue* fl_test_method_message_codec_read_value_of_type(
FlStandardMessageCodec* codec,
GBytes* buffer,
size_t* offset,
int type,
GError** error) {
if (type == 128) {
return read_custom_value(codec, buffer, offset, error);
} else {
return FL_STANDARD_MESSAGE_CODEC_CLASS(
fl_test_method_message_codec_parent_class)
->read_value_of_type(codec, buffer, offset, type, error);
}
}

static void fl_test_method_message_codec_class_init(
FlTestMethodMessageCodecClass* klass) {
FL_STANDARD_MESSAGE_CODEC_CLASS(klass)->write_value =
fl_test_method_message_codec_write_value;
FL_STANDARD_MESSAGE_CODEC_CLASS(klass)->read_value_of_type =
fl_test_method_message_codec_read_value_of_type;
}

static void fl_test_method_message_codec_init(FlTestMethodMessageCodec* self) {
// The following line suppresses a warning for unused function
FL_IS_TEST_METHOD_MESSAGE_CODEC(self);
}

static FlTestMethodMessageCodec* fl_test_method_message_codec_new() {
return FL_TEST_METHOD_MESSAGE_CODEC(
g_object_new(fl_test_method_message_codec_get_type(), nullptr));
}

// NOTE(robert-ancell) These test cases assumes a little-endian architecture.
// These tests will need to be updated if tested on a big endian architecture.

Expand Down Expand Up @@ -375,3 +478,32 @@ TEST(FlStandardMethodCodecTest, DecodeResponseUnknownEnvelope) {
decode_error_response("02", FL_MESSAGE_CODEC_ERROR,
FL_MESSAGE_CODEC_ERROR_FAILED);
}

TEST(FlStandardMethodCodecTest, CustomMessageCodec) {
g_autoptr(FlTestMethodMessageCodec) message_codec =
fl_test_method_message_codec_new();
g_autoptr(FlStandardMethodCodec) codec =
fl_standard_method_codec_new_with_message_codec(
FL_STANDARD_MESSAGE_CODEC(message_codec));

g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) value = fl_value_new_custom(128, "hello", nullptr);
g_autoptr(GBytes) message = fl_method_codec_encode_success_envelope(
FL_METHOD_CODEC(codec), value, &error);
EXPECT_NE(message, nullptr);
EXPECT_EQ(error, nullptr);
g_autofree gchar* hex_string = bytes_to_hex_string(message);
EXPECT_STREQ(hex_string, "00800568656c6c6f");

g_autoptr(FlMethodResponse) response =
fl_method_codec_decode_response(FL_METHOD_CODEC(codec), message, &error);
EXPECT_NE(response, nullptr);
EXPECT_EQ(error, nullptr);
EXPECT_TRUE(FL_IS_METHOD_SUCCESS_RESPONSE(response));
FlValue* result = fl_method_success_response_get_result(
FL_METHOD_SUCCESS_RESPONSE(response));
ASSERT_EQ(fl_value_get_type(result), FL_VALUE_TYPE_CUSTOM);
ASSERT_EQ(fl_value_get_custom_type(result), 128);
EXPECT_STREQ(static_cast<const gchar*>(fl_value_get_custom_value(result)),
"hello");
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <gmodule.h>

#include "fl_method_codec.h"
#include "fl_standard_message_codec.h"

G_BEGIN_DECLS

Expand Down Expand Up @@ -42,6 +43,17 @@ G_DECLARE_FINAL_TYPE(FlStandardMethodCodec,
*/
FlStandardMethodCodec* fl_standard_method_codec_new();

/**
* fl_standard_method_codec_new:
* @message_codec: A #FlMessageCodec.
*
* Creates an #FlStandardMethodCodec with a custom message codec.
*
* Returns: a new #FlStandardMethodCodec.
*/
FlStandardMethodCodec* fl_standard_method_codec_new_with_message_codec(
FlStandardMessageCodec* message_codec);

G_END_DECLS

#endif // FLUTTER_SHELL_PLATFORM_LINUX_PUBLIC_FLUTTER_LINUX_FL_STANDARD_METHOD_CODEC_H_