[Embedder API] Lock nested structs to guarantee ABI (flutter/engine#40069)

[Embedder API] Lock nested structs for ABI stability
This commit is contained in:
Loïc Sharma 2023-03-09 13:09:50 -08:00 committed by GitHub
parent c9d003f7b3
commit 89a738d1b7
3 changed files with 89 additions and 3 deletions

View File

@ -25,12 +25,16 @@
// - Function signatures (names, argument counts, argument order, and argument
// type) cannot change.
// - The core behavior of existing functions cannot change.
// - Instead of nesting structures by value within another structure, prefer
// nesting by pointer. This ensures that adding members to the nested struct
// does not break the ABI of the parent struct.
// - Instead of array of structures, prefer array of pointers to structures.
// This ensures that array indexing does not break if members are added
// to the structure.
//
// These changes are allowed:
// - Adding new struct members at the end of a structure.
// - Adding new struct members at the end of a structure as long as the struct
// is not nested within another struct by value.
// - Adding new enum members with a new value.
// - Renaming a struct member as long as its type, size, and intent remain the
// same.

View File

@ -22,6 +22,47 @@
namespace flutter {
namespace testing {
// New members must not be added to `FlutterTransformation`
// as it would break the ABI of `FlutterSemanticsNode`.
// See: https://github.com/flutter/flutter/issues/121176
typedef struct {
double scaleX;
double skewX;
double transX;
double skewY;
double scaleY;
double transY;
double pers0;
double pers1;
double pers2;
} FrozenFlutterTransformation;
// New members must not be added to `FlutterRect` as it would
// break the ABI of `FlutterSemanticsNode` and `FlutterDamage`.
// See: https://github.com/flutter/flutter/issues/121176
// See: https://github.com/flutter/flutter/issues/121347
typedef struct {
double left;
double top;
double right;
double bottom;
} FrozenFlutterRect;
// New members must not be added to `FlutterPoint` as it would
// break the ABI of `FlutterLayer`.
typedef struct {
double x;
double y;
} FrozenFlutterPoint;
// New members must not be added to `FlutterDamage` as it would
// break the ABI of `FlutterPresentInfo`.
typedef struct {
size_t struct_size;
size_t num_rects;
FrozenFlutterRect* damage;
} FrozenFlutterDamage;
// New members must not be added to `FlutterSemanticsNode`
// as it would break the ABI of `FlutterSemanticsUpdate`.
// See: https://github.com/flutter/flutter/issues/121176
@ -45,8 +86,8 @@ typedef struct {
const char* increased_value;
const char* decreased_value;
FlutterTextDirection text_direction;
FlutterRect rect;
FlutterTransformation transform;
FrozenFlutterRect rect;
FrozenFlutterTransformation transform;
size_t child_count;
const int32_t* children_in_traversal_order;
const int32_t* children_in_hit_test_order;

View File

@ -14,6 +14,47 @@ namespace testing {
#define ASSERT_EQ_OFFSET(type1, type2, member) \
ASSERT_EQ(offsetof(type1, member), offsetof(type2, member))
// New members must not be added to `FlutterTransformation`
// as it would break the ABI of `FlutterSemanticsNode`.
// See: https://github.com/flutter/flutter/issues/121176
TEST(EmbedderFrozen, FlutterTransformationIsFrozen) {
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, scaleX);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, skewX);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, transX);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, skewY);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, scaleY);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, transY);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, pers0);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, pers1);
ASSERT_EQ_OFFSET(FlutterTransformation, FrozenFlutterTransformation, pers2);
}
// New members must not be added to `FlutterRect` as it would
// break the ABI of `FlutterSemanticsNode` and `FlutterDamage`.
// See: https://github.com/flutter/flutter/issues/121176
// See: https://github.com/flutter/flutter/issues/121347
TEST(EmbedderFrozen, FlutterRectIsFrozen) {
ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, left);
ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, top);
ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, right);
ASSERT_EQ_OFFSET(FlutterRect, FrozenFlutterRect, bottom);
}
// New members must not be added to `FlutterPoint` as it would
// break the ABI of `FlutterLayer`.
TEST(EmbedderFrozen, FlutterPointIsFrozen) {
ASSERT_EQ_OFFSET(FlutterPoint, FrozenFlutterPoint, x);
ASSERT_EQ_OFFSET(FlutterPoint, FrozenFlutterPoint, y);
}
// New members must not be added to `FlutterDamage` as it would
// break the ABI of `FlutterPresentInfo`.
TEST(EmbedderFrozen, FlutterDamageIsFrozen) {
ASSERT_EQ_OFFSET(FlutterDamage, FrozenFlutterDamage, struct_size);
ASSERT_EQ_OFFSET(FlutterDamage, FrozenFlutterDamage, num_rects);
ASSERT_EQ_OFFSET(FlutterDamage, FrozenFlutterDamage, damage);
}
// New members must not be added to `FlutterSemanticsNode`
// as it would break the ABI of `FlutterSemanticsUpdate`.
// See: https://github.com/flutter/flutter/issues/121176