Android 17 重点新特性介绍

本文重点面向 Android 应用开发者,围绕 Android 17 中值得关注的系统行为变更、性能分析、大屏适配、后台音频等方向展开。

随着 AI Coding 的普及,很多日常业务代码已经可以交给 AI 辅助完成。但 Android 系统版本的行为变更,尤其是 Framework 层、系统调度策略、后台限制、兼容性开关等内容,仍然需要开发者自己保持关注。

原因很简单:AI 可以帮我们写代码,但它不一定天然知道某个 Android 新版本中具体改了什么。如果开发者自己不了解系统行为变化,就很容易让 AI 继续按照旧版本经验生成代码,最后在高版本系统上出现兼容性问题。

本文主要梳理 Android 17 中几个值得重点关注的变化:

  1. MessageQueue 无锁化重构
  2. ProfilingManager 触发器能力增强
  3. 大屏适配要求进一步强制化
  4. 后台音频交互限制加强

1、MessageQueue 无锁化重构

Android 开发者对 HandlerLooperMessageQueue 这套机制应该都不陌生。它从 Android 早期版本开始就是主线程消息循环的核心,也是面试中经常被反复追问的基础模块。

但从性能角度看,传统 MessageQueue 并不是没有问题。

1.1 旧实现的问题

传统 MessageQueue 的队列同步依赖比较重的同步锁。主线程从队列中取消息,或者其他线程向队列中投递消息时,都可能围绕同一把锁发生竞争。

在早期单核或少核设备上,这类锁竞争问题并不一定明显。但现在手机性能越来越强,应用内部线程数量也越来越多。网络回调、图片加载、数据库访问、埋点、APM、业务线程池等模块,都可能不断向主线程投递消息。

这就可能出现一种情况:

非主线程正在操作 MessageQueue 并持有锁,主线程想取下一条消息时却需要等待锁释放。对于用户来说,这种等待最终可能体现为卡顿。

1.2 Android 17 的变化

Android 17 对 MessageQueue 引入了新的内部实现。这套新实现的核心思路是通过类似 CAS 的原子操作来减少传统锁竞争。

CAS 即 Compare And Swap,是并发编程中常见的无锁同步方式。它不会像传统锁一样挂起线程,而是通过不断比较当前值是否符合预期来决定是否更新。

放到 MessageQueue 场景中,这意味着:

  1. 非主线程投递消息时,不再像过去那样容易阻塞主线程。
  2. 主线程出队时由主线程自身完成,减少锁竞争。
  3. 多线程频繁操作消息队列时,理论上能降低由锁竞争带来的卡顿风险。

从效果上看,这是一个偏 Framework 内部实现的性能优化。普通业务代码中常用的 Handler.post {}sendMessage() 等方式一般不会受到影响。

1.3 对应用代码的影响

真正需要警惕的是那些反射访问 MessageQueue 内部字段的代码。

过去很多性能监控、卡顿检测、测试框架、APM SDK,会通过反射读取 MessageQueue 中的内部链表,比如读取 mMessages,然后遍历队列中的消息,分析任务耗时、调度情况或卡顿原因。

Android 17 新实现中,这个字段虽然可能仍然存在,但它不再代表真实队列内容,甚至可能长期为空。也就是说,依赖该字段的逻辑会失效。

需要重点检查的场景包括:

  1. 自研 APM 或卡顿监控代码
  2. 反射读取 MessageQueue.mMessages 的工具类
  3. 三方性能分析 SDK
  4. UI 自动化测试框架
  5. Robolectric、Espresso 等测试依赖

Espresso 建议升级到 3.7.0 之后的版本,因为旧版本也可能依赖相关内部字段。

1.4 建议的适配动作

对于业务应用来说,可以按下面几个步骤排查:

  1. 全局搜索 MessageQueuemMessagesLooperHandler 相关反射代码。
  2. 检查 APM、卡顿监控、性能 SDK 是否使用了私有字段。
  3. 升级测试框架,尤其是 Espresso、Robolectric。
  4. 对需要支持 Android 17 的包提前打开兼容性开关验证。
  5. 尽量避免继续依赖 Framework 私有字段构建监控能力。

可以把这个变化理解为:普通消息投递代码没什么问题,但"偷看消息队列内部结构"的代码需要重新审视。

2、ProfilingManager 触发器增强

