【Android原生问题分析】夸克、抖音划动无响应问题【Android14】

news2024/11/19 22:45:25

在这里插入图片描述

1 问题描述

偶现问题,用户打开夸克、抖音后,在界面上划动无响应,但是没有ANR。回到Launcher后再次打开夸克/抖音,发现App的界面发生了变化,但是仍然是划不动的。

2 log初分析

复现问题附近的log为:

在这里插入图片描述

用户打开夸克的时间点为“00:27:25”左右,然后是持续的划动无响应,最后在“00:27:36”最后退出了夸克。

现在基本上已经没有冻屏的操作了,从log中也没有看到可能的痕迹,并且根据用户的描述,在夸克界面上划动无响应,切换到别的界面后再切回夸克,看到夸克的界面是有更新的,说明应该是在绘制或者合成的地方卡住了。

由于默认的log有限,无法定位到具体的问题,因此需要添加log。

3 第一次添加log

由于不确定是哪个阶段出了问题,因此先针对Input流程和measure、layout以及draw流程添加了log,后面测试再次复现问题后,查看log发现问题出在draw流程(其实从问题描述上也能看出来,从App切换到Launcher再切换回App,界面发生了变化,说明输入事件应该是被App正确接收到了)。

第一帧正常:

在这里插入图片描述

从第二帧开始异常:

在这里插入图片描述

异常的点在ViewRootImpl.performDraw:

在这里插入图片描述

这里就是问题的直接原因了,明明是亮屏状态,但是ViewRootImpl.mAttachInfo.mDisplayState保存的值却是Display.STATE_OFF,导致代码误判断此时处于灭屏状态,因此不会继续走绘制流程。

至于为什么第一帧有没问题,而从第二帧开始就出问题了,因为第一帧的时候,ViewRootImpl.mReportNextDraw为true,所以没有提前return,可以继续走draw流程。而从第二帧开始,ViewRootImpl.mReportNextDraw就变成了false,导致代码提前返回。

搜索代码,AttachInfo.mDisplayState赋值的地方只有四处:

1、View.dispatchMovedToDisplay

2、ViewRootImpl.onMovedToDisplay

3、ViewRootImpl.setView

4、ViewRootImpl.mDisplayListener.onDisplayChanged

前两处是跟移动到新的Display相关的,可以排除,第3处是窗口首次添加,也可以排除,那么就只有第4处是Display状态改变后,更新AttachInfo.mDisplayState的地方。

另外根据本地调试也的确如此,当发生亮灭屏时,触发的是ViewRootImpl.mDisplayListener.onDisplayChanged:

DisplayManagerGlobal.DisplayManagerCallback.onDisplayEvent

-> DisplayManagerGlobal.handleDisplayEvent

-> DisplayManagerGlobal.DisplayListenerDelegate.sendDisplayEvent

在这里插入图片描述

最终的调用起点在系统进程的DisplayManagerService。

由于之前对DisplayManagerService了解比较少,所以还不清楚问题出在哪儿,这次加的log不太够,需要继续在DisplayManagerService处加log,然后让测试帮忙去复现问题。

但是同时别的同事也合入了几个google的patch,导致后续问题复现不到了,这个问题一度没有了下文,当时觉得还挺可惜,花了挺长的时间去分析,结果后面复现不到了。

4 第二次添加log

虽然之前的问题不了了之了,但是后面别的项目又继续复现了该问题,希望又被点燃了…先在DisplayManagerService中添加一些log,然后继续让测试同事帮忙复现,最终成功复现到了问题。

以下是当时的log分析:

4.1 11-12 22:25:14 - 第一次启动抖音

在这里插入图片描述

这个是后续发生问题的抖音界面第一次启动的时间,此时是正常的。

中间又多次启动抖音以及亮灭屏,但是都没有问题,所以我们跳过这些阶段。

直接看发生问题前的那次启动抖音的情况。

4.2 11-13 10:33:39 - 再次启动抖音

