解决 Android 应用日志中 JDWP 报错问题

解决 Android 应用日志中 JDWP 报错问题

现象

在基于 Android 11 的代码中,如果关闭 USB 调试,日志中会反复出现以下报错:

复制代码
failed to connect to jdwp control socket: Connection refused

而启用开发者选项的 USB 调试 后,日志中则不会出现该问题。

原因

报错的根本原因出现在 ART 虚拟机 中的 adbconnection 模块,该模块的代码实现了一个无限循环逻辑:

路径:art/adbconnection/adbconnection.cc

复制代码
bool AdbConnectionState::SetupAdbConnection() {
  int sleep_ms = 500;
  const int sleep_max_ms = 2 * 1000;

  const AdbConnectionClientInfo infos[] = {
    {.type = AdbConnectionClientInfoType::pid, .data.pid = static_cast<uint64_t>(getpid())},
    {.type = AdbConnectionClientInfoType::debuggable, .data.debuggable = true},
  };
  const AdbConnectionClientInfo* info_ptrs[] = {&infos[0], &infos[1]};

  while (!shutting_down_) {
    // If adbd isn't running, because USB debugging was disabled or
    // perhaps the system is restarting it for "adb root", the
    // connect() will fail.  We loop here forever waiting for it
    // to come back.
    //
    // Waking up and polling every couple of seconds is generally a
    // bad thing to do, but we only do this if the application is
    // debuggable *and* adbd isn't running.  Still, for the sake
    // of battery life, we should consider timing out and giving
    // up after a few minutes in case somebody ships an app with
    // the debuggable flag set.
    control_ctx_.reset(adbconnection_client_new(info_ptrs, std::size(infos)));
    if (control_ctx_) {
      return true;
    }

    // We failed to connect.
    usleep(sleep_ms * 1000);

    sleep_ms += (sleep_ms >> 1);
    if (sleep_ms > sleep_max_ms) {
      sleep_ms = sleep_max_ms;
    }  
  }

无限循环触发条件

  1. 关闭 USB 调试:此时 adbd 服务未运行,adbconnection_client_new() 方法无法建立连接。
  2. 应用标记为可调试(debuggable=true):系统会持续尝试连接 JDWP 控制 Socket,即使失败也不会终止循环。

连接失败的根本原因

函数 adbconnection_client_new 中尝试连接 JDWP 控制 Socket,但因 adbd 未运行导致连接失败

路径:system/core/adb/libs/adbconnection/adbconnection_client.cpp

复制代码
int rc = connect(ctx->control_socket_.get(), reinterpret_cast<sockaddr*>(&addr), addr_len);
if (rc != 0) {
    PLOG(ERROR) << "failed to connect to jdwp control socket";
    return nullptr;
}

具体触发条件:

  • adbconnection_client_new 方法会调用 connect 尝试建立 Unix 域套接字(AF_UNIX)。
  • 当 JDWP 控制 Socket 无法找到或连接被拒绝时,会输出 Connection refused 错误。

解决方式

方法一:禁用应用的可调试标记

将应用的 AndroidManifest.xml 中的 debuggable 属性设置为 false:

复制代码
<application
    android:debuggable="false"
    ...>
</application>

但是系统中有太多其他的APP,没办法保证每个APP都将 debuggable 属性设置为 false

方法二:修改无限循环逻辑

adbconnection.cc 中的无限循环逻辑进行优化,引入超时机制或条件限制。例如,在 while 循环中加入超时退出逻辑:

复制代码
+  int max_retries = 10; // max retries
+  int retry_count = 0;  // current retries
  while (!shutting_down_) {
    control_ctx_.reset(adbconnection_client_new(info_ptrs, std::size(infos)));
    if (control_ctx_) {
      return true;
    }

    // We failed to connect.
    usleep(sleep_ms * 1000);

    sleep_ms += (sleep_ms >> 1);
    if (sleep_ms > sleep_max_ms) {
      sleep_ms = sleep_max_ms;
    }

+    // set loop limit and exit the loop after reaching the max retries
+    retry_count++;
+    VLOG(jdwp) << "Retry attempt #" << retry_count;
+    if (retry_count >= max_retries) {
+        VLOG(jdwp) << "Reach max retrie, exit the loop";
+        break;
+    }    
  }

  return false;
}
相关推荐
fatiaozhang952741 分钟前
中兴B860AV5.2-U_原机安卓4.4.2系统专用_晶晨S905L3SB处理器_线刷固件包
android·电视盒子·刷机固件·机顶盒刷机·中兴b860av5.2-u
儿歌八万首1 小时前
Android 自定义 View 实战:打造一个跟随滑动的丝滑指示器
android·kotlin
我有与与症1 小时前
Kuikly 实战:手把手撸一个跨平台 AI 聊天助手 (ChatDemo)
android
恋猫de小郭1 小时前
Flutter UI 设计库解耦重构进度,官方解答未来如何适配
android·前端·flutter
apihz1 小时前
全球IP归属地查询免费API详细指南
android·服务器·网络·网络协议·tcp/ip
hgz07102 小时前
Linux环境下MySQL 5.7安装与配置完全指南
android·adb
Just_Paranoid2 小时前
【Android UI】Android 添加圆角背景和点击效果
android·ui·shape·button·textview·ripple
梁同学与Android2 小时前
Android ---【经验篇】阿里云 CentOS 服务器环境搭建 + SpringBoot项目部署(二)
android·spring boot·后端
风往哪边走2 小时前
自定义简易日历
android