性能问题最难处理的地方,往往不是不会分析,而是问题难以复现。

线上用户遇到 ANR、OOM、启动变慢、CPU 使用过高、系统强杀等问题时,开发者在本地未必能复现同样环境。即使加日志、加埋点、加监控,也可能因为数据不够完整而无法定位根因。

ProfilingManager 正是 Android 提供的系统级性能数据采集入口。它在 API 35 开始提供主动请求 profiling 的能力,支持采集 system trace、Java heap dump、heap profile、stack sampling 等数据;到了 API 36,系统开始引入 ProfilingTrigger,应用可以注册某类系统事件,让系统在事件发生时自动捕获 profiling 产物。

2.1 从主动请求到系统触发

主动请求 profiling 的方式适合开发者明确知道"现在要采集"的场景。例如在某个调试入口点击按钮,调用 requestProfiling() 主动抓一段 trace 或 heap dump。

但线上性能问题通常不是这样发生的。很多问题发生时,开发者并不知道它即将出现:

  1. ANR 发生前,主线程可能已经阻塞了一段时间。
  2. OOM 抛出时,内存分配现场已经非常接近崩溃边界。
  3. 应用冷启动慢,关键耗时往往出现在非常早的启动阶段。
  4. 进程因为 CPU 使用异常被系统终止时,应用可能已经没有机会自己采集数据。

如果等问题发生后再开始采集,最关键的现场很可能已经丢失。

ProfilingTrigger 的价值就在这里:应用提前注册自己关心的触发器,由系统在特定事件发生时捕获 profiling 产物,再通过回调把文件路径交给应用。

2.2 可用的系统触发器

ProfilingTrigger 本身从 API 36 开始提供:

  • API 36 阶段主要覆盖启动完成、ANR 等关键事件;
  • API 36.1 补充了请求当前后台 trace 快照、用户主动终止应用等场景;
  • API 37,也就是 Android 17,则新增了冷启动、OOM、异常检测、CPU 使用过高终止、兼容性异常等更贴近线上治理的触发器。

API 36/36.1:基础触发器

Trigger 版本 触发时机 返回产物
TRIGGER_TYPE_APP_FULLY_DRAWN API 36 冷启动后调用 Activity.reportFullyDrawn() system trace 快照
TRIGGER_TYPE_ANR API 36 系统识别到 ANR 后、尝试杀进程前 system trace 快照
TRIGGER_TYPE_APP_REQUEST_RUNNING_TRACE API 36.1 应用调用 requestRunningSystemTrace() 请求当前 trace system trace 快照
TRIGGER_TYPE_KILL_FORCE_STOP API 36.1 用户在设置页点击 Force stop 强停应用 system trace 快照
TRIGGER_TYPE_KILL_RECENTS API 36.1 用户在最近任务界面移除应用 system trace 快照
TRIGGER_TYPE_KILL_TASK_MANAGER API 36.1 用户在 Task Manager 中点击 Stop 终止应用 system trace 快照

API 37:Android 17 新增触发器

Trigger 触发时机 返回产物 适合分析
TRIGGER_TYPE_COLD_START 应用冷启动早期触发,ApplicationStartInfo.getStartType()START_TYPE_COLD system trace + stack sampling profile 冷启动耗时、启动早期阻塞、初始化过重
TRIGGER_TYPE_OOM 应用抛出 OutOfMemoryError Java heap dump Java 堆泄漏、大对象分配、缓存失控
TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE 应用因 CPU 使用过高被系统终止,退出原因为 REASON_EXCESSIVE_RESOURCE_USAGE system trace 快照 后台 CPU 异常、死循环、线程池失控
TRIGGER_TYPE_ANOMALY 系统检测到异常行为,例如 binder 调用过多、内存使用过高等 随异常类型变化,可能是 heap dump 或 stack sampling profile 系统检测到的资源异常、潜在稳定性问题
TRIGGER_TYPE_APP_COMPAT 系统检测到未来版本可能不再支持的异常行为 随兼容性问题变化 提前发现兼容性风险

这里需要特别注意 TRIGGER_TYPE_APP_FULLY_DRAWN。它依赖应用调用 Activity.reportFullyDrawn(),如果应用从来不调用这个方法,系统也就无法在这个点建立有效触发。也就是说,启动性能治理不仅是注册 trigger,还需要把启动完成信号上报规范化。