在这里插入图片描述

ViewRootImpl保存的DisplayState已经是2了,即Display.STATE_ON,这次绘制没有问题。

4.3 11-13 10:53:42 - 灭屏

在这里插入图片描述

此次DisplayManagerService向SplashActivity对应进程“17885”进行了通知。

最终抖音对应进程“17885”也打印了相应的onDisplayChanged的log。

4.4 11-13 10:55:07 - 亮屏

在这里插入图片描述

DisplayManagerService没有通知抖音对应进程“17885”,有以下log打印:

11-13 10:55:07.252351  1450  1575 I DisplayManagerService: DisplayManagerService.deliverDisplayEvent: isUidCached=10224
11-13 10:55:07.252761  1450  1575 I DisplayManagerService: DisplayManagerService.deliverDisplayEvent: isUidCached=10224
11-13 10:55:07.253925  1450  1575 D DisplayManagerService: Ignore redundant display event 0/2 to 10224/16998
11-13 10:55:07.253967  1450  1575 I DisplayManagerService: DisplayManagerService.deliverDisplayEvent: isUidCached=10224
11-13 10:55:07.253978  1450  1575 D DisplayManagerService: Ignore redundant display event 0/2 to 10224/16998

4.5 11-13 10:55:16 - 灭屏

在这里插入图片描述

DisplayManagerService没有通知抖音对应进程“17885”。

4.6 11-13 13:00:00 - 出现问题前的最后一次亮屏

在这里插入图片描述

DisplayManagerService还是没有通知抖音对应进程“17885”。

4.7 11-13 13:24:18 - 再次启动抖音,有问题

在这里插入图片描述

原因则是“11-13 10:53:42”那次灭屏DisplayManagerService通知到了抖音对应进程“17885”,随后不管是亮屏还是灭屏都没有再通知抖音进程,导致此次启动抖音SplashActivity后,其ViewRootImpl处保存的DisplayState还是1,即Display.STATE_OFF,灭屏状态,所以不会走绘制流程。

接下来需要看下具体的代码,为什么没有通知到抖音进程,并且打印了这些log:

11-13 10:55:07.252351  1450  1575 I DisplayManagerService: DisplayManagerService.deliverDisplayEvent: isUidCached=10224
11-13 10:55:07.252761  1450  1575 I DisplayManagerService: DisplayManagerService.deliverDisplayEvent: isUidCached=10224
11-13 10:55:07.253925  1450  1575 D DisplayManagerService: Ignore redundant display event 0/2 to 10224/16998
11-13 10:55:07.253967  1450  1575 I DisplayManagerService: DisplayManagerService.deliverDisplayEvent: isUidCached=10224
11-13 10:55:07.253978  1450  1575 D DisplayManagerService: Ignore redundant display event 0/2 to 10224/16998

5 代码分析

5.1 App侧注册display状态的监听

ViewRootImpl有一个DisplayListener的成员变量mDisplayListener,该成员变量用来接收DisplayManagerService关于Display状态改变的通知:

在这里插入图片描述

当onDisplayChanged回调触发,会更新mAttachInfo.mDisplayState的值。

该成员变量通过DisplayManagerGlobal.registerDisplayListener进行注册,最终是调用了IDisplayManager.registerCallbackWithEventMask,跨进程在DisplayManagerService进行了注册,如下图:

在这里插入图片描述

DisplayManagerService内部类BinderService是IDisplayManager的本地实现,然后BinderService.registerCallbackWithEventMask又调用了DisplayManagerService.registerCallbackInternal:

在这里插入图片描述

最终,DisplayManagerService为每一个通过IDisplayManager.registerCallbackWithEventMask监听Display状态的客户端,都创建了一个CallbackRecord对象,用来代表一个客户端记录,该CallbackRecord被保存在DisplayManagerService的成员变量mCallbacks中。

至于CallbackRecord,其内部保存了客户端的pid和uid,因此可以唯一对应一个客户端。

