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

在这里插入图片描述

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 descriptionChange-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-cachedsynchronized (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.rhkb.cn/news/473274.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【STM32】MPU6050简介

文章目录 MPU6050简介MPU6050关键块带有16位ADC和信号调理的三轴MEMS陀螺仪具有16位ADC和信号调理的三轴MEMS加速度计I2C串行通信接口 MPU6050对应的数据手册&#xff1a;MPU6050 陀螺仪加速度计 链接: https://pan.baidu.com/s/13nwEhGvsfxx0euR2hMHsyw?pwdv2i6 提取码: v2i6…

【软件测试】设计测试用例的万能公式

文章目录 概念设计测试用例的万能公式常规思考逆向思维发散性思维万能公式水杯测试弱网测试如何进行弱网测试 安装卸载测试 概念 什么是测试用例&#xff1f; 测试⽤例&#xff08;Test Case&#xff09;是为了实施测试⽽向被测试的系统提供的⼀组集合&#xff0c;这组集合包…

使用 TensorFlow 实现 ZFNet 进行 MNIST 图像分类

ZFNet&#xff08;ZF-Net&#xff09;是由 Matthew Zeiler 和 Rob Fergus 提出的卷积神经网络架构&#xff0c;它在图像分类任务中取得了显著的效果。它在标准卷积神经网络&#xff08;CNN&#xff09;的基础上做了一些创新&#xff0c;例如优化了卷积核大小和池化策略&#xf…

如何让手机ip变成动态

在数字化浪潮中&#xff0c;手机已成为我们日常生活中不可或缺的一部分。无论是浏览网页、使用社交媒体还是进行在线购物&#xff0c;手机都扮演着举足轻重的角色。然而&#xff0c;在享受网络带来的便利时&#xff0c;我们也需要关注网络安全和隐私保护。静态IP地址可能让手机…

前端三大组件之CSS,三大选择器,游戏网页仿写

回顾 full stack全栈 Web前端三大组件 结构(html) 样式(css) 动作/交互(js) --- 》 框架vue&#xff0c;安哥拉 div 常用的标签 扩展标签 列表 ul/ol order——有序号 unordered——没序号的黑点 <!DOCTYPE html> <html><head><meta charset"…

CPU执行指令的过程

通过前面两篇文章的介绍&#xff0c;我们已经认识到了&#xff1a;可执行程序通过作业调度装入内存&#xff0c;操作系统为进程创建虚拟地址空间&#xff0c;分配物理内存&#xff0c;建立页表&#xff08;映射关系&#xff09;&#xff0c;申请并初始化PCB&#xff0c;开始调度…

【MySQL】InnoDB内存结构

目录 InnoDB内存结构 主要组成 缓冲池 缓冲池的作用 缓冲池的结构 缓冲池中页与页之间连接方式分析 缓冲池如何组织数据 控制块初始化 页面初始化 缓冲池中页的管理 缓冲区淘汰策略 查看缓冲池信息 总结 变更缓冲区-Chang Buffer 变更缓冲区的作用 主要配置选项…

论文笔记 SuDORMRF:EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION

SUDORMRF: EFFICIENT NETWORKS FOR UNIVERSAL AUDIO SOURCE SEPARATION 人的精神寄托可以是音乐&#xff0c;可以是书籍&#xff0c;可以是运动&#xff0c;可以是工作&#xff0c;可以是山川湖海&#xff0c;唯独不可以是人。 Depthwise Separable Convolution 深度分离卷积&a…

SpringBoot+React养老院管理系统 附带详细运行指导视频

文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码1.入住合同文件上传2.添加和修改套餐的代码3.查看入住记录代码 一、项目演示 项目演示地址&#xff1a; 视频地址 二、项目介绍 项目描述&#xff1a;这是一个基于SpringBootReact框架开发的养老院管理系统。首先…

w039基于Web足球青训俱乐部管理后台系统开发

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

Go 语言已立足主流,编程语言排行榜24 年 11 月

Go语言概述 Go语言&#xff0c;简称Golang&#xff0c;是由Google的Robert Griesemer、Rob Pike和Ken Thompson在2007年设计&#xff0c;并于2009年11月正式宣布推出的静态类型、编译型开源编程语言。Go语言以其提高编程效率、软件构建速度和运行时性能的设计目标&#xff0c;…

【java】链表:判断链表是否成环

问题&#xff1a; 分析&#xff1a; 这里我们还是定义快慢双指针 。 如果有环&#xff0c;快慢指针一定会相遇。 // 构建成环链表public void makeCircle(){Node node1new Node(1);Node node2new Node(2);Node node3new Node(5);Node node4new Node(6);Node node5new …

基于视觉智能的时间序列基础模型

GitHub链接&#xff1a;ViTime: A Visual Intelligence-Based Foundation Model for Time Series Forecasting 论文链接&#xff1a;https://github.com/IkeYang/ViTime 前言 作者是来自西安理工大学&#xff0c;西北工业大学&#xff0c;以色列理工大学以及香港城市大学的研…

006.精读《Apache Paimon Docs - Concepts》

文章目录 1. 引言2. 基本概念2.1 基本构成2.2 Schema2.3 Snapshot2.4 Manifest2.5 Data File2.6 Table2.7 File index 3.并发控制3.1 基本概念3.2 快照冲突3.3 文件冲突 4. 总结 1. 引言 在本期的技术深度解析中&#xff0c;我们将学习并且了解Apache Paimon 的基本概念&#…

RedHat7—Linux中kickstart自动安装脚本制作

本实验使用虚拟机版本为rhel7&#xff0c;从rhel7后的版本kickstart工具进行收费使用。 1.在VMware关闭dhcp自动获取ip地址功能 2.安装并启动httpd [rootlocalhost ~]# yum install httpd [rootlocalhost ~]# systemctl start httpd [rootlocalhost ~]#systemctl stop firewal…

数据集的重要性:如何构建AIGC训练集

文章目录 一、为什么数据集对AIGC如此重要&#xff1f;1. 数据决定模型的知识边界2. 数据质量直接影响生成效果3. 数据集多样性提升模型鲁棒性 二、构建AIGC训练集的关键步骤1. 明确目标任务和生成需求2. 数据源的选择3. 数据清洗与预处理4. 数据标注5. 数据增强 三、针对不同类…

结构化需求分析与设计

前言: 感觉书本上和线上课程, 讲的太抽象, 不好理解, 但软件开发不就是为了开发应用程序吗?! 干嘛搞这么抽象,对吧, 下面是个人对于软件开发的看法, 结合我的一些看法, 主打简单易懂, 当然,我一IT界小菜鸟, 对软件开发的认识也很浅显, 这个思维导图也仅仅是现阶段我的看…

docker-hub 无法访问,使用windows魔法拉取docker images再上传到linux docker环境中

云机的服务器是可以docker拉取镜像的&#xff0c;但是本地的虚拟机、物理服务器等网络环境不好的情况&#xff0c;是无法访问docker-hub的&#xff0c;即使更换了docker镜像源国内源也无法使用。 本文章使用 在魔法网络环境下的windows&#xff0c;下载docker images后&#xf…

LlamaIndex+本地部署InternLM实践

1.环境配置 1.1 配置基础环境 这里以在 Intern Studio 服务器上部署 LlamaIndex 为例。 首先&#xff0c;打开 Intern Studio 界面&#xff0c;点击 创建开发机 配置开发机系统 填写 开发机名称 后&#xff0c;点击 选择镜像 使用 Cuda11.7-conda 镜像&#xff0c;然后在资源…

MySql 日期周处理方式

MySql 日期周处理方式 最近在做数仓相关工作&#xff0c;最近遇到 几个问题&#xff0c; 1、计算指定日期是一年中的第几周&#xff0c;周一为周的第一天 2、计算周的开始时间&#xff0c;结束时间 3、计算周对应的年 比如 2023-01-01 WEEKOFYEAR(2023-01-01) 是2022年的52周&…