Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
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
17 changes: 17 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -1173,18 +1173,35 @@ FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.cc
FILE: ../../../flutter/shell/platform/glfw/text_input_plugin.h
FILE: ../../../flutter/shell/platform/linux/fl_binary_messenger.cc
FILE: ../../../flutter/shell/platform/linux/fl_binary_messenger_private.h
FILE: ../../../flutter/shell/platform/linux/fl_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_dart_project.cc
FILE: ../../../flutter/shell/platform/linux/fl_dart_project_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_engine.cc
FILE: ../../../flutter/shell/platform/linux/fl_engine_private.h
FILE: ../../../flutter/shell/platform/linux/fl_method_channel.cc
FILE: ../../../flutter/shell/platform/linux/fl_method_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_method_codec_private.h
FILE: ../../../flutter/shell/platform/linux/fl_method_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer.h
FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.cc
FILE: ../../../flutter/shell/platform/linux/fl_renderer_x11.h
FILE: ../../../flutter/shell/platform/linux/fl_standard_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_standard_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec.cc
FILE: ../../../flutter/shell/platform/linux/fl_standard_method_codec_test.cc
FILE: ../../../flutter/shell/platform/linux/fl_value.cc
FILE: ../../../flutter/shell/platform/linux/fl_view.cc
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_binary_messenger.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_dart_project.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_engine.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_channel.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_method_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_standard_method_codec.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_value.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/fl_view.h
FILE: ../../../flutter/shell/platform/linux/public/flutter_linux/flutter_linux.h
FILE: ../../../flutter/shell/platform/windows/angle_surface_manager.cc
Expand Down
16 changes: 16 additions & 0 deletions shell/platform/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ if (build_glfw_shell) {
_public_headers = [
"public/flutter_linux/fl_binary_messenger.h",
"public/flutter_linux/fl_dart_project.h",
"public/flutter_linux/fl_codec.h",
"public/flutter_linux/fl_engine.h",
"public/flutter_linux/fl_method_channel.h",
"public/flutter_linux/fl_method_codec.h",
"public/flutter_linux/fl_standard_codec.h",
"public/flutter_linux/fl_standard_method_codec.h",
"public/flutter_linux/fl_value.h",
"public/flutter_linux/fl_view.h",
"public/flutter_linux/flutter_linux.h",
]
Expand All @@ -60,10 +66,16 @@ source_set("flutter_linux") {

sources = [
"fl_binary_messenger.cc",
"fl_codec.cc",
"fl_dart_project.cc",
"fl_engine.cc",
"fl_method_channel.cc",
"fl_method_codec.cc",
"fl_renderer.cc",
"fl_renderer_x11.cc",
"fl_standard_codec.cc",
"fl_standard_method_codec.cc",
"fl_value.cc",
"fl_view.cc",
]

Expand All @@ -89,7 +101,11 @@ executable("flutter_linux_unittests") {
testonly = true

sources = [
"fl_codec_test.cc",
"fl_dart_project_test.cc",
"fl_method_codec_test.cc",
"fl_standard_codec_test.cc",
"fl_standard_method_codec_test.cc",
]

public_configs = [ "//flutter:config" ]
Expand Down
21 changes: 13 additions & 8 deletions shell/platform/linux/fl_binary_messenger.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,6 @@ struct _FlBinaryMessengerResponseHandle {
const FlutterPlatformMessageResponseHandle* response_handle;
};

static void engine_weak_notify_cb(gpointer user_data, GObject* object) {
FlBinaryMessenger* self = FL_BINARY_MESSENGER(user_data);
self->engine = nullptr;
}

static FlBinaryMessengerResponseHandle* response_handle_new(
const FlutterPlatformMessageResponseHandle* response_handle) {
FlBinaryMessengerResponseHandle* handle =
Expand All @@ -64,6 +59,14 @@ static void response_handle_free(FlBinaryMessengerResponseHandle* handle) {
g_free(handle);
}

G_DEFINE_AUTOPTR_CLEANUP_FUNC(FlBinaryMessengerResponseHandle,
response_handle_free);

static void engine_weak_notify_cb(gpointer user_data, GObject* object) {
FlBinaryMessenger* self = FL_BINARY_MESSENGER(user_data);
self->engine = nullptr;
}

static gboolean fl_binary_messenger_platform_message_callback(
FlEngine* engine,
const gchar* channel,
Expand Down Expand Up @@ -139,18 +142,20 @@ G_MODULE_EXPORT void fl_binary_messenger_set_message_handler_on_channel(

G_MODULE_EXPORT gboolean fl_binary_messenger_send_response(
FlBinaryMessenger* self,
FlBinaryMessengerResponseHandle* response_handle,
FlBinaryMessengerResponseHandle* response_handle_,
GBytes* response,
GError** error) {
g_return_val_if_fail(FL_IS_BINARY_MESSENGER(self), FALSE);
g_return_val_if_fail(response_handle != nullptr, FALSE);
g_return_val_if_fail(response_handle_ != nullptr, FALSE);

// Take reference to ensure it is freed
g_autoptr(FlBinaryMessengerResponseHandle) response_handle = response_handle_;

if (self->engine == nullptr)
return TRUE;

gboolean result = fl_engine_send_platform_message_response(
self->engine, response_handle->response_handle, response, error);
response_handle_free(response_handle);

return result;
}
Expand Down
53 changes: 53 additions & 0 deletions shell/platform/linux/fl_codec.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2013 The Flutter 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 "flutter/shell/platform/linux/public/flutter_linux/fl_codec.h"

#include <gmodule.h>

G_DEFINE_QUARK(fl_codec_error_quark, fl_codec_error)

// Added here to stop the compiler from optimising this function away
G_MODULE_EXPORT GType fl_codec_get_type();

G_DEFINE_TYPE(FlCodec, fl_codec, G_TYPE_OBJECT)

static void fl_codec_class_init(FlCodecClass* klass) {}

static void fl_codec_init(FlCodec* self) {}

G_MODULE_EXPORT gboolean fl_codec_write_value(FlCodec* self,
GByteArray* buffer,
FlValue* value,
GError** error) {
g_return_val_if_fail(FL_IS_CODEC(self), FALSE);
g_return_val_if_fail(buffer != nullptr, FALSE);

g_autoptr(FlValue) null_value = NULL;
if (value == nullptr)
value = null_value = fl_value_null_new();

return FL_CODEC_GET_CLASS(self)->write_value(self, buffer, value, error);
}

G_MODULE_EXPORT FlValue* fl_codec_read_value(FlCodec* self,
GBytes* buffer,
size_t* offset,
GError** error) {
g_return_val_if_fail(FL_IS_CODEC(self), nullptr);
g_return_val_if_fail(buffer != nullptr, nullptr);

size_t o = offset != nullptr ? *offset : 0;
if (o >= g_bytes_get_size(buffer)) {
g_set_error(error, FL_CODEC_ERROR, FL_CODEC_ERROR_OUT_OF_DATA,
"Out of data");
return NULL;
}

FlValue* value =
FL_CODEC_GET_CLASS(self)->read_value(self, buffer, &o, error);
if (value != nullptr && offset != nullptr)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If offset is an i/o param, why is it valid for it to be null? It seems like this should just be an assertion at the start of the method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using it as an optional in/out param, i.e. NULL is "start at zero and I don't care what the result is". It could be asserted though, I wasn't 100% sure which way to go on this. I do find it annoying in APIs when you have to provide something like this and you don't care.

This has been refactored though with the FlMessageCodec changes, so it may not be signficant anymore. I'll keep it in mind and we can bring up again if it remains in a a later PR.

*offset = o;
return value;
}
186 changes: 186 additions & 0 deletions shell/platform/linux/fl_codec_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// Copyright 2013 The Flutter 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 "flutter/shell/platform/linux/public/flutter_linux/fl_codec.h"
#include "gtest/gtest.h"

G_DECLARE_FINAL_TYPE(FlTestCodec, fl_test_codec, FL, TEST_CODEC, FlCodec)

struct _FlTestCodec {
FlCodec parent_instance;
};

G_DEFINE_TYPE(FlTestCodec, fl_test_codec, fl_codec_get_type())

static gboolean fl_test_codec_write_value(FlCodec* codec,
GByteArray* buffer,
FlValue* value,
GError** error) {
EXPECT_TRUE(FL_IS_TEST_CODEC(codec));

if (fl_value_get_type(value) == FL_VALUE_TYPE_INT) {
char c = '0' + fl_value_get_int(value);
g_byte_array_append(buffer, reinterpret_cast<const guint8*>(&c), 1);
return TRUE;
} else {
g_set_error(error, FL_CODEC_ERROR, FL_CODEC_ERROR_FAILED, "ERROR");
return FALSE;
}
}

static FlValue* fl_test_codec_read_value(FlCodec* codec,
GBytes* message,
size_t* offset,
GError** error) {
EXPECT_TRUE(FL_IS_TEST_CODEC(codec));
EXPECT_TRUE(*offset < g_bytes_get_size(message));

size_t data_length;
const uint8_t* data =
static_cast<const uint8_t*>(g_bytes_get_data(message, &data_length));
if (data_length == 0) {
g_set_error(error, FL_CODEC_ERROR, FL_CODEC_ERROR_FAILED, "ERROR");
return FALSE;
}

g_autoptr(FlValue) value = fl_value_int_new(data[*offset] - '0');
(*offset)++;
return fl_value_ref(value);
}

static void fl_test_codec_class_init(FlTestCodecClass* klass) {
FL_CODEC_CLASS(klass)->write_value = fl_test_codec_write_value;
FL_CODEC_CLASS(klass)->read_value = fl_test_codec_read_value;
}

static void fl_test_codec_init(FlTestCodec* self) {}

static FlTestCodec* fl_test_codec_new() {
return FL_TEST_CODEC(g_object_new(fl_test_codec_get_type(), nullptr));
}

TEST(FlCodecTest, WriteValue) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
g_autoptr(GByteArray) buffer = g_byte_array_new();

g_autoptr(FlValue) value = fl_value_int_new(1);
g_autoptr(GError) error = nullptr;
gboolean result =
fl_codec_write_value(FL_CODEC(codec), buffer, value, &error);
EXPECT_TRUE(result);
EXPECT_EQ(error, nullptr);
EXPECT_EQ(buffer->len, static_cast<unsigned int>(1));
EXPECT_EQ(buffer->data[0], '1');
}

TEST(FlCodecTest, WriteValues) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
g_autoptr(GByteArray) buffer = g_byte_array_new();

for (int i = 1; i <= 5; i++) {
g_autoptr(FlValue) value = fl_value_int_new(i);
g_autoptr(GError) error = nullptr;
gboolean result =
fl_codec_write_value(FL_CODEC(codec), buffer, value, &error);
EXPECT_TRUE(result);
EXPECT_EQ(error, nullptr);
}

EXPECT_EQ(buffer->len, static_cast<unsigned int>(5));
for (int i = 1; i <= 5; i++)
EXPECT_EQ(buffer->data[i - 1], '0' + i);
}

TEST(FlCodecTest, WriteValueError) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
g_autoptr(GByteArray) buffer = g_byte_array_new();

g_autoptr(FlValue) value = fl_value_null_new();
g_autoptr(GError) error = nullptr;
gboolean result =
fl_codec_write_value(FL_CODEC(codec), buffer, value, &error);
EXPECT_FALSE(result);
EXPECT_TRUE(g_error_matches(error, FL_CODEC_ERROR, FL_CODEC_ERROR_FAILED));
EXPECT_EQ(buffer->len, static_cast<unsigned int>(0));
}

TEST(FlCodecTest, ReadValueEmpty) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
g_autoptr(GBytes) message = g_bytes_new(nullptr, 0);

size_t offset = 0;
g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) value =
fl_codec_read_value(FL_CODEC(codec), message, &offset, &error);
EXPECT_EQ(value, nullptr);
EXPECT_TRUE(
g_error_matches(error, FL_CODEC_ERROR, FL_CODEC_ERROR_OUT_OF_DATA));
EXPECT_EQ(offset, static_cast<size_t>(0));
}

TEST(FlCodecTest, ReadValue) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
uint8_t data[] = {'1'};
g_autoptr(GBytes) message = g_bytes_new(data, 1);

size_t offset = 0;
g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) value =
fl_codec_read_value(FL_CODEC(codec), message, &offset, &error);
EXPECT_NE(value, nullptr);
EXPECT_EQ(error, nullptr);
EXPECT_EQ(offset, static_cast<size_t>(1));