Android 17 新增的几个触发器里,最值得优先关注的是 TRIGGER_TYPE_COLD_STARTTRIGGER_TYPE_OOMTRIGGER_TYPE_ANOMALY

TRIGGER_TYPE_COLD_STARTAPP_FULLY_DRAWN 的区别在于,它的触发时间更早。系统会尽可能在冷启动早期开始采集,直到应用调用 reportFullyDrawn(),如果应用没有调用,则默认约 5 秒后停止。这个 trigger 使用 discard buffer,缓冲区满时会丢弃较新的事件,从而尽量保留最早期的 tracepoint。这对分析启动早期问题很有价值。

TRIGGER_TYPE_OOM 的产物是 Java heap dump。不过它有一个前提:如果应用自定义了 Thread.UncaughtExceptionHandler,需要继续调用默认的 uncaught exception handler。否则系统无法基于该 trigger 自动提供 heap dump,只能由应用自己调用 requestProfiling() 采集。

TRIGGER_TYPE_ANOMALY 更像是系统侧的异常检测入口。Android 17 引入设备端异常检测服务,用于监控资源密集行为和潜在兼容性回归。例如 binder 调用过多、内存使用过高等问题,都可能通过该 trigger 反馈给应用。实际落地时,可以结合 resultFilePath 对应的 profiling 产物、应用自身上下文和平台侧异常记录做进一步分类。

2.3 基本接入方式

触发器的接入可以概括为两步:

  1. 尽早注册全局 profiling 结果回调。
  2. 构建触发器列表,并通过 addProfilingTriggers() 添加到系统。

下面这段代码按照"先注册回调,再添加触发器"的方式组织。需要注意,ProfilingTrigger.Builder 的构造参数就是 trigger type,不是先创建 Builder 再调用 setTriggerType();结果回调中使用的是 resultFilePath,不是 traceFile

kotlin 复制代码
class App : Application() {

    override fun onCreate() {
        super.onCreate()

        if (Build.VERSION.SDK_INT < 37) return

        // 在 Application.onCreate() 中尽早注册
        val pm = getSystemService(ProfilingManager::class.java)
        val mainExecutor = Executors.newSingleThreadExecutor()

        // Step 1: 注册全局结果回调
        pm.registerForAllProfilingResults(mainExecutor) { result ->
            if (result.errorCode == ProfilingResult.ERROR_NONE) {
                // 字段名是 resultFilePath,不是 traceFile
                uploadToAnalytics(result.resultFilePath)
            } else {
                // 记录 result.errorCode 和 result.errorMessage,便于排查采集失败原因
            }
        }

        // Step 2: 添加触发器,Builder 把 type 作为构造参数
        val triggers = listOf(
            ProfilingTrigger.Builder(
                ProfilingTrigger.TRIGGER_TYPE_COLD_START
            ).build(),
            ProfilingTrigger.Builder(
                ProfilingTrigger.TRIGGER_TYPE_OOM
            ).build(),
            ProfilingTrigger.Builder(
                ProfilingTrigger.TRIGGER_TYPE_KILL_EXCESSIVE_CPU_USAGE
            ).build()
        )

        pm.addProfilingTriggers(triggers)
    }
}

这里的代码只表达接入结构。真实项目中还需要根据 compileSdk、API 可用性、采集文件大小、上传时机、隐私合规、失败重试等做完整封装。如果还需要兼容 API 36/36.1,可以把 TRIGGER_TYPE_ANRTRIGGER_TYPE_APP_FULLY_DRAWN 等触发器放到对应的版本判断分支中。

2.4 结果文件如何处理

触发式 profiling 产物会保存到应用数据目录中,文件名大致遵循下面的形式:

text 复制代码
profile_trigger_<profile_type_code>_<datetime>.<profile-type-name>

例如 system trace 可能是 .perfetto-trace 文件。应用在回调中可以通过 ProfilingResult.getResultFilePath() 拿到保存路径,再决定是否上传或本地保留。

从工程落地角度看,如果要把这类结果接入 APM 平台,不建议只上传一个孤立文件。更实用的做法是同时记录:

  1. profiling 文件路径和文件大小
  2. errorCodeerrorMessage 等采集结果信息
  3. 应用版本、渠道、进程名
  4. Android 版本、设备型号、厂商
  5. 当前页面、启动阶段、登录状态等业务上下文
  6. 最近一次异常、ANR、Crash、OOM、应用退出原因