5.2 DisplayManagerService通知客户端Display状态改变

直接放结论,在CallbackRecord.notifyDisplayEventAsync中:

在这里插入图片描述

CallbackRecord中的IDisplayManagerCallback类型的成员变量mCallback保存的是客户端进程传过来的IDisplayManagerCallback代理,因此调用IDisplayManagerCallback.onDisplayEvent最终可以调用到客户端进程的DisplayManagerGlobal:

在这里插入图片描述

最终通知到ViewRootImpl。

CallbackRecord.notifyDisplayEventAsync方法调用的地方有两处,先看第一处,在DisplayManagerService.deliverDisplayEvent:

在这里插入图片描述

这里会将DisplayManagerService.mCallbacks的数据拷贝到DisplayManagerService.mTempCallbacks,然后调用DisplayManagerService.isUidCached方法来判断需要通知的进程是否处于cached mode:

在这里插入图片描述

如果不是,那么说明此时该客户端进程的优先级比较高,需要直接调用CallbackRecord.notifyDisplayEventAsync来通知客户端Display状态改变的消息。

如果客户端进程处于cached mode,那么说明该进程处于一个优先级较低的状态,因此不会立即调用CallbackRecord.notifyDisplayEventAsync,而是创建一个PendingCallback对象,然后保存到DisplayManagerService的mPendingCallbackSelfLocked成员变量中,注意这里mPendingCallbackSelfLocked是根据uid去区分的,并非是pid。

等到客户端进程的进程优先级提高后,再去从DisplayManagerService.mPendingCallbackSelfLocked中取出相应的CallbackRecord,然后调用CallbackRecord.notifyDisplayEventAsync方法通知客户端进程,这也就是第二处调用CallbackRecord.notifyDisplayEventAsync的地方,在PendingCallback.sendPendingDisplayEvent:

在这里插入图片描述

而PendingCallback.sendPendingDisplayEvent方法则由UidImportanceListener.onUidImportance方法调用。

这里的逻辑很好理解,当进程的优先级改变的时候,会回调UidImportanceListener.onUidImportance,然后UidImportanceListener.onUidImportance中继续判断该进程的优先级,如果优先级高于IMPORTANCE_CACHED,那么会继续根据该进程的uid从DisplayManagerService.mPendingCallbackSelfLocked中找其对应的PendingCallback,如果能找到,那么调用PendingCallback.sendPendingDisplayEvent,最终在PendingCallback.sendPendingDisplayEvent中调用CallbackRecord.notifyDisplayEventAsync来通知客户端Display状态的改变。

5.3 省流版

概括一点说,就是并不是每次Display状态发生变化的时候,DisplayMangerService就会去通知抖音进程,而是会调用DisplayManagerService.isUidCached方法来看这个App进程的优先级是否足够高:

1)、如果优先级高于IMPORTANCE_CACHED,说明此时优先级还是挺高的,那么DisplayManagerService会立即通知抖音进程。

2)、如果优先级等于或者低于IMPORTANCE_CACHED,说明优先级不够高,那么DisplayManagerService不会立即通知抖音进程,而是为其创建一个记录,等到抖音进程的优先级改变并且高于IMPORTANCE_CACHED的时候,根据这个记录找到抖音进程,然后通知它。

6 原因分析

1)、首先是这次:”11-13 10:33:39 - 再次启动抖音“

这是离问题发生时间点最近的那次启动抖音。

2)、然后接着:”11-13 10:53:42 - 灭屏“

看到这次灭屏的时候,可能是由于距离启动抖音的时间不长,因此这时抖音进程的优先级还比较高,所以这次灭屏的时候,通知到了抖音进程17885。

3)、接着是”11-13 10:55:07 - 亮屏“

这里我们之前的分析有误,看了代码后才了解,不是说DisplayManagerService没有通知抖音进程17885,而是抖音进程的优先级比较低,所以没有立即通知抖音进程,而是为其创建了PendingCallback,等待抖音进程优先级提高后,再去通知抖音进程,如这里的log:

