解决 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;
}
相关推荐
方白羽2 小时前
Android NFC 功能集成-读卡器模式
android·app·客户端
进击的cc2 小时前
Android Kotlin:委托属性深度解析
android·kotlin
进击的cc2 小时前
Android Kotlin:Kotlin数据类与密封类
android·kotlin
恋猫de小郭2 小时前
你的蓝牙设备可能正在泄漏你的隐私? Bluehood 如何追踪附近设备并做隐私分析
android·前端·ios
私人珍藏库3 小时前
[Android] 卫星地图 共生地球 v1.1.22
android·app·工具·软件·多功能
冰珊孤雪3 小时前
Android Studio Panda革命性升级:内存诊断、构建标准化与AI调试全解析
android·前端
_李小白4 小时前
【OSG学习笔记】Day 23: ClipNode(动态裁剪)
android·笔记·学习
Eagsen CEO4 小时前
如何让 Gemini 在 Android Studio 中顺利工作
android·ide·android studio
ywf12155 小时前
FlinkCDC实战:将 MySQL 数据同步至 ES
android·mysql·elasticsearch
鹏程十八少6 小时前
9. Android Shadow插件化如何解决资源冲突问题和实现tinker热修复资源(源码分析4)
android·前端·面试