这样后续才能把系统级 profiling 文件和业务现场关联起来。

另外,接入时建议控制采集频率和上传策略。比如合理设置 setRateLimitingPeriodHours(),避免高频触发器消耗过多系统配额;对 trace、heap dump 等文件做大小限制、压缩、过期清理和隐私脱敏;上传时尽量放到后台任务中处理,不要在主线程直接读取大文件。

这一部分属于工程化扩展建议,核心还是围绕一个目标:把线上问题发生前后的系统现场尽可能带回来。Android 17 新增的 OOM、冷启动、异常检测、CPU 过高终止等触发器,正好补上了过去线上问题排查中最缺的几类现场数据。

3、大屏适配进一步强制化

Android 近几个版本持续推动大屏适配。这里的大屏不只是传统平板,还包括折叠屏、横屏设备、桌面模式、分屏窗口等形态。

过去很多应用为了省事,会在 Manifest 中写死竖屏,或者在代码中强制设置方向。这样在手机上看起来问题不大,但在宽屏设备上经常出现两边大面积留白、内容被强行居中、窗口体验割裂等问题。

Android 16 和 Android 17 正在逐步收紧这类行为。

3.1 方向和尺寸限制逐步失效

在宽度大于约 600dp 的设备上,应用通过 Manifest 或代码强制设置屏幕方向的方式会逐步失效。

Android 16 阶段还提供了一些兼容配置来绕过,但 Android 17 中限制更强,开发者不能继续依赖"强制竖屏"逃避大屏适配。

这意味着,如果应用没有做好自适应布局,在 Android 17 大屏设备上可能出现:

  1. 页面被强制拉伸
  2. 横屏布局比例异常
  3. 折叠屏展开后内容不适配
  4. 分屏窗口中控件拥挤或留白
  5. Activity 重建导致状态丢失

3.2 推荐使用 Window Size Class

大屏适配不应该只靠判断横竖屏,更应该基于窗口尺寸和设备折叠状态做布局决策。

Jetpack Window 相关库提供了 WindowSizeClass 等能力,可以根据当前窗口宽度、高度、折叠状态来决定页面结构。

例如:

  1. Compact 宽度下使用单栏布局。
  2. Medium 宽度下适当增加侧栏或双栏。
  3. Expanded 宽度下展示列表 + 详情、多面板布局。
  4. 折叠屏根据 hinge 状态避开折痕区域。

这类适配比单纯判断 orientation == landscape 更可靠。

3.3 状态保存问题

大屏适配中还有一个容易被忽略的问题:配置变更导致的数据丢失。

当设备旋转、折叠、展开、进入分屏、调整窗口大小时,Activity 可能重建。如果页面状态只保存在普通内存变量里,就可能在重建后丢失。

不同技术栈可以采用不同方式:

  1. Compose 中使用 rememberSaveable 保存可恢复状态。
  2. 复杂业务状态放入 ViewModel
  3. 必须跨进程或跨重启保留的数据写入本地存储。
  4. 页面输入、滚动位置、筛选条件等需要明确设计恢复策略。

这里的关键不是"阻止重建",而是让重建后页面仍能恢复到合理状态。

3.4 相机场景需要额外关注

相机类应用在大屏和方向适配中更容易踩坑。

原因是相机传感器方向、设备方向、预览 View 方向之间存在映射关系。过去如果应用强制竖屏,可能可以绕过一些复杂情况。但当系统不再允许应用简单锁定方向后,预览画面可能出现拉伸、旋转错误或比例异常。

相机预览类业务建议优先考虑迁移到 CameraX Preview 等官方封装能力,让官方库处理更多传感器方向和预览变换问题。

3.5 建议的验证方式

大屏适配不能只靠代码 review,需要真机或模拟器验证。建议至少覆盖:

  1. 普通手机竖屏
  2. 普通手机横屏
  3. 平板横屏
  4. 折叠屏折叠态
  5. 折叠屏展开态
  6. 分屏模式
  7. 可调整窗口大小的桌面模式

如果短期无法完整适配,至少要先把核心链路跑通,避免首页、登录、支付、播放、编辑等关键路径在大屏上出现明显错乱。

4、后台音频限制加强