在这里插入图片描述

但是这里的逻辑有问题。

如log中显示的,这里抖音App的uid为10224,有三个进程,16998,17885,18213,我们关注的抖音的”SplashActivity”所在进程是17885.

然后再看代码:

在这里插入图片描述

首先对于抖音进程16998,由于这是遍历到的抖音的第一个进程,因此DisplayManagerService.mPendingCallbackSelfLocked中是没有抖音uid的信息的,所以这里会基于进程16998对应的CallbackRecord创建一个PendingCallback对象,然后保存到DisplayManagerService.mPendingCallbackSelfLocked中。

然后遍历到抖音进程17885的时候,由于它和抖音进程16998的uid是一样的,都是10224,那么这里就不会为进程17885再去创建一个PendingCallback对象, 而是直接复用上一步创建的那个PendingCallback,如这里的log打印:

”Ignore redundant display event…“

那么这里就是问题的根因所在了,抖音有三个进程,这里只为抖音进程16998对应的CallbackRecord创建了一个PendingCallback,到后续抖音进程优先级提高的时候,那么也只会调用该PendingCallback中的CallbackRecord的notifyDisplayEventAsync方法,那么这意味着只有进程16998会得到Display状态改变的通知,进程17885和进程18213都无法得到通知,再看后面抖音进程优先级提升的情况:

在这里插入图片描述

看到果然只有进程16998得到通知了,我们关注的进程17885没有被通知到,那么进程17885的ViewRootImpl保存的mAttachInfo.mDisplayState将一直是灭屏的状态。

不太省流的省流版

目前的代码,在一个App对应一个uid,以及一个pid的情况下,是够用的,但是实际上一个App对应了一个uid,但是可能会有多个进程,即一个uid会对应多个pid。

再回看我们的代码总结:如果App优先级等于或者低于IMPORTANCE_CACHED,说明优先级不够高,那么DisplayManagerService不会立即通知抖音进程,而是为其创建一个记录,等到抖音进程的优先级改变并且高于IMPORTANCE_CACHED的时候,根据这个记录找到抖音进程,然后通知它。

这里创建的记录,是根据uid去创建的,那么即使抖音有多个进程,也只会创建一个记录,根据遍历顺序来看则是pid最小的那个。

再看问题场景:

1)、启动完抖音后灭屏,此时抖音的优先级比较高,因此DisplayMangerService会立即通知抖音进程,这里抖音的三个进程都能通知到,因此进程17885的ViewRootImpl处保存的Display状态就是灭屏状态。

2)、过了一阵子再次亮屏,由于抖音的优先级降低了,所以DisplayManagerService没有立即通知抖音进程,而是创建为抖音创建了一个记录,等到抖音优先级提高的时候,再去通知抖音进程。此时抖音有三个进程,16998,17885,18213,这里只为pid最小的16998创建了一项纪录。

3)、后续抖音优先级提高的时候,DisplayMangerService只通知了进程16998,由于没有为剩下的两个进程创建记录,因此这两个进程就通知不到了,所以我们关注的进程17885出了问题。

从以上分析可以知道,我们需要为每一个pid都创建一个记录,而非每一个uid。

7 问题解决

最终看到已经有google patch解决这个问题了:

Diff - f2daa46634f6a1e5e329041f07a27dbc894d71b2^! - platform/frameworks/base - Git at Google

Correct the deferred sending of display events.

When multiple processes sharing the same uid become non-cached, the
current deferred transmission logic does not consider all of them,
leading to only the first process in the callback list to receive the
pending display events. Moreover, this first process may inadvertently
receive unintended display events.

Bug: 325692442
Test: manual, see bug description

Change-Id: Ife98a8d843a3000294fbc9929bb78a755534b5dc
Signed-off-by: Hyeongseop Shim <hyeongseop.shim@samsung.corp-partner.google.com>

diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ba21a32..434985e 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java

