[engine] force semantics action to post a task. (flutter/engine#56514)

Repro:

Testing WIP.

b/373761573

```dart

import 'package:flutter/material.dart';

void main() {
  runApp(const Example());
}

class Example extends StatefulWidget {
  const Example({super.key});

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  bool value = true;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Semantics(
            child: Text(
              value ? 'Hello, world!' : 'Goodbye, World!',
            ),
            button: true,
            onTap: () async {
              await null;
              setState(() {
                value = !value;
              });
            },
          ),
        ),
      ),
      );
  }
}

```
This commit is contained in:
Jonah Williams 2024-11-12 17:06:05 -08:00 committed by GitHub
parent 655a5d5947
commit d838b4bd03
5 changed files with 62 additions and 2 deletions

View File

@ -4,6 +4,7 @@
// ignore_for_file: avoid_print
import 'dart:async';
import 'dart:convert' show json, utf8;
import 'dart:isolate';
import 'dart:typed_data';
@ -629,3 +630,13 @@ void renderWarmUpView1and2() {
}
});
}
@pragma('vm:entry-point')
void testSemanticsActions() {
PlatformDispatcher.instance.onSemanticsActionEvent = (SemanticsActionEvent action) async {
await null;
Future<void>.value().then((_) {
notifyNative();
});
};
}

View File

@ -1122,8 +1122,7 @@ void Shell::OnPlatformViewDispatchSemanticsAction(int32_t node_id,
FML_DCHECK(is_set_up_);
FML_DCHECK(task_runners_.GetPlatformTaskRunner()->RunsTasksOnCurrentThread());
fml::TaskRunner::RunNowOrPostTask(
task_runners_.GetUITaskRunner(),
task_runners_.GetUITaskRunner()->PostTask(
fml::MakeCopyable([engine = engine_->GetWeakPtr(), node_id, action,
args = std::move(args)]() mutable {
if (engine) {

View File

@ -65,6 +65,14 @@ void ShellTest::SendPlatformMessage(Shell* shell,
shell->OnPlatformViewDispatchPlatformMessage(std::move(message));
}
void ShellTest::SendSemanticsAction(Shell* shell,
int32_t node_id,
SemanticsAction action,
fml::MallocMapping args) {
shell->OnPlatformViewDispatchSemanticsAction(node_id, action,
std::move(args));
}
void ShellTest::SendEnginePlatformMessage(
Shell* shell,
std::unique_ptr<PlatformMessage> message) {

View File

@ -90,6 +90,11 @@ class ShellTest : public FixtureTest {
void SendPlatformMessage(Shell* shell,
std::unique_ptr<PlatformMessage> message);
void SendSemanticsAction(Shell* shell,
int32_t node_id,
SemanticsAction action,
fml::MallocMapping args);
void SendEnginePlatformMessage(Shell* shell,
std::unique_ptr<PlatformMessage> message);

View File

@ -45,8 +45,10 @@
#include "flutter/shell/common/vsync_waiters_test.h"
#include "flutter/shell/version/version.h"
#include "flutter/testing/testing.h"
#include "fml/mapping.h"
#include "gmock/gmock.h"
#include "impeller/core/runtime_types.h"
#include "lib/ui/semantics/semantics_node.h"
#include "third_party/rapidjson/include/rapidjson/writer.h"
#include "third_party/skia/include/codec/SkCodecAnimation.h"
#include "third_party/tonic/converter/dart_converter.h"
@ -4311,6 +4313,41 @@ TEST_F(ShellTest, NavigationMessageDispachedImmediately) {
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, SemanticsActionsPostTask) {
Settings settings = CreateSettingsForFixture();
ThreadHost thread_host("io.flutter.test." + GetCurrentTestName() + ".",
ThreadHost::Type::kPlatform);
auto task_runner = thread_host.platform_thread->GetTaskRunner();
TaskRunners task_runners("test", task_runner, task_runner, task_runner,
task_runner);
EXPECT_EQ(task_runners.GetPlatformTaskRunner(),
task_runners.GetUITaskRunner());
auto shell = CreateShell(settings, task_runners);
auto configuration = RunConfiguration::InferFromSettings(settings);
configuration.SetEntrypoint("testSemanticsActions");
RunEngine(shell.get(), std::move(configuration));
task_runners.GetPlatformTaskRunner()->PostTask([&] {
SendSemanticsAction(shell.get(), 0, SemanticsAction::kTap,
fml::MallocMapping(nullptr, 0));
});
// Fulfill native function for the second Shell's entrypoint.
fml::CountDownLatch latch(1);
AddNativeCallback(
// The Dart native function names aren't very consistent but this is
// just the native function name of the second vm entrypoint in the
// fixture.
"NotifyNative",
CREATE_NATIVE_ENTRY([&](auto args) { latch.CountDown(); }));
latch.Wait();
DestroyShell(std::move(shell), task_runners);
ASSERT_FALSE(DartVMRef::IsInstanceRunning());
}
TEST_F(ShellTest, DiesIfSoftwareRenderingAndImpellerAreEnabledDeathTest) {
#if defined(OS_FUCHSIA)
GTEST_SKIP() << "Fuchsia";