ASSERT_TRUE(fl_value_get_type(value) == FL_VALUE_TYPE_INT);
EXPECT_EQ(fl_value_get_int(value), 1);
}

TEST(FlCodecTest, ReadValues) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
uint8_t data[] = {'1', '2', '3', '4', '5'};
g_autoptr(GBytes) message = g_bytes_new(data, 5);

size_t offset = 0;
for (int i = 1; i <= 5; i++) {
g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) value =
fl_codec_read_value(FL_CODEC(codec), message, &offset, &error);
EXPECT_NE(value, nullptr);
EXPECT_EQ(error, nullptr);
ASSERT_TRUE(fl_value_get_type(value) == FL_VALUE_TYPE_INT);
EXPECT_EQ(fl_value_get_int(value), i);
}

EXPECT_EQ(offset, static_cast<size_t>(5));
}

TEST(FlCodecTest, ReadValueNullOffset) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
uint8_t data[] = {'1'};
g_autoptr(GBytes) message = g_bytes_new(data, 1);

g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) value =
fl_codec_read_value(FL_CODEC(codec), message, NULL, &error);
EXPECT_NE(value, nullptr);
EXPECT_EQ(error, nullptr);

ASSERT_TRUE(fl_value_get_type(value) == FL_VALUE_TYPE_INT);
EXPECT_EQ(fl_value_get_int(value), 1);
}

TEST(FlCodecTest, ReadValueInvalidOffset) {
g_autoptr(FlTestCodec) codec = fl_test_codec_new();
uint8_t data[] = {'1', '2', '3', '4', '5'};
g_autoptr(GBytes) message = g_bytes_new(data, 5);

size_t offset = 9999;
g_autoptr(GError) error = nullptr;
g_autoptr(FlValue) value =
fl_codec_read_value(FL_CODEC(codec), message, &offset, &error);
EXPECT_EQ(value, nullptr);
EXPECT_TRUE(
g_error_matches(error, FL_CODEC_ERROR, FL_CODEC_ERROR_OUT_OF_DATA));
EXPECT_EQ(offset, static_cast<size_t>(9999));
}
Loading