@@ -464,10 +464,11 @@
     // May be used outside of the lock but only on the handler thread.
     private final ArrayList<CallbackRecord> mTempCallbacks = new ArrayList<CallbackRecord>();
 
-    // Pending callback records indexed by calling process uid.
+    // Pending callback records indexed by calling process uid and pid.
     // Must be used outside of the lock mSyncRoot and should be selflocked.
     @GuardedBy("mPendingCallbackSelfLocked")
-    public final SparseArray<PendingCallback> mPendingCallbackSelfLocked = new SparseArray<>();
+    public final SparseArray<SparseArray<PendingCallback>> mPendingCallbackSelfLocked =
+            new SparseArray<>();
 
     // Temporary viewports, used when sending new viewport information to the
     // input system.  May be used outside of the lock but only on the handler thread.
@@ -1011,8 +1012,8 @@
                 }
 
                 // Do we care about this uid?
-                PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
-                if (pendingCallback == null) {
+                SparseArray<PendingCallback> pendingCallbacks = mPendingCallbackSelfLocked.get(uid);
+                if (pendingCallbacks == null) {
                     return;
                 }
 
@@ -1020,7 +1021,12 @@
                 if (DEBUG) {
                     Slog.d(TAG, "Uid " + uid + " becomes " + importance);
                 }
-                pendingCallback.sendPendingDisplayEvent();
+                for (int i = 0; i < pendingCallbacks.size(); i++) {
+                    PendingCallback pendingCallback = pendingCallbacks.valueAt(i);
+                    if (pendingCallback != null) {
+                        pendingCallback.sendPendingDisplayEvent();
+                    }
+                }
                 mPendingCallbackSelfLocked.delete(uid);
             }
         }
