Terminate the application when the UI thread is dead. Close #343

This commit is contained in:
2025-04-24 16:44:51 +08:00
parent 17e2696ca4
commit f38129133a
2 changed files with 43 additions and 0 deletions

View File

@@ -1,4 +1,7 @@
import 'dart:async';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_saf/flutter_saf.dart'; import 'package:flutter_saf/flutter_saf.dart';
import 'package:rhttp/rhttp.dart'; import 'package:rhttp/rhttp.dart';
import 'package:venera/foundation/app.dart'; import 'package:venera/foundation/app.dart';
@@ -51,6 +54,14 @@ Future<void> init() async {
FlutterError.onError = (details) { FlutterError.onError = (details) {
Log.error("Unhandled Exception", "${details.exception}\n${details.stack}"); Log.error("Unhandled Exception", "${details.exception}\n${details.stack}");
}; };
if (App.isWindows) {
// Report to the monitor thread that the app is running
// https://github.com/venera-app/venera/issues/343
Timer.periodic(const Duration(seconds: 1), (_) {
const methodChannel = MethodChannel('venera/method_channel');
methodChannel.invokeMethod("heartBeat");
});
}
} }
void _checkOldConfigs() { void _checkOldConfigs() {

View File

@@ -10,11 +10,16 @@
#include <flutter/event_stream_handler_functions.h> #include <flutter/event_stream_handler_functions.h>
#include <flutter/standard_method_codec.h> #include <flutter/standard_method_codec.h>
#include "flutter/generated_plugin_registrant.h" #include "flutter/generated_plugin_registrant.h"
#include <thread>
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
std::unique_ptr<flutter::EventSink<flutter::EncodableValue>>&& mouseEvents = nullptr; std::unique_ptr<flutter::EventSink<flutter::EncodableValue>>&& mouseEvents = nullptr;
std::atomic<bool> mainThreadAlive(true);
std::atomic<std::chrono::steady_clock::time_point> lastHeartbeat(std::chrono::steady_clock::now());
std::thread* monitorThread = nullptr;
char* wideCharToMultiByte(wchar_t* pWCStrKey) char* wideCharToMultiByte(wchar_t* pWCStrKey)
{ {
size_t pSize = WideCharToMultiByte(CP_OEMCP, 0, pWCStrKey, wcslen(pWCStrKey), NULL, 0, NULL, NULL); size_t pSize = WideCharToMultiByte(CP_OEMCP, 0, pWCStrKey, wcslen(pWCStrKey), NULL, 0, NULL, NULL);
@@ -45,6 +50,22 @@ FlutterWindow::FlutterWindow(const flutter::DartProject& project)
FlutterWindow::~FlutterWindow() {} FlutterWindow::~FlutterWindow() {}
void monitorUIThread() {
const auto timeout = std::chrono::seconds(5);
while (mainThreadAlive.load()) {
auto now = std::chrono::steady_clock::now();
auto duration = now - lastHeartbeat.load();
if (duration > timeout) {
std::cerr << "The UI thread is dead. Terminate the application.";
std::exit(0);
}
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
bool FlutterWindow::OnCreate() { bool FlutterWindow::OnCreate() {
if (!Win32Window::OnCreate()) { if (!Win32Window::OnCreate()) {
return false; return false;
@@ -78,6 +99,13 @@ bool FlutterWindow::OnCreate() {
result->Success(flutter::EncodableValue("No Proxy")); result->Success(flutter::EncodableValue("No Proxy"));
delete(res); delete(res);
} }
else if (call.method_name() == "heartBeat") {
if (monitorThread == nullptr) {
monitorThread = new std::thread{ monitorUIThread };
}
lastHeartbeat = std::chrono::steady_clock::now();
result->Success();
}
}); });
flutter::EventChannel<> channel2( flutter::EventChannel<> channel2(
@@ -163,6 +191,10 @@ void FlutterWindow::OnDestroy() {
} }
Win32Window::OnDestroy(); Win32Window::OnDestroy();
if (monitorThread != nullptr) {
mainThreadAlive = false;
monitorThread->join();
}
} }
void mouse_side_button_listener(unsigned int input) void mouse_side_button_listener(unsigned int input)