本页将介绍如何配置 Android 运行时 (ART) 及其编译选项。讨论的主题包括:系统映像预编译配置、dex2oat
编译选项,以及如何在 system 分区空间、data 分区空间和性能这三者之间取得平衡。
请参阅 ART 和 Dalvik以及Dalvik 可执行文件格式,了解如何使用 ART。请参阅在 Android Runtime (ART) 上验证应用行为,了解如何确保您的应用能够正常运行。
ART 的运作方式
ART 使用预先 (AOT) 编译,并且从 Android 7 开始结合使用 AOT 编译、即时 (JIT) 编译和解译,AOT 编译可由配置文件引导。所有这些执行模式的组合均可配置,我们将在本部分中对此进行介绍。例如,Pixel 设备配置为在以下流程中运行:
- 应用最初是通过 Play 商店分发的 dex 元数据 (
.dm
) 文件安装的,该文件包含云配置文件。ART 会对云配置文件中列出的方法进行 AOT 编译。或者,如果应用不是通过 dex 元数据文件安装的,则不会执行 AOT 编译。 - 应用前几次运行时,系统会对未经过 AOT 编译的方法进行解译。在经过解译的方法中,经常执行的那些方法随后会进行 JIT 编译。ART 会根据执行情况生成一个本地配置文件,并将其与云配置文件(如果有)相结合。
- 当设备空闲并在充电时,编译守护程序会运行,以便根据在前几次运行期间生成的组合配置文件重新编译应用。
- 在后续运行应用时,ART 会使用编译守护程序生成的工件,这些工件包含更多经过 AOT 编译的代码(与未经过 AOT 编译但仍经过解译或 JIT 编译的方法生成的工件相比)。ART 会根据执行情况更新配置文件安装,然后,系统会在后续运行编译守护程序时收集该配置文件。
ART 包括一个编译器(dex2oat
工具)和一个在启动期间加载的运行时 (libart.so
)。dex2oat
工具接受一个 APK 文件,并生成一个或多个编译工件文件,然后运行时将会加载这些文件。文件的个数、扩展名和名称因版本而异,但在 Android 8 版本中,将会生成以下文件:
.vdex
:包含一些可加快验证速度的其他元数据(有时还有 APK 的未压缩 DEX 代码)。.odex
:包含 APK 中已经过 AOT 编译的方法代码。.art (optional)
:包含 APK 中列出的某些字符串和类的 ART 内部表示,用于加快应用启动速度。
编译选项
ART 的编译选项分为两类:
- 系统 ROM 配置:构建系统映像时,会对哪些代码进行 AOT 编译。
- 运行时配置:ART 如何在设备上编译和运行应用。
编译器过滤器
用于配置这两个类别的一个核心 ART 选项是“编译器过滤器”。编译过滤器可控制 ART 如何编译 DEX 代码,是一个传递给 dex2oat
工具的选项。从 Android 8 开始,有四个官方支持的过滤器:
verify
:只运行 DEX 代码验证(不进行 AOT 编译)。quicken
:(在 Android 11 之前)运行 DEX 代码验证,并优化一些 DEX 指令,以获得更好的解译器性能。speed
:运行 DEX 代码验证,并对所有方法进行 AOT 编译。speed-profile
:运行 DEX 代码验证,并对配置文件中列出的方法进行 AOT 编译。
系统 ROM 配置
在构建系统映像时,预安装的库和应用会进行 AOT 编译。此流程称为 dexpreopt。 只要所有依赖项(尤其是启动类路径)保持不变,此类已编译的文件即可使用。
注意:如果设备进行系统模块更新,启动类路径在下次更新期间很可能会发生变化,这会导致所有 dexpreopt 文件都会过时,从而无法使用。
有许多 ART 构建选项可用于配置 dexpreopt。如何配置这些选项取决于系统映像的可用存储空间以及预安装应用的数量。编译到系统 ROM 中的 JAR/APK 可以分为以下四个类别:
- 启动类路径代码:默认使用
speed-profile
编译器过滤器进行编译。 - 系统服务器代码(请参阅本文档后面部分介绍的
PRODUCT_SYSTEM_SERVER_JARS
、PRODUCT_APEX_SYSTEM_SERVER_JARS
、PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
、PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
):- (Android 14 及更高版本)默认使用
speed-profile
编译过滤器进行编译;如果未提供配置文件,则使用speed
编译过滤器进行编译。 - (Android 13 及更低版本)默认使用
speed
编译过滤器进行编译。
PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
进行配置(请参阅本文档的后面部分)。 - (Android 14 及更高版本)默认使用
- 产品专属的核心应用(请参阅本文档后面部分介绍的
PRODUCT_DEXPREOPT_SPEED_APPS
):默认使用speed
编译过滤器进行编译。 - 所有其他应用:默认使用
speed-profile
编译过滤器进行编译;如果未提供配置文件,则使用verify
编译过滤器进行编译。可通过
PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
进行配置(请参阅本文档的后面部分)。
Makefile 选项
WITH_DEXPREOPT
DONT_DEXPREOPT_PREBUILTS
(Android 5 及更高版本)PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
(Android 9 及更高版本)WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
(从 Android 8 MR1 开始)LOCAL_DEX_PREOPT
PRODUCT_DEX_PREOPT_BOOT_FLAGS
PRODUCT_DEX_PREOPT_DEFAULT_FLAGS
PRODUCT_DEX_PREOPT_MODULE_CONFIGS
PRODUCT_DEXPREOPT_SPEED_APPS
(从 Android 8 开始)PRODUCT_SYSTEM_SERVER_APPS
(从 Android 8 开始)PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD
(从 Android 8 开始)WITH_DEXPREOPT_PIC
(在 Android 7 之前)WITH_DEXPREOPT_BOOT_IMG_ONLY
(在 Android 7 MR1 之前)PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
- (Android 14 及更高版本)如果未指定,则使用
speed-profile
编译过滤器;如果未提供配置文件,则使用speed
编译过滤器。 - (Android 13 及更低版本)如果未指定,则使用
speed
编译过滤器。 - 如果设置为
speed
,则使用speed
编译过滤器。 - 如果设置为
speed-profile
,则使用speed-profile
编译过滤器;如果未提供配置文件,则使用verify
编译过滤器。 - 如果设置为
verify
,则使用verify
编译过滤器。 PRODUCT_SYSTEM_SERVER_JARS
、PRODUCT_APEX_SYSTEM_SERVER_JARS
、PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
、PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
- (必需)
PRODUCT_SYSTEM_SERVER_JARS
:平台上的系统服务器类路径 JAR 的列表(即作为SYSTEMSERVERCLASSPATH
的一部分)。需要将系统服务器类路径 JAR 添加到此列表。如果未能将系统服务器类路径 JAR 添加到此列表,会导致这些 JAR 无法加载。 - (必需)
PRODUCT_APEX_SYSTEM_SERVER_JARS
:通过 APEX 传递的系统服务器类路径 JAR 的列表(即作为SYSTEMSERVERCLASSPATH
的一部分)。格式为<apex name>:<jar name>
。必需将 APEX 系统服务器类路径 JAR 添加到此列表。如果未能将 APEX 系统服务器类路径 JAR 添加到此列表,会导致这些 JAR 无法加载。 - (可选,Android 13 及更低版本)
PRODUCT_STANDALONE_SYSTEM_SERVER_JARS
:系统服务器使用单独的类加载器动态加载(通过SystemServiceManager.startServiceFromJar
)的 JAR 的列表。无需将独立系统服务器 JAR 添加到此列表,但强烈建议您这样做,原因是这会使 JAR 经过编译,因此 JAR 将具有良好的运行时性能。 - (必需,从 Android 13 开始)
PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS
:通过 APEX 传递且系统服务器使用单独的类加载器动态加载(即通过SystemServiceManager.startServiceFromJar
或声明为<apex-system-service>
)的 JAR 的列表。格式为<apex name>:<jar name>
。必需将独立的 APEX 系统服务器 JAR 添加到此列表。如果未能将独立的 APEX 系统服务器 JAR 添加到此列表,会导致启动失败。
是否对系统映像上安装的 DEX 代码调用 dex2oat
。默认处于启用状态。
启用 DONT_DEXPREOPT_PREBUILTS
可防止对预构建应用进行 dexpreopt。这些都是在 Android.mk
中指定了 include $(BUILD_PREBUILT)
的应用。如果不对这些可能要通过 Google Play 更新的预构建应用进行 dexpreopt,可以节省系统映像内的空间,但是会增加首次启动时间。请注意,此选项对 Android.bp
中定义的预构建应用没有任何影响。
PRODUCT_DEX_PREOPT_DEFAULT_COMPILER_FILTER
为经过 dexpreopt 的应用指定默认编译器过滤器。这些都是 Android.bp
中定义或在 Android.mk
中指定了 include $(BUILD_PREBUILT)
的应用。如果未指定,则默认值为 speed-profile
;如果未指定值且未提供配置文件,则值为 verify
。
如果启用 WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
,将只会对启动类路径和系统服务器 JAR 进行 dexpreopt。
通过在模块定义中指定 LOCAL_DEX_PREOPT
选项,还可以针对个别应用启用或停用 dexpreopt。这有助于避免对那些可能会立即收到 Google Play 更新的应用进行 dexpreopt,因为更新之后,对系统映像中的代码所做的 dexpreopt 都会变为无用功。此外,这还有助于在进行重大版本 OTA 升级时节省空间,因为用户的数据分区中可能已经有了更高版本的应用。
LOCAL_DEX_PREOPT
支持分别使用值 true
或 false
来启用或停用 dexpreopt。此外,如果在 dexpreopt 过程中不应将 classes.dex
文件从 APK 或 JAR 文件中剥离出来,则可以指定 nostripping
。通常情况下,该文件会被剥离出来,因为在进行 dexpreopt 之后将不再需要该文件;但若要使第三方 APK 签名仍保持有效,则必须使用最后这个选项。
将选项传递给 dex2oat
以控制如何编译启动映像。该选项可用于指定自定义映像类列表、已编译类列表,以及编译过滤器。
将选项传递给 dex2oat
以控制如何编译除启动映像之外的所有内容。
用于为特定模块和产品配置传递 dex2oat
选项。该选项在产品的 device.mk
文件中通过 $(call add-product-dex-preopt-module-config,<modules>,<option>)
设置,其中 <modules>
是一个 LOCAL_MODULE
(表示 JAR 文件)和 LOCAL_PACKAGE
(表示 APK 文件)名称的列表。
一个应用列表,其中的应用被确定为产品的核心应用,并且应使用 speed
编译器过滤器进行编译。例如,常驻应用(如 SystemUI)只有在下次系统重新启动时才有机会使用配置文件引导的编译,因此可能最好是让产品始终对这些应用进行 AOT 编译。
系统服务器加载的应用的列表。这些应用默认使用 speed
编译器过滤器进行编译。
是否在设备上包含 ART 的调试版本。默认情况下,系统会针对 userdebug build 和 eng build 启用此选项。可以通过将该选项明确设为 true
或 false
来覆盖此行为。
默认情况下,设备将使用非调试版本 (libart.so
)。如需进行切换,请将系统属性 persist.sys.dalvik.vm.lib.2
设置为 libartd.so
。
从 Android 5.1.0 到 Android 6.0.1 的所有版本中,都可以指定 WITH_DEXPREOPT_PIC
来启用位置无关代码 (PIC)。这样一来,就不必将来自映像的编译代码从 /system
迁移到 /data/dalvik-cache
,因此可以节省 data 分区中的空间。不过,因为该选项会停用根据位置相关代码进行的优化,所以会对运行时产生轻微的影响。通常情况下,需要节省 /data
空间的设备应启用 PIC 编译。
在 Android 7.0 中,PIC 编译默认处于启用状态。
此选项已被 WITH_DEXPREOPT_BOOT_IMG_AND_SYSTEM_SERVER_ONLY
取代,后者还会预先优化系统服务器 JAR。
此选项可指定系统服务器的编译过滤器。
以下是系统服务器加载的 JAR 的列表。JAR 使用由 PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
指定的编译过滤器进行编译
启动类路径配置
预加载的类列表列出了 Zygote 在启动时初始化的类。利用该列表,每个应用无需单独运行这些类初始化程序,从而可以更快地启动并共享内存中的页面。预加载的类列表文件默认位于 frameworks/base/config/preloaded-classes
,其中包含一个针对典型手机使用场景优化的列表。此列表可能不适用于其他设备(如穿戴式设备),必须进行相应调整。做调整时要格外小心;添加的类太多会造成加载未用到的类而浪费内存,而添加的类太少又会导致每个应用都各有一份副本,同样会造成内存浪费。
使用示例(在产品的 device.mk
中):
PRODUCT_COPY_FILES += <filename>:system/etc/preloaded-classes
注意:如果有任何从 build/target/product/base.mk
提取默认值的产品配置 makefile,则此行必须放置在沿用任何这类 makefile 的行之前。
运行时配置
JIT 选项
仅在 ART JIT 编译器可用的情况下,以下选项才会影响 Android 版本。
dalvik.vm.usejit
:是否启用 JIT。dalvik.vm.jitinitialsize
(默认为 64K):代码缓存的初始容量。代码缓存将定期进行垃圾回收 (GC),并将视需要增加容量。dalvik.vm.jitmaxsize
(默认为 64M):代码缓存的最大容量。dalvik.vm.jitthreshold
(默认为 10000):方法的“热度”计数器必须超过该阈值,系统才会对方法进行 JIT 编译。“热度”计数器是运行时的内部指标。它的影响因素包括调用次数、后向分支及其他因素。dalvik.vm.usejitprofiles
(在 Android 13 之前):是否启用 JIT 配置文件;即使dalvik.vm.usejit
为 false,也可以使用该选项。请注意,如果该选项为 false,编译器过滤器speed-profile
将不会对任何方法进行 AOT 编译,效果与verify
相同。从 Android 14 开始,JIT 配置文件始终处于启用状态,并且无法关闭。dalvik.vm.jitprithreadweight
(默认为dalvik.vm.jitthreshold
/ 20):应用界面线程的 JIT“样本”(请参阅 jitthreshold)的权重。用于加快以下方法的编译速度:当用户与应用交互时,会直接影响用户体验的方法。dalvik.vm.jittransitionweight
(默认为dalvik.vm.jitthreshold
/ 10):调用时需要在编译代码和解译器之间进行转换的方法的权重。这有助于确保对所涉及的方法进行编译以尽可能减少转换(转换需要很大开销)。
Dex2oat 选项
这些选项会影响设备端编译(又称为 dexopt),其中几个选项还会影响 dexpreopt,而上文系统 ROM 配置部分中所述的选项只会影响 dexpreopt。
用于控制资源使用情况的选项:
dalvik.vm.image-dex2oat-threads
/dalvik.vm.image-dex2oat-cpu-set
(在 Android 11 之前):用于启动映像的线程数量和 CPU 核心组(见下文)。dalvik.vm.boot-dex2oat-threads
/dalvik.vm.boot-dex2oat-cpu-set
:- (在 Android 11 之前)在启动期间用于除启动映像外所有其他内容的线程数量和 CPU 核心组(见下文)。
- (从 Android 12 开始)在启动期间用于所有内容(包括启动映像)的线程数量和 CPU 核心组(见下文)。
- 具体而言,从 Android 14 开始,这与 ART 服务中的优先级类
PRIORITY_BOOT
对应。
- 具体而言,从 Android 14 开始,这与 ART 服务中的优先级类
dalvik.vm.restore-dex2oat-threads
/dalvik.vm.restore-dex2oat-cpu-set
:- (从 Android 11 到 Android 13)从云端备份恢复所用的线程数量和 CPU 核心组(见下文)。
- (从 Android 14 开始)用于比正常情况对延迟更敏感的所有操作(包括从云端备份恢复)的线程数量和 CPU 核心组(见下文)。
- 具体而言,这与 ART 服务中的优先级类
PRIORITY_INTERACTIVE_FAST
对应。
- 具体而言,这与 ART 服务中的优先级类
dalvik.vm.background-dex2oat-threads
/dalvik.vm.background-dex2oat-cpu-set
(从 Android 14 开始):在后台使用的线程数量和 CPU 核心组(见下文)。- 具体而言,这与 ART 服务中的优先级类
PRIORITY_BACKGROUND
对应。
- 具体而言,这与 ART 服务中的优先级类
dalvik.vm.dex2oat-threads
/dalvik.vm.dex2oat-cpu-set
:用于所有其他操作的线程数量和 CPU 核心组。
指定 CPU 核心组时,应采用以英文逗号分隔的 CPU ID 列表的形式。例如,如需在 CPU 核心 0-3 上运行 dex2oat,请按如下所示进行设置:
dalvik.vm.dex2oat-cpu-set=0,1,2,3
设置 CPU 亲和性属性时,建议设定 dex2oat 线程数量的相应属性与选定的 CPU 的数量相匹配,以避免不必要的内存和 I/O 争用:
dalvik.vm.dex2oat-cpu-set=0,1,2,3 dalvik.vm.dex2oat-threads=4
除了上述系统属性之外,您还可以使用任务配置文件来控制 dex2oat 的资源使用情况(请参阅 Cgroup 抽象层)。
支持的任务配置文件包括:
Dex2OatBackground
(从 Android 14 开始)(默认情况下继承Dex2OatBootComplete
):控制在后台使用的资源。- 具体而言,这与 ART 服务中的优先级类
PRIORITY_BACKGROUND
对应。
- 具体而言,这与 ART 服务中的优先级类
Dex2OatBootComplete
:- (在 Android 13 之前)控制要用于启动后的所有操作的资源。
- (从 Android 14 开始)控制要用于启动后的所有非后台运行操作的资源。
- 具体而言,这与 ART 服务中的优先级类
PRIORITY_INTERACTIVE_FAST
和PRIORITY_INTERACTIVE
对应。
- 具体而言,这与 ART 服务中的优先级类
如果同时指定了系统属性和任务配置文件,则两者都会生效。
用于控制堆大小的选项:
dalvik.vm.image-dex2oat-Xms
:启动映像的初始堆大小。dalvik.vm.image-dex2oat-Xmx
:启动映像的堆大小上限。dalvik.vm.dex2oat-Xms
:所有其他内容的初始堆大小。dalvik.vm.dex2oat-Xmx
:所有其他内容的堆大小上限。
不应减小用于控制 dex2oat
初始堆大小和堆大小上限的选项数值,因为它们可能会限制可对哪些应用进行编译。
用于控制编译器过滤器的选项:
dalvik.vm.image-dex2oat-filter
(在 Android 11 之前):启动映像的编译器过滤器。从 Android 12 开始,启动映像的编译器过滤器始终为speed-profile
,并且无法更改。dalvik.vm.systemservercompilerfilter
(从 Android 13 开始):系统服务器的编译器过滤器。请参阅PRODUCT_SYSTEM_SERVER_COMPILER_FILTER
。dalvik.vm.systemuicompilerfilter
(从 Android 13 开始):系统界面包的编译器过滤器。dalvik.vm.dex2oat-filter
(在 Android 6 之前):所有其他内容的编译器过滤器。pm.dexopt.<reason>
(从 Android 7 开始):所有其他内容的编译器过滤器。对于 Android 14 及更高版本,请参阅 ART 服务配置;对于 Android 13 及更低版本,请参阅软件包管理系统配置。
用于控制除启动映像外的所有其他内容的编译的其他选项:
dalvik.vm.dex2oat-very-large
(从 Android 7.1 开始):停用 AOT 编译的最小总 dex 文件大小(以字节为单位)。dalvik.vm.dex2oat-swap
(从 Android 7.1 开始)(默认值:true):允许为 dex2oat 使用交换文件。这有助于避免内存不足崩溃。请注意,即使此选项已开启,dex2oat 也只会在特定条件下(例如 dex 文件数量很多)使用交换文件,条件可能会发生变化。dalvik.vm.ps-min-first-save-ms
(从 Android 12 开始):在运行时生成应用配置文件(应用首次启动)之前等待的最短时间。dalvik.vm.ps-min-save-period-ms
(从 Android 12 开始):更新应用配置文件之前等待的最短时间。dalvik.vm.dex2oat64.enabled
(从 Android 11 开始)(默认值:false):是否使用 64 位版本的 dex2oat。dalvik.vm.bgdexopt.new-classes-percent
(从 Android 12 开始)(默认值:20):配置文件中用于触发重新编译的新类的最小百分比(0 到 100 之间)。仅适用于配置文件引导的编译 (speed-profile
),通常在后台 dexopt 运行期间。请注意,除了百分比阈值之外,系统还会创建“至少 50 个新类”阈值,并且该阈值不可配置。dalvik.vm.bgdexopt.new-methods-percent
(从 Android 12 开始)(默认值:20):配置文件中用于触发重新编译的新方法的最小百分比(0 到 100 之间)。 仅适用于配置文件引导的编译 (speed-profile
),通常在后台 dexopt 运行期间。请注意,除了百分比阈值之外,系统还会创建“至少 100 个新方法”阈值,并且该阈值不可配置。dalvik.vm.dex2oat-max-image-block-size
(从 Android 10 开始)(默认值:524288)压缩图片的实心块大小上限。系统会将一张大图片拆分为一组实心块,确保实心块不超过大小上限。dalvik.vm.dex2oat-resolve-startup-strings
(从 Android 10 开始)(默认值:true)如果为 true,则会导致 dex2oat 解析配置文件中标记为“startup”的方法引用的所有常量字符串。debug.generate-debug-info
(默认值:false)是否要为原生调试生成调试信息,例如堆栈展开信息、ELF 符号和 dwarf 部分。dalvik.vm.dex2oat-minidebuginfo
(从 Android 9 开始)(默认值:true)是否生成输出回溯所需的最少量的 LZMA 压缩调试信息。
ART 服务选项
从 Android 14 开始,应用的设备端 AOT 编译(又称为 dexopt)由 ART 服务处理。如需了解如何配置 ART 服务,请参阅 ART 服务配置。软件包管理系统选项
在 Android 14 之前,应用的设备端 AOT 编译(又称为 dexopt)由软件包管理系统处理。如需了解如何为 dexopt 配置软件包管理系统,请参阅软件包管理系统配置。A/B 专有配置
ROM 配置
从 Android 7.0 开始,设备可以使用两个 system 分区来实现 A/B 系统更新。为了减小 system 分区大小,可以将经过预先优化的文件安装在未使用的第二个 system 分区中。在系统首次启动时,这些文件会被复制到 data 分区。
使用示例(在 device-common.mk
中):
PRODUCT_PACKAGES += \ cppreopts.sh PRODUCT_PROPERTY_OVERRIDES += \ ro.cp_system_other_odex=1
在设备的 BoardConfig.mk
中:
BOARD_USES_SYSTEM_OTHER_ODEX := true
请注意,启动类路径代码、系统服务器代码以及产品专属的核心应用始终会被编译到系统分区中。默认情况下,所有其他应用都会被编译到未使用的第二个系统分区中。可以使用 SYSTEM_OTHER_ODEX_FILTER
控制此行为,其值默认为:
SYSTEM_OTHER_ODEX_FILTER ?= app/% priv-app/%
后台 OTA dexopt
在启用了 A/B 的设备上,在使用新的系统映像重新启动之前,可以在后台编译应用。如需在系统映像中选择性地加入编译脚本和二进制文件,请参阅在后台编译应用。可通过以下选项控制用于此类编译的编译器过滤器:
pm.dexopt.ab-ota=speed-profile
我们建议使用 speed-profile
,以利用配置文件引导的编译并节省存储空间。
JDWP 选项
persist.debug.dalvik.vm.jdwp.enabled
系统属性用于控制是否在 userdebug build 中创建 Java 调试网络协议 (JDWP) 线程。默认情况下,系统不会设置此属性,且系统只会为可调试应用创建 JDWP 线程。如需同时为可调试和不可调试应用启用 JDWP 线程,请将 persist.debug.dalvik.vm.jdwp.enabled
设为 1
。必须重新启动设备,才能使属性更改生效。
如需在 userdebug build 中调试某个不可调试应用,请运行以下命令来启用 JDWP:
对于搭载 Android 13 或更低版本的设备,运行时会在 userdebug build 中为可调试和不可调试应用创建 JDWP 线程。这意味着,您可以在 userdebug build 中附加调试程序或分析应用性能。adb shell setprop persist.debug.dalvik.vm.jdwp.enabled 1
adb reboot