Android 17 对后台音频行为也做了更严格的限制。这部分对音乐、播客、有声书、语音房、导航、车载音频等应用影响较大。

4.1 为什么要限制后台音频

后台音频问题在用户侧很容易造成糟糕体验。

例如:

  1. 用户把应用切到后台后,音频突然停止。
  2. 应用已经很久没打开,却在某个时间突然播放。
  3. 后台播放断断续续。
  4. 应用抢占音频焦点后没有释放,影响其他播放器。
  5. 没有前台服务却试图持续播放,导致资源不足或被系统限制。

这些问题的共同点是:应用在用户没有明确感知或授权的情况下,继续执行音频相关操作。

Android 17 的思路是要求应用证明自己的音频行为是用户可感知、用户触发或前台服务承载的。

4.2 对所有应用的限制

不管应用的 targetSdkVersion 是否达到 Android 17 对应版本,只要运行在 Android 17 上,后台音频相关操作都需要满足一定条件。

应用在后台尝试播放音频、获取音频焦点、调整音量时,通常需要满足以下条件之一:

  1. 应用当前有可见 Activity。
  2. 应用有合规的前台服务,且服务类型不是短时服务。

换句话说,要么应用在前台,要么后台确实有一个合规且用户可感知的前台服务支撑播放。

4.3 对 targetSdkVersion 37 的更严格要求

如果应用 targetSdkVersion 达到 37,限制会进一步加强。

这时即使应用启动了前台服务,也要求前台服务的启动与用户操作相关。例如:

  1. 用户点击播放按钮。
  2. 用户点击通知栏中的播放操作。
  3. 应用可见状态下触发播放。

如果应用在后台收到推送、广播或其他系统事件后,直接启动前台服务并播放音频,就可能被系统阻止。

这对过去依赖后台广播自动恢复播放、自动拉起服务的应用影响比较大。

4.4 前台服务类型必须声明正确

音频播放服务需要在 Manifest 中声明正确的前台服务类型,例如 mediaPlayback

不建议使用宽泛或不匹配的类型,更不能用 shortService 这类短时服务类型承载长时间播放。

示例:

xml 复制代码
<service
    android:name=".player.PlaybackService"
    android:exported="false"
    android:foregroundServiceType="mediaPlayback" />

如果类型声明不正确,通常不是编译期失败,而是在运行时播放行为受限,比如无法稳定播放、无法获取焦点或被系统限制资源。

4.5 推荐迁移到 MediaSessionService

音频类应用推荐使用 MediaSessionService 这类官方方案。

它的好处是,不只是满足后台播放限制,还能顺带处理:

  1. 通知栏播放控制
  2. 锁屏播放控制
  3. 蓝牙耳机控制
  4. 车载系统集成
  5. 音频焦点管理
  6. 播放状态同步

如果应用仍在使用老的 MediaPlayer + 普通 Service 方式后台播放,就需要尽快评估迁移成本。

推荐的启动链路应该是从用户明确操作开始,例如用户点击播放按钮时启动媒体播放前台服务:

kotlin 复制代码
class PlayerActivity : AppCompatActivity() {

    fun onPlayButtonClick() {
        ContextCompat.startForegroundService(
            this,
            Intent(this, MusicPlaybackService::class.java)
        )

        // 后续通过 MediaController 控制播放
    }
}

对应的服务需要在 Manifest 中声明为媒体播放类型:

xml 复制代码
<service
    android:name=".MusicPlaybackService"
    android:exported="false"
    android:foregroundServiceType="mediaPlayback" />

不推荐的方式,是在用户不可见、非用户触发的后台场景中直接拉起播放服务。例如监听开机广播后自动启动前台服务:

kotlin 复制代码
class BootReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
            // Android 17 下后台启动前台服务会被静默阻止
            context.startForegroundService(
                Intent(context, MusicPlaybackService::class.java)
            )
        }
    }
}

这里有三个点需要特别注意:

  1. FGS 类型 :Manifest 中要设置 mediaPlayback,不要用 shortService 承载长时间音频播放。
  2. 启动时机:前台服务必须由用户操作或应用可见状态触发,后台广播、推送等自动拉起方式风险很高。
  3. 失败检测:请求音频焦点、启动服务或恢复播放时,要明确处理失败返回值,不能默认一定成功。

4.6 音频焦点丢失时不要轻易 stop