@@ -3193,16 +3199,23 @@
         for (int i = 0; i < mTempCallbacks.size(); i++) {
             CallbackRecord callbackRecord = mTempCallbacks.get(i);
             final int uid = callbackRecord.mUid;
+            final int pid = callbackRecord.mPid;
             if (isUidCached(uid)) {
                 // For cached apps, save the pending event until it becomes non-cached
                 synchronized (mPendingCallbackSelfLocked) {
-                    PendingCallback pendingCallback = mPendingCallbackSelfLocked.get(uid);
+                    SparseArray<PendingCallback> pendingCallbacks = mPendingCallbackSelfLocked.get(
+                            uid);
                     if (extraLogging(callbackRecord.mPackageName)) {
-                        Slog.i(TAG,
-                                "Uid is cached: " + uid + ", pendingCallback: " + pendingCallback);
+                        Slog.i(TAG, "Uid is cached: " + uid
+                                + ", pendingCallbacks: " + pendingCallbacks);
                     }
+                    if (pendingCallbacks == null) {
+                        pendingCallbacks = new SparseArray<>();
+                        mPendingCallbackSelfLocked.put(uid, pendingCallbacks);
+                    }
+                    PendingCallback pendingCallback = pendingCallbacks.get(pid);
                     if (pendingCallback == null) {
-                        mPendingCallbackSelfLocked.put(uid,
+                        pendingCallbacks.put(pid,
                                 new PendingCallback(callbackRecord, displayId, event));
                     } else {
                         pendingCallback.addDisplayEvent(displayId, event);

看注释,说的就是多个进程共享同一个uid的情况。

再看修改,将原来的:

public final SparseArray<PendingCallback> mPendingCallbackSelfLocked = new SparseArray<>();

改为了:

    public final SparseArray<SparseArray<PendingCallback>> mPendingCallbackSelfLocked =
           new SparseArray<>();

很明显,之前是一个uid对应一个PendingCallback对象,现在是一个uid对应一组PendingCallback对象,即一个uid对应多个进程的情况,这样同一个uid下多个进程都能得到通知了,代码比较简单,不再赘述。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2243667.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

datawhale 2411组队学习:模型压缩4 模型量化理论(数据类型、int8量化方法、PTQ和QWT)

文章目录 一、数据类型1.1 整型1.2 定点数1.3 浮点数1.3.1 正规浮点数&#xff08;fp32&#xff09;1.3.2 非正规浮点数&#xff08;fp32&#xff09;1.3.3 其它数据类型1.3.4 浮点数误差1.3.5 浮点数导致的模型训练问题 二、量化基本方法2.1 int8量化2.1.1 k-means 量化2.1.2 …

ssm139选课排课系统的设计与开发+vue(论文+源码)_kaic

摘 要 互联网的普及&#xff0c;改变了人们正常的生活学习及消费习惯&#xff0c;而且也大大的节省了人们的时间&#xff0c;由于各种管理系统都再不断的增加&#xff0c;更方便了用户&#xff0c;也改良了很多的用户习惯。对于选课排课系统查询方面缺乏系统的管理方式&#x…

Datawhale组队学习】模型减肥秘籍:模型压缩技术3——模型量化

模型量化的目的是通过将浮点运算转换为定点运算&#xff0c;以减少模型大小、内存和存储需求&#xff0c;同时加快推理速度&#xff0c;降低计算功耗&#xff0c;使得模型在低算力设备上运行更加高效&#xff0c;特别适用于嵌入式设备或移动端场景。 不同数据类型&#xff08;…

【MongoDB】MongoDB的集群,部署架构,OptLog,集群优化等详解

文章目录 一、引入复制集的原因二、复制集成员&#xff08;一&#xff09;基本成员&#xff08;二&#xff09;主节点&#xff08;Primary&#xff09;细化成员 三、复制集常见部署架构&#xff08;一&#xff09;基础三节点&#xff08;二&#xff09;跨数据中心 四、复制集保…

Javaweb梳理17——HTMLCSS简介

Javaweb梳理17——HTML&CSS简介 17 HTML&CSS简介17.1 HTML介绍17.2 快速入门17.3 基础标签17.3 .1 标题标签17.3.2 hr标签17.3.3 字体标签17.3.4 换行17.3.8 案例17.3.9 图片、音频、视频标签17.3.10 超链接标签17.3.11 列表标签17.3.12 表格标签17.3.11 布局标签17.3.…

远程管理不再难!树莓派5安装Raspberry Pi OS并实现使用VNC异地连接

前言&#xff1a;大家好&#xff01;今天我要教你们如何在树莓派5上安装Raspberry Pi OS&#xff0c;并配置SSH和VNC权限。通过这些步骤&#xff0c;你将能够在Windows电脑上使用VNC Viewer&#xff0c;结合Cpolar内网穿透工具&#xff0c;实现长期的公网远程访问管理本地树莓派…

力扣 LeetCode 94. 二叉树的中序遍历(Day6:二叉树)

解题思路&#xff1a; 方法一&#xff1a;递归&#xff08;左中右&#xff09; class Solution {List<Integer> res new ArrayList<>();public List<Integer> inorderTraversal(TreeNode root) {recur(root);return res;}public void recur(TreeNode root…

MySQL查询执行(七):临时表

临时表重名 思考&#xff1a;临时表和内存表的区别? 内存表&#xff0c; 指的是使用Memory引擎的表&#xff0c; 建表语法是create table …enginememory。 这种表的数据都保存在内存里&#xff0c; 系统重启的时候会被清空&#xff0c; 但是表结构还在。 除了这两个特性看上…

自己动手写Qt Creator插件

文章目录 前言一、环境准备1.先看自己的Qt Creator IDE的版本2.下载源码 二、使用步骤1.参考原本的插件2.编写自定义插件1.cmakelist增加一个模块2.同理&#xff0c;qbs文件也增加一个3.插件源码 三、效果总结 前言 就目前而言&#xff0c;Qt Creator这个IDE&#xff0c;插件比…

【星海随笔】ZooKeeper-Mesos

开源的由 Twitter 与 伯克利分校的 Mesos 项目组共同研发设计。 两极调度架构 支持高可用集群&#xff0c;通过ZooKeeper进行选举。 Mesos master 管理着所有的 Mesos slave 守护进程 每个slave运行具体的任务或者服务。 Franework 包括的调度器和执行机两部分 执行器运行在Me…

集群聊天服务器(12)nginx负载均衡器

目录 负载均衡器nginx负载均衡器优势 如何解决集群聊天服务器跨服务器通信问题&#xff1f;nginx的TCP负载均衡配置nginx配置 负载均衡器 目前最多只能支持2w台客户机进行同时聊天 所以要引入集群&#xff0c;多服务器。 但是客户连哪一台服务器呢&#xff1f;客户并不知道哪一…

集群聊天服务器(3)muduo网络库

目录 基于muduo的客户端服务器编程 muduo只能装在linux中&#xff0c;依赖boost库 客户端并不需要高并发 基于muduo的客户端服务器编程 支持epoll线程池&#xff0c;muduo封装了线程池 而且还有完善的日志系统 使用muduo库代码非常固定&#xff0c;基本就只有chatserver的类名…

深入内核讲明白Android Binder【一】

深入内核讲明白Android Binder【一】 前言一、Android Binder应用编写概述二、基于C语言编写Android Binder跨进程通信Demo0. Demo简介1. 服务的管理者server_manager.c2. Binder服务端代码实现 test_service.c2.1 实现思路2.2 完整实现代码 3. Binder客户端代码实现 test_clie…

NIST 发布后量子密码学转型战略草案

美国国家标准与技术研究所 (NIST) 发布了其初步战略草案&#xff0c;即内部报告 (IR) 8547&#xff0c;标题为“向后量子密码标准过渡”。 该草案概述了 NIST 从当前易受量子计算攻击的加密算法迁移到抗量子替代算法的战略。该草案于 2024 年 11 月 12 日发布&#xff0c;开放…

探索大规模语言模型(LLM)在心理健康护理领域中的应用与潜力

概述 心理健康是公共卫生最重要的领域之一。根据美国国家精神卫生研究所&#xff08;NIMH&#xff09;的数据&#xff0c;到 2021 年&#xff0c;22.8% 的美国成年人将患上某种形式的精神疾病。在全球范围内&#xff0c;精神疾病占非致命性疾病负担的 30%&#xff0c;并被世界…

排序(C语言实现)

排序 文章目录 排序插入排序直接插入排序折半查找插入排序希尔排序 选择排序简单选择排序堆排序一、构建堆**堆有以下性质**&#xff1a;**堆的存储方式**&#xff1a;**设计堆**数据结构堆的维护堆的初始化创建堆插入一个元素删除一个元素返回有效元素的个数获得优先级最高的元…

i春秋-EXEC(命令执行、nc传输文件、带外通道传输数据)

练习平台地址 竞赛中心 题目描述 题目内容 小猫旁边有一个no sign F12检查页面 没有提示 检查源代码 发现使用了vim编辑器 进而联想到vim编辑器的临时交换文件.xxx.swp 访问.index.php.swp&#xff0c;成功下载文件 使用vim -r 查看文件内容 vim -r index.php.swp <?p…

移情别恋c++ ദ്ദി˶ー̀֊ー́ ) ——14.哈希(2)(模拟实现)

1.概念介绍 1.1开散列 开散列&#xff08;Open Hashing&#xff09;&#xff0c;也叫链地址法&#xff0c;是一种解决哈希冲突的方法。每个哈希表槽位保存一个链表&#xff0c;所有散列到同一位置的元素都存储在该链表中。当插入元素发生冲突时&#xff0c;将新元素添加到相应…

使用Web Speech API实现语音识别与合成技术

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Speech API实现语音识别与合成技术 使用Web Speech API实现语音识别与合成技术 使用Web Speech API实现语音识别与合成技…

自动驾驶系列—面向自动驾驶的模型迭代:工具、平台与最佳实践

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…