From 4a6bd4e5672029d03f287a8aff13140b45624f3e Mon Sep 17 00:00:00 2001 From: zzyyyl Date: Sat, 17 Sep 2022 16:59:14 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20Controller=20?= =?UTF-8?q?=E4=B8=AD=20m=5Finstance=5Fcount=20=E4=B8=80=E5=AE=9A=E4=BC=9A?= =?UTF-8?q?=E5=87=8F=E5=88=B0=E8=B4=9F=E6=95=B0=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 满是bug的代码居然正常的跑起来了.jpg --- src/MeoAssistant/Controller.cpp | 126 +++++++++++++++++--------------- src/MeoAssistant/Controller.h | 6 +- 2 files changed, 70 insertions(+), 62 deletions(-) diff --git a/src/MeoAssistant/Controller.cpp b/src/MeoAssistant/Controller.cpp index 863e959452..f63f75ac89 100644 --- a/src/MeoAssistant/Controller.cpp +++ b/src/MeoAssistant/Controller.cpp @@ -40,14 +40,10 @@ asst::Controller::Controller(AsstCallback callback, void* callback_arg) #ifdef _WIN32 - m_support_socket = false; - do { - if (!WsaHelper::get_instance()()) { - Log.error("WSA not supports"); - break; - } - m_support_socket = true; - } while (false); + m_support_socket = WsaHelper::get_instance()(); + if (!m_support_socket) { + Log.error("WSA not supports"); + } #else int pipe_in_ret = pipe(m_pipe_in); @@ -76,9 +72,7 @@ asst::Controller::~Controller() m_cmd_thread.join(); } - if (--m_instance_count) { - release(); - } + try_release(); #ifndef _WIN32 close(m_pipe_in[PIPE_READ]); @@ -185,7 +179,8 @@ void asst::Controller::pipe_working_proc() } } -std::optional asst::Controller::call_command(const std::string& cmd, int64_t timeout, bool recv_by_socket) +std::optional asst::Controller::call_command(const std::string& cmd, int64_t timeout, bool recv_by_socket, + bool allow_reconnect) { using namespace std::chrono_literals; using namespace std::chrono; @@ -424,10 +419,7 @@ std::optional asst::Controller::call_command(const std::string& cmd if (!exit_ret) { return recv_by_socket ? sock_data : pipe_data; } - else if (m_inited) { - // 这里用 m_inited 限制了仅递归一层,修改需要注意下 - m_inited = false; - + else if (allow_reconnect) { // 之前可以运行,突然运行不了了,这种情况多半是 adb 炸了。所以重新连接一下 json::value reconnect_info = json::object { { "uuid", m_uuid }, @@ -448,20 +440,18 @@ std::optional asst::Controller::call_command(const std::string& cmd callback(AsstMsg::ConnectionInfo, reconnect_info); std::this_thread::sleep_for(10s); - auto reconnect_ret = call_command(m_adb.connect, 60LL * 1000); + auto reconnect_ret = call_command(m_adb.connect, 60LL * 1000, false /* 禁止重连避免无限递归 */); bool is_reconnect_success = false; if (reconnect_ret) { auto& reconnect_str = reconnect_ret.value(); is_reconnect_success = reconnect_str.find("error") == std::string::npos; } if (is_reconnect_success) { - auto recall_ret = call_command(cmd, timeout, recv_by_socket); + auto recall_ret = call_command(cmd, timeout, recv_by_socket, false /* 禁止重连避免无限递归 */); if (recall_ret) { // 重连并成功执行了 - m_inited = true; reconnect_info["what"] = "Reconnected"; callback(AsstMsg::ConnectionInfo, reconnect_info); - return recall_ret; } } @@ -475,7 +465,7 @@ std::optional asst::Controller::call_command(const std::string& cmd { "cmd", m_adb.connect }, } }, }; - m_inited = false; + try_release(); // 重连失败,释放 callback(AsstMsg::ConnectionInfo, info); } @@ -564,7 +554,7 @@ void asst::Controller::random_delay() const void asst::Controller::clear_info() noexcept { - m_inited = false; + try_release(); m_adb = decltype(m_adb)(); m_uuid.clear(); m_width = 0; @@ -578,7 +568,6 @@ void asst::Controller::clear_info() noexcept } m_server_started = false; #endif - --m_instance_count; } int asst::Controller::push_cmd(const std::string& cmd) @@ -705,7 +694,7 @@ bool asst::Controller::screencap() case AdbProperty::ScreencapMethod::UnknownYet: { using namespace std::chrono; Log.info("Try to find the fastest way to screencap"); - m_inited = false; + try_release(); // 这个地方应该是 inited() == false 的,不会 release,因为 connect 函数调用前会 clear_info auto min_cost = milliseconds(LLONG_MAX); auto start_time = high_resolution_clock::now(); @@ -713,7 +702,7 @@ bool asst::Controller::screencap() auto duration = duration_cast(high_resolution_clock::now() - start_time); if (duration < min_cost) { m_adb.screencap_method = AdbProperty::ScreencapMethod::RawByNc; - m_inited = true; + set_inited(); min_cost = duration; } Log.info("RawByNc cost", duration.count(), "ms"); @@ -728,7 +717,7 @@ bool asst::Controller::screencap() auto duration = duration_cast(high_resolution_clock::now() - start_time); if (duration < min_cost) { m_adb.screencap_method = AdbProperty::ScreencapMethod::RawWithGzip; - m_inited = true; + set_inited(); min_cost = duration; } Log.info("RawWithGzip cost", duration.count(), "ms"); @@ -743,7 +732,7 @@ bool asst::Controller::screencap() auto duration = duration_cast(high_resolution_clock::now() - start_time); if (duration < min_cost) { m_adb.screencap_method = AdbProperty::ScreencapMethod::Encode; - m_inited = true; + set_inited(); min_cost = duration; } Log.info("Encode cost", duration.count(), "ms"); @@ -753,7 +742,7 @@ bool asst::Controller::screencap() } Log.info("The fastest way is", static_cast(m_adb.screencap_method), ", cost:", min_cost.count(), "ms"); clear_lf_info(); - return m_inited; + return inited(); } break; case AdbProperty::ScreencapMethod::RawByNc: { return screencap(m_adb.screencap_raw_by_nc, decode_raw, true); @@ -793,7 +782,7 @@ bool asst::Controller::screencap(const std::string& cmd, const DecodeFunc& decod } if (decode_func(data)) [[likely]] { - if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) { + if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) [[unlikely]] { Log.info("screencap_end_of_line is LF"); m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::LF; } @@ -802,31 +791,29 @@ bool asst::Controller::screencap(const std::string& cmd, const DecodeFunc& decod else { Log.info("data is not empty, but image is empty"); - if (!tried_conversion) { - Log.info("try to cvt lf"); - if (!convert_lf(data)) { // 没找到 "\r\n",data 没有变化,不必重试 - Log.error("skip retry decoding and decode failed!"); - return false; - } - - if (decode_func(data)) { - if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) { - Log.info("screencap_end_of_line is CRLF"); - } - else { - Log.info("screencap_end_of_line is changed to CRLF"); - } - m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::CRLF; - return true; - } - else { - Log.error("convert lf and retry decode failed!"); - } - } - else { // 已经转换过行尾,再次转换 data 不会变化,不必重试 + if (tried_conversion) { // 已经转换过行尾,再次转换 data 不会变化,不必重试 Log.error("skip retry decoding and decode failed!"); + return false; } - return false; + + Log.info("try to cvt lf"); + if (!convert_lf(data)) { // 没找到 "\r\n",data 没有变化,不必重试 + Log.error("no `\\r\\n` found, skip retry decode"); + return false; + } + if (!decode_func(data)) { + Log.error("convert lf and retry decode failed!"); + return false; + } + + if (m_adb.screencap_end_of_line == AdbProperty::ScreencapEndOfLine::UnknownYet) { + Log.info("screencap_end_of_line is CRLF"); + } + else { + Log.info("screencap_end_of_line is changed to CRLF"); + } + m_adb.screencap_end_of_line = AdbProperty::ScreencapEndOfLine::CRLF; + return true; } } @@ -928,10 +915,8 @@ int asst::Controller::swipe(const Rect& r1, const Rect& r2, int duration, bool b int asst::Controller::swipe_without_scale(const Point& p1, const Point& p2, int duration, bool block, int extra_delay, bool extra_swipe) { - int x1 = p1.x; - int y1 = p1.y; - int x2 = p2.x; - int y2 = p2.y; + int x1 = p1.x, y1 = p1.y; + int x2 = p2.x, y2 = p2.y; // 起点不能在屏幕外,但是终点可以 if (x1 < 0 || x1 >= m_width || y1 < 0 || y1 >= m_height) { @@ -990,7 +975,7 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a #ifdef ASST_DEBUG if (config == "DEBUG") { - m_inited = true; + set_inited(); return true; } #endif @@ -1221,9 +1206,30 @@ bool asst::Controller::connect(const std::string& adb_path, const std::string& a } // try to find the fastest way - screencap(); + if (!screencap()) { + Log.error("Cannot find a proper way to screencap!"); + return false; + } - ++m_instance_count; + return true; +} + +void asst::Controller::set_inited() noexcept +{ + if (!m_inited) { + m_inited = true; + ++m_instance_count; + } +} + +bool asst::Controller::try_release() +{ + if (m_inited) { + m_inited = false; + if (!--m_instance_count) { // 所有实例全部释放,才执行最终的 release 函数 + return release(); + } + } return true; } @@ -1275,7 +1281,7 @@ cv::Mat asst::Controller::get_image(bool raw) // 有些模拟器adb偶尔会莫名其妙截图失败,多试几次 static constexpr int MaxTryCount = 20; bool success = false; - for (int i = 0; i < MaxTryCount && m_inited; ++i) { + for (int i = 0; i < MaxTryCount && inited(); ++i) { if (need_exit()) { break; } diff --git a/src/MeoAssistant/Controller.h b/src/MeoAssistant/Controller.h index 5c777965bd..2c7d6dd832 100644 --- a/src/MeoAssistant/Controller.h +++ b/src/MeoAssistant/Controller.h @@ -35,7 +35,7 @@ namespace asst ~Controller(); bool connect(const std::string& adb_path, const std::string& address, const std::string& config); - bool release(); + bool try_release(); bool inited() const noexcept; void set_exit_flag(bool* flag); @@ -76,8 +76,10 @@ namespace asst bool need_exit() const; void pipe_working_proc(); std::optional call_command(const std::string& cmd, int64_t timeout = 20000, - bool recv_by_socket = false); + bool recv_by_socket = false, bool allow_reconnect = true); int push_cmd(const std::string& cmd); + bool release(); + void set_inited() noexcept; std::optional try_to_init_socket(const std::string& local_address);