这里还有一个容易忽略的细节:处理音频焦点丢失时,最好不要直接 stop 播放器或 stopSelf() 停掉服务。

更合适的做法通常是先 pause。这样前台服务和播放会话状态仍然可以保留,后续用户恢复播放时更容易继续维持合规状态。

只有在永久丢失焦点,或者用户明确停止播放时,才考虑真正停止前台服务。

可以简单理解为:

  1. 临时失焦:暂停播放。
  2. 永久失焦:停止播放并释放资源。
  3. 用户主动停止:停止前台服务。
  4. 后台自动恢复:谨慎处理,避免违反用户触发要求。

5、适配优先级建议

如果项目准备适配 Android 17,可以按优先级拆成几类任务。

5.1 所有应用都建议做

  1. 检查是否反射访问 MessageQueue 内部字段。
  2. 升级 Espresso、Robolectric 等测试依赖。
  3. 检查三方 APM、卡顿监控 SDK 的 Android 17 兼容性。
  4. 在大屏模拟器或折叠屏模拟器上跑核心链路。
  5. 检查 Activity 重建后的状态恢复。

5.2 性能和稳定性团队建议做

  1. 调研并接入 ProfilingManager
  2. 建立 profiling 文件上传和解析链路。
  3. 针对 ANR、OOM、CPU 过高等问题建立专项采集策略。
  4. 将系统版本、设备型号、应用版本与 profiling 数据关联。

5.3 大屏相关应用建议做

  1. 引入 Jetpack Window 相关能力。
  2. WindowSizeClass 替代简单横竖屏判断。
  3. 针对平板、折叠屏、分屏设计多栏布局。
  4. 对相机、地图、视频、编辑器等页面做专项验证。

5.4 音频类应用必须重点关注

  1. 检查后台播放是否依赖普通 Service
  2. 前台服务类型是否声明为 mediaPlayback
  3. 播放服务是否由用户操作触发。
  4. 音频焦点丢失时是否错误调用 stopstopSelf()
  5. 评估迁移到 MediaSessionService 或 Media3。

6、总结

Android 17 的这些变化表面上看分散在不同模块,但背后的方向是一致的:

  1. Framework 内部减少历史包袱,提高性能。
  2. 系统提供更强的线上问题诊断能力。
  3. 推动应用适配多设备、多窗口、大屏形态。
  4. 收紧后台行为,让用户可感知、可控制。

对于普通业务开发来说,最先要做的是兼容性排查,尤其是 MessageQueue 反射、大屏布局、后台服务这几类问题。

对于负责架构、性能、稳定性的开发者来说,ProfilingManager 值得重点关注。它可能会成为后续 Android 线上问题治理中很重要的一块基础能力。

对于音频类应用来说,Android 17 的后台音频限制不是简单的 API 变化,而是播放架构和用户触发链路的重新梳理。越早迁移到官方推荐的媒体会话体系,后续适配成本越低。

新系统适配这件事,短期看像是额外工作,长期看其实是在替应用还技术债。尤其是大屏和后台服务这两类变化,已经不是"以后有空再说"的优化项,而是会直接影响用户体验和应用稳定性的基础工程。

7、参考资料

  1. ProfilingManager API Reference
  2. ProfilingTrigger API Reference
  3. Trigger-based profiling
  4. Android 17 features - new ProfilingManager triggers
相关推荐
YM52e9 小时前
鸿蒙 Flutter 渐变效果详解:LinearGradient、RadialGradient、SweepGradient
android·学习·flutter·华为·harmonyos·鸿蒙
-SOLO-10 小时前
Android 内存压力工具
android
雅客李10 小时前
2026云手机延迟数据测评 安卓云手机远程操控实测哪个最好
android·智能手机
YM52e11 小时前
鸿蒙Flutter Card组件:Material设计风格卡片
android·学习·flutter·华为·harmonyos·鸿蒙
Xzaveir1 天前
不要用一个状态表示“号码已认证”:企业号码身份的四域模型
android·人工智能
(Charon)1 天前
【C++】手写 MySQL 连接池(二):同步连接的获取、加锁与释放
android
zhangjin11201 天前
AOSP下载
android
Mico181 天前
MySQL 8.0.35 GTID 主从复制搭建-基于GITD
android·mysql·adb
YXL1111YXL1 天前
LeakCanary 源码解析检测泄露工作机制(一)
android·leakcanary