Android Native 之 文件系统挂载
一、文件系统挂载流程概述
二、文件系统挂载流程细节
1、Init启动阶段
众所周知,init进程为android系统的第一个进程,也是native世界的开端,要想让整个android世界能够稳定的运行,文件系统的创建和初始化是必不可少的,这个过程需要在android世界的前面。
//aosp/system/core/init/first_stage_init.cpp
int FirstStageMain(int argc, char** argv) {LOG(INFO) << "init first stage started!";//.....bool created_devices = false;if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {if (!IsRecoveryMode()) {//第一步:创建设备created_devices = DoCreateDevices();if (!created_devices) {LOG(ERROR) << "Failed to create device nodes early";}}StartConsole(cmdline);}//......//第二步:挂载设备if (!DoFirstStageMount(!created_devices)) {LOG(FATAL) << "Failed to mount required partitions early ...";}//.....
}
//aosp/system/core/init/first_stage_mount.cpp
// Public functions公共函数
// Creates devices and logical partitions from storage devices
bool DoCreateDevices() {auto fsm = FirstStageMount::Create();if (!fsm.ok()) {LOG(ERROR) << "Failed to create FirstStageMount: " << fsm.error();return false;}//来创建设备/即初始化磁盘逻辑分区return (*fsm)->DoCreateDevices();
}
// Mounts partitions specified by fstab in device tree.
bool DoFirstStageMount(bool create_devices) {// Skips first stage mount if we're in recovery mode.if (IsRecoveryMode()) {LOG(INFO) << "First stage mount skipped (recovery mode)";return true;}auto fsm = FirstStageMount::Create();if (!fsm.ok()) {LOG(ERROR) << "Failed to create FirstStageMount " << fsm.error();return false;}if (create_devices) {if (!(*fsm)->DoCreateDevices()) return false;}//来进行文件系统的挂载return (*fsm)->DoFirstStageMount();
}
//void SetInitAvbVersionInRecovery() 第三个public函数,看起来是和recovery有关系的
Init进程的通过FirstStageMount::Create()来拿到一个fsm对象,然后依次调用fsm的DoCreateDevices和DoFirstStageMount来初始化挂载文件系统。
1.1 FirstStageMount::Create读取fstab配置表
此步骤主要是读取fstab分区配置表,具体实现逻辑其实移交给了fs_mgr
//aosp/system/core/init/first_stage_mount.cpp
using android::fs_mgr::ReadDefaultFstab;
using android::fs_mgr::ReadFstabFromDt;
Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {//读取fstab配置表,此表配置了各个目录支持的文件系统相关配置auto fstab = ReadFirstStageFstab();if (!fstab.ok()) {return fstab.error();}return std::make_unique<FirstStageMountVBootV2>(std::move(*fstab));
}
static Result<Fstab> ReadFirstStageFstab() {Fstab fstab;//从DT里面获取,DT好像跟内核有关系,没有具体研究if (!ReadFstabFromDt(&fstab)) {//读取默认的fstab配置表if (ReadDefaultFstab(&fstab)) {fstab.erase(std::remove_if(fstab.begin(), fstab.end(),[](const auto& entry) { return !entry.fs_mgr_flags.first_stage_mount; }),fstab.end());} else {return Error() << "failed to read default fstab for first stage mount";}}return fstab;
}
fs_mgr被编译成为静态库lib_fs_mgr,这部分逻辑其实就是读取fstab.ini配置文件并进行解析:
//aosp/system/core/fs_mgr/fs_mgr_fstab.cpp
// Loads the fstab file and combines with fstab entries passed in from device tree.
bool ReadDefaultFstab(Fstab* fstab) {fstab->clear();ReadFstabFromDt(fstab, false /* verbose */);std::string default_fstab_path;// Use different fstab paths for normal boot and recovery boot, respectivelyif ((access("/sbin/recovery", F_OK) == 0) || (access("/system/bin/recovery", F_OK) == 0)) {//recovery模式下读取/etc/recovery.fstabdefault_fstab_path = "/etc/recovery.fstab";} else { //正常模式下读取类似于/odm/etc/fstab.default_fstab_path = GetFstabPath();}Fstab default_fstab;if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {for (auto&& entry : default_fstab) {fstab->emplace_back(std::move(entry));}} else {LINFO << __FUNCTION__ << "(): failed to find device default fstab";}return !fstab->empty();
}
// Return the path to the fstab file. There may be multiple fstab files; the
// one that is returned will be the first that exists of fstab.<fstab_suffix>,
// fstab.<hardware>, and fstab.<hardware.platform>. The fstab is searched for
// in /odm/etc/ and /vendor/etc/, as well as in the locations where it may be in
// the first stage ramdisk during early boot. Previously, the first stage
// ramdisk's copy of the fstab had to be located in the root directory, but now
// the system/etc directory is supported too and is the preferred location.
std::string GetFstabPath() {for (const char* prop : {"fstab_suffix", "hardware", "hardware.platform"}) {std::string suffix;if (!fs_mgr_get_boot_config(prop, &suffix)) continue;for (const char* prefix : {// late-boot/post-boot locations"/odm/etc/fstab.", "/vendor/etc/fstab.",// early boot locations"/system/etc/fstab.", "/first_stage_ramdisk/system/etc/fstab.","/fstab.", "/first_stage_ramdisk/fstab."}) {std::string fstab_path = prefix + suffix;if (access(fstab_path.c_str(), F_OK) == 0) {return fstab_path;}}}return "";
}
如下Android 14的手机的开机日志,在init阶段来读取fstab配置表的打印:这里的dt没有配置fstab,默认路径没有任何打印,但是可以了解到libfs_mgr的入口
1.2 fstab文件是什么样子的?
android系统的文件系统相关参数定义被统一放在fstab.in里面,从上面的流程可以了解到fs_mgr会去读取fstab.*文件,并根据此文件配置的内容去逐一挂载所有的分区,那么它到底长什么样子的呢?
首先cat /vendor/etc/fstab.mtxxxx内容如下:
D50:/vendor/etc # cat fsta
fstab.enableswap fstab.mt6765 fstab.mt8768
D50:/vendor/etc # cat fstab.mt6765
# 1 "vendor/mediatek/proprietary/hardware/fstab/mt6765/fstab.in.mt6765"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 341 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "vendor/mediatek/proprietary/hardware/fstab/mt6765/fstab.in.mt6765" 2
# 145 "vendor/mediatek/proprietary/hardware/fstab/mt6765/fstab.in.mt6765"
system /system ext4 ro wait,avb=vbmeta_system,logical,first_stage_mount,avb_keys=/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey,slotselect
system_ext /system_ext ext4 ro wait,avb=vbmeta_system,logical,first_stage_mount,avb_keys=/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey,slotselectvendor /vendor ext4 ro wait,avb,logical,first_stage_mount,slotselectproduct /product ext4 ro wait,avb,logical,first_stage_mount,slotselect
# 170 "vendor/mediatek/proprietary/hardware/fstab/mt6765/fstab.in.mt6765"
/dev/block/by-name/md_udc /metadata ext4 noatime,nosuid,nodev,discard wait,check,formattable,first_stage_mount/dev/block/by-name/userdata /data f2fs noatime,nosuid,nodev,discard,noflush_merge,reserve_root=134217,resgid=1065,inlinecrypt latemount,wait,check,quota,reservedsize=128M,formattable,resize,,checkpoint=fs,fileencryption=aes-256-xts:aes-256-cts:v2,keydirectory=/metadata/vold/metadata_encryption/dev/block/by-name/protect1 /mnt/vendor/protect_f ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable
/dev/block/by-name/protect2 /mnt/vendor/protect_s ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable
/dev/block/by-name/nvdata /mnt/vendor/nvdata ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable
/dev/block/by-name/nvcfg /mnt/vendor/nvcfg ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable/dev/block/by-name/persist /mnt/vendor/persist ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable/devices/platform/externdevice* auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata/devices/platform/mt_usb* auto vfat defaults voldmanaged=usbotg:auto/dev/block/by-name/frp /persistent emmc defaults defaults/dev/block/by-name/nvram /nvram emmc defaults defaults
/dev/block/by-name/proinfo /proinfo emmc defaults defaults
/dev/block/by-name/lk /bootloader emmc defaults defaults
/dev/block/by-name/lk2 /bootloader2 emmc defaults defaults
/dev/block/by-name/para /misc emmc defaults defaults/dev/block/by-name/boot /boot emmc defaults first_stage_mount,nofail,slotselect
# 210 "vendor/mediatek/proprietary/hardware/fstab/mt6765/fstab.in.mt6765"
/dev/block/by-name/vbmeta_vendor /vbmeta_vendor emmc defaults first_stage_mount,nofail,slotselect
/dev/block/by-name/vbmeta_system /vbmeta_system emmc defaults first_stage_mount,nofail,slotselect,avb=vbmeta/dev/block/by-name/logo /logo emmc defaults defaults
/dev/block/by-name/expdb /expdb emmc defaults defaults
/dev/block/by-name/seccfg /seccfg emmc defaults defaults/dev/block/by-name/tee1 /tee1 emmc defaults defaults
/dev/block/by-name/tee2 /tee2 emmc defaults defaults/dev/block/by-name/scp1 /scp1 emmc defaults defaults
/dev/block/by-name/scp2 /scp2 emmc defaults defaults/dev/block/by-name/sspm_1 /sspm_1 emmc defaults defaults
/dev/block/by-name/sspm_2 /sspm_2 emmc defaults defaults/dev/block/by-name/md1img /md1img emmc defaults defaults
/dev/block/by-name/md1dsp /md1dsp emmc defaults defaults
/dev/block/by-name/md1arm7 /md1arm7 emmc defaults defaults
/dev/block/by-name/md3img /md3img emmc defaults defaults/dev/block/by-name/gz1 /gz1 emmc defaults defaults
/dev/block/by-name/gz2 /gz2 emmc defaults defaults/dev/block/by-name/spmfw /spmfw emmc defaults defaults/dev/block/by-name/boot_para /boot_para emmc defaults defaults
/dev/block/by-name/odmdtbo /odmdtbo emmc defaults defaults
/dev/block/by-name/dtbo /dtbo emmc defaults defaults/dev/block/by-name/vbmeta /vbmeta emmc defaults defaults
D50:/vendor/etc #
如上格式,此文件可以解析如下三部分
那么我们在源代码是如何配置的呢?MTK可以参考如下逻辑,后文详细解读各大配置参数
1.3 FirstStageMount::DoCreateDevices
//aosp/system/core/init/first_stage_mount.cpp
bool FirstStageMount::DoCreateDevices() {if (!InitDevices()) return false;// Mount /metadata before creating logical partitions, since we need to// know whether a snapshot merge is in progress.auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) {//从fstab配置表中寻找/metadata分区的信息,此分区很重要存储了一些元数据和秘钥相关的东西return entry.mount_point == "/metadata";});if (metadata_partition != fstab_.end()) {//首先需要挂载/metadata分区,因为它太重要了if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {// Copies DSU AVB keys from the ramdisk to /metadata.// Must be done before the following TrySwitchSystemAsRoot().// Otherwise, ramdisk will be inaccessible after switching root.//它为什么重要,就是因为拷贝AVB Key到这个目录,详细的待后续研究CopyDsuAvbKeys();}}//创建逻辑分区if (!CreateLogicalPartitions()) return false;return true;
}
流程1:如上逻辑首先挂载了/metadata分区,为什么要先挂载它?
流程2:/metadata分区挂载流程对应日志:注意这里调用了metadata_partition函数传递了参数,所以只挂载了一个分区
流程3:创建逻辑分区,那么何为逻辑分区?从下面日志来看个人理解它类似与PC的C盘来区别于其他磁盘,因此这里的逻辑分区通常为system/vendor几个目录
如上日志对应逻辑代码如下:
1.4 FirstStageMount::DoFirstStageMount
//aosp/system/core/init/first_stage_mount.cpp
bool FirstStageMount::DoFirstStageMount() {if (!IsDmLinearEnabled() && fstab_.empty()) {// Nothing to mount.LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";return true;}//挂载分区if (!MountPartitions()) return false; return true;
}
这里的主要流程还是去调用MountPartitions()去挂载分区,注意这里不像metadata哪里传递了参数,因此这里是根据fstab表去挂载所有其他分区,代码如下:
2、fstab文件参数解读
3、fs_mgr挂载分区
接着init的FirstStageMount::MountPartition通过fstab表来挂载单个分区,如下逻辑,在对底层设备块相关初始化之后通过fs_mgr来进行单个分区的挂载。
//aosp/system/core/init/first_stage_mount.cpp
bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, Fstab::iterator* end) {// Sets end to begin + 1, so we can just return on failure below.if (end) {*end = begin + 1;}if (!fs_mgr_create_canonical_mount_point(begin->mount_point)) {return false;}//跟底层设备块有关系,暂时没有深入研究if (begin->fs_mgr_flags.logical) {if (!fs_mgr_update_logical_partition(&(*begin))) {return false;}if (!block_dev_init_.InitDmDevice(begin->blk_device)) {return false;}}if (!SetUpDmVerity(&(*begin))) {PLOG(ERROR) << "Failed to setup verity for '" << begin->mount_point << "'";return false;}//核心代码,通过fs_mgr去进行挂载bool mounted = (fs_mgr_do_mount_one(*begin) == 0);// Try other mounts with the same mount point.Fstab::iterator current = begin + 1;for (; current != fstab_.end() && current->mount_point == begin->mount_point; current++) {if (!mounted) {// blk_device is already updated to /dev/dm-<N> by SetUpDmVerity() above.// Copy it from the begin iterator.current->blk_device = begin->blk_device;mounted = (fs_mgr_do_mount_one(*current) == 0);}}if (erase_same_mounts) {current = fstab_.erase(begin, current);}if (end) {*end = current;}return mounted;
}
//aosp/system/core/fs_mgr/fs_mgr.cpp
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& alt_mount_point) {// First check the filesystem if requested.if (entry.fs_mgr_flags.wait && !WaitForFile(entry.blk_device, 20s)) {LERROR << "Skipping mounting '" << entry.blk_device << "'";}auto& mount_point = alt_mount_point.empty() ? entry.mount_point : alt_mount_point;//步骤1:挂载前的准备工作,其实就是解析fstab分区配置的各种参数int ret = prepare_fs_for_mount(entry.blk_device, entry, mount_point);// Wiped case doesn't require to try __mount below.if (ret & FS_STAT_INVALID_MAGIC) {return FS_MGR_DOMNT_FAILED;}//步骤2:正式进行文件分区的挂载ret = __mount(entry.blk_device, mount_point, entry);if (ret) {ret = (errno == EBUSY) ? FS_MGR_DOMNT_BUSY : FS_MGR_DOMNT_FAILED;}return ret;
}
如上代码进行总结如下:
- init最后通过libfs_mgr最后调用了fs_mgr.cpp来进行文件分区的挂载
- 首先通过prepare_fs_for_mount来解析fstab里面配置的一系列参数
- 最后通过__mount来进行文件分区的挂载
3.1 挂载前的准备工作prepare_fs_for_mount
总结如上代码逻辑,主要做了如下几个步骤:
- tune_quota:Enable/disable quota support on the filesystem if needed
- resize_fs:重置文件系统
- check_fs:校验文件系统
- tune_reserved_size:ext4支持
- tune_encrypt:ext4支持
- tune_verity:ext4支持
- tune_casefold:ext4支持
- tune_metadata_csum:ext4支持
3.2 挂载文件分区流程__mount
相关文章:
Android Native 之 文件系统挂载
一、文件系统挂载流程概述 二、文件系统挂载流程细节 1、Init启动阶段 众所周知,init进程为android系统的第一个进程,也是native世界的开端,要想让整个android世界能够稳定的运行,文件系统的创建和初始化是必不可少的ÿ…...
DirectX12(D3D12)基础教程四 入门指南
本章主要讲了些D3D12概念和理论,对第一、二章相关概念的补充和纠正,要的理解D3D12概念和理论基础,结合代码加深理解。 命令队列和命令列表 为了实现渲染工作的重用和多线程缩放, 在 D3D12 中,做了三个重要方面不同于 …...
android13打基础: timepicker控件
public class Ch4_TimePickerActivity extends AppCompatActivity implements TimePickerDialog.OnTimeSetListener {private TextView tv_time; // 声明一个文本视图对象private TimePicker tp_time; // 声明一个时间选择器对象Overrideprotected void onCreate(Nullable Bund…...
国产化板卡设计原理图:2330-基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡
基于FMC接口的JFM7K325T PCIeX4 3U PXIe接口卡 一、板卡概述 本板卡基于 FPGAJFM7K325T 芯片,pin_to_pin兼容FPGAXC7K410T-2FFG900 ,支持PCIeX8、64bit DDR3容量2GByte,HPC的FMC连接器,板卡支持PXIE标准协议,其中XJ3…...
Oracle SQL优化①——查看SQL执行计划的几种方法
前言 在日常的运维工作中,SQL优化是DBA的进阶技能,SQL优化的前提是要看SQL的执行计划是否正确,下面分享几种查看执行计划的方法,每一种方法都各有各的好处,可以根据特定场景选择某种方法。 一.使用AUTOTRACE查看执行…...
MySQL主从架构配合ShardingJdbc实现读写分离
文章目录 目录架构搭建读写分离pom.xmlfdy-live-user-provider 模块application.ymlfdy-db-sharding.yamlShardingJdbcDatasourceAutoInitConnectionConfig.java 目录 架构搭建 基于Docker去创建MySQL的主从架构 读写分离 pom.xml <dependency><groupId>mysql…...
MyBatis @Param 注解详解:多参数传递与正确使用方式
Param 注解主要用于 MyBatis 进行参数传递时给 SQL 语句中的参数 起别名,通常用于 多参数 方法,使参数在 XML Mapper 文件或注解 SQL 语句中更清晰易用。 1. 基本用法 在 Mapper 接口中使用 Param 来为参数命名,避免 MyBatis 解析时出现参数…...
【JAVA架构师成长之路】【Redis】第14集:Redis缓存穿透原理、规避、解决方案
30分钟自学教程:Redis缓存穿透原理与解决方案 目标 理解缓存穿透的成因及危害。掌握布隆过滤器、空值缓存等核心防御技术。能够通过代码实现请求拦截与缓存保护。学会限流降级、异步加载等应急方案。 教程内容 0~2分钟:缓存穿透的定义与核心原因 定义…...
mybatis报错org/apache/commons/lang3/tuple/Pair] with root cause
mybatis一对多查询配置resultMap映射报错org/apache/commons/lang3/tuple/Pair] with root cause 原因是mybatis依赖common-lang3这个包, 只需要添加common-lang3的依赖坐标即可: <dependency><groupId>org.apache.commons</groupId><artifactId>comm…...
supervisord管理Gunicorn进程,使用Nginx作为反向代理运行flask web项目
1. 安装 Gunicorn 在项目虚拟环境中安装 Gunicorn:2. 基本用法 配置文件 创建一个 Gunicorn 配置文件(如 gunicorn_config.py),方便管理复杂配置。 示例 gunicorn_config.py: bind "0.0.0.0:8000" #…...
STM32之软件SPI
SPI传输更快,最大可达80MHz,而I2C最大只有3.4MHz。输入输出是分开的,可以同时输出输入。是同步全双工。仅支持一主多从。SS是从机选择线。每个从机一根。SPI无应答机制的设计。 注意:所有设备需要共地,时钟线主机输出&…...
fastjson漏洞
fastjson漏洞 fastjson工作原理攻击原理补充 例子 fastjson工作原理 fastjson的作用是将JAVA对象转换成对应的json表示形式,也可以反过来将json转化为对应的Java对象。fastjson使用AutoType功能进行反序列化,AutoType使用type标记字符的原始类型&#x…...
【YOLOv12改进trick】医学图像分割网络CMUNeXt引入YOLOv12中,增强全局上下文信息实现涨点,含创新点Python代码,方便发论文
🍋改进模块🍋:医学全卷积U型网络(CMUNeXtBlock) 🍋解决问题🍋:CMUNeXtBlock模块解决了在医学图像分割任务中,传统的卷积操作由于其局部性限制,难以有效提取全局上下文信息的问题。 🍋改进优势🍋:利用大卷积核和倒置瓶颈结构,提取全局上下文信息,同时保持卷…...
机器学习的半监督学习,弱监督学习,自监督学习
半监督学习、弱监督学习和自监督学习是机器学习中利用不同形式监督信号的三种方法,它们的核心区别在于标注数据的数量、质量以及监督信号的来源。以下是它们的详细对比: 1. 半监督学习(Semi-Supervised Learning) 核心特点&#x…...
K8S学习之基础十七:k8s的蓝绿部署
蓝绿部署概述 蓝绿部署中,一共有两套系统,一套是正在提供服务的系统,一套是准备发布的系统。两套系统都是功能完善、正在运行的系统,只是版本和对外服务情况不同。 开发新版本,要用新版本替换线上的旧版本&…...
【计算机网络】计算机网络的性能指标——时延、时延带宽积、往返时延、信道利用率
计算机网络的性能指标 导读 大家好,很高兴又和大家见面啦!!! 在上一篇内容中我们介绍了计算机网络的三个性能指标——速率、带宽和吞吐量。用大白话来说就是:网速、最高网速和实时网速。 相信大家看到这三个词应该就…...
单片机如何用C语言重写vfprintf
在单片机中,标准库函数 vfprintf 可能不可用或占用过多资源(如内存或代码空间),因此我们可以通过自定义实现一个轻量级的 vfprintf 函数,专门用于单片机的串口输出。以下是一个用 C 语言重写 vfprintf 的示例ÿ…...
1.4 单元测试与热部署
本次实战实现Spring Boot的单元测试与热部署功能。单元测试方面,通过JUnit和Mockito等工具,结合SpringBootTest注解,可以模拟真实环境对应用组件进行独立测试,验证逻辑正确性,提升代码质量。具体演示了HelloWorld01和H…...
使用免费IP数据库离线查询IP归属地
一、准备工作 1.下载免费IP数据库 首先,访问 MaxMind官网(https://www.maxmind.com/en/home)如果你还没有MaxMind账号,可以通过此链接地址(https://www.maxmind.com/en/geolite2/signup)进行账号注册&…...
go语言数据类型
一.Go 语言有四大显著特点:高效性:编译与运行效率高。并发性:原生支持并发编程。简洁性:编程风格简洁直接,代码可读性与可维护性高。跨平台性:程序能在 Windows、Linux、Mac OS 等多系统运行。二.go的包:pa…...
操作系统 1.3-开机页面的产生
问题引入 从打开电源开始.. 这神秘的黑色背后发生着什么?... 设计思路 伟大的数学家图灵,设计了这样的一个模型: 首先我们计算机有一个控制器,他可以处理一系列提供给他的动作。我们将控制器动作,控制器状态,数据…...
单例模式:确保一个类只有一个实例
目录 引言 1. 单例模式的核心思想 2. 单例模式的实现方式 2.1 饿汉式单例 2.2 懒汉式单例 2.3 线程安全的懒汉式单例 2.4 双重检查锁定(Double-Checked Locking) 2.5 静态内部类实现单例 2.6 枚举实现单例 3. 单例模式的使用场景 4. 单例模式…...
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_modules
定义在 objs\ngx_modules.c #include <ngx_config.h> #include <ngx_core.h>extern ngx_module_t ngx_core_module; extern ngx_module_t ngx_errlog_module; extern ngx_module_t ngx_conf_module; extern ngx_module_t ngx_openssl_module; extern ngx_modul…...
vue3中 组合式~测试深入组件:事件 与 $emit()—setup() 上下文对象ctx.emit
一、语法(props) 第一步:在组件模板表达式中,可以直接用$emit()方法触发自定义事件, <!-- MyComponent --> <button click"$emit(someEvent)">Click Me</button> 第二步父组件可以通过 v-on (缩写为 ) 来监听…...
uniapp小程序对接腾讯IM即时通讯无ui集成(1)
首先需要完成一些准备工作。 1.注册腾讯云账号 腾讯云 注册账号后搜索im即时通讯,新创建一个应用。 2.uniapp创建项目 腾讯云无ui集成文档 按照文档步骤下载完这两个包后打开项目。有下图这两个包就算完成了开始工作。 3.APP目录进行引入和集成 <script…...
【YOLOv12改进trick】StarBlock引入YOLOv12,创新涨点优化,含创新点Python代码,方便发论文
🍋改进模块🍋:StarBlock 🍋解决问题🍋:采用StarBlock将输入数据映射到一个极高维的非线性特征空间,生成丰富的特征表示,使得模型在处理复杂数据时更加有效。 🍋改进优势🍋:简单粗暴的星型乘法涨点却很明显 🍋适用场景🍋:目标检测、语义分割、自然语言处理…...
机器学习之强化学习
引言 在人工智能的众多分支中,强化学习(Reinforcement Learning, RL) 因其独特的学习范式而备受关注。与依赖标注数据的监督学习或探索数据结构的无监督学习不同,强化学习的核心是智能体(Agent)通过与环境…...
天津大学02-深度解读DeepSeek:部署、使用、安全【文末附下载链接】
大模型风险与不当用例——价值观错位 大模型与人类价值观、期望之间的不一致而导致的安全问题,包含:• 社会偏见(Social Bias)LLM在生成文本时强化对特定社会群体的刻板印象,例如将穆斯林与恐怖主义关联,或…...
C# OPC DA获取DCS数据(提前配置DCOM)
OPC DA配置操作手册 配置完成后,访问远程ip,就能获取到服务 C#使用Interop.OPCAutomation采集OPC DA数据,支持订阅(数据变化)、单个读取、单个写入、断线重连...
ReAct论文阅读笔记总结
ReAct:Synergizing Reasoning and Acting in Language Models 背景 最近的研究结果暗示了在自主系统中结合语言推理与交互决策的可能性。 一方面,经过适当Prompt的大型语言模型(LLMs)已经展示了在算术、常识和符号推理任务中通…...
【计网】运输层
运输层 5.1 运输层概述5.2 运输层端口号、复用与分用5.3 UDP和TCP的区别5.4 TCP具体实现5.4.1 TCP的流量控制5.4.2 TCP的拥塞控制5.4.3 TCP超时重传时间的选择5.4.4 TCP可靠传输的实现5.4.5 TCP运输连接管理(一)TCP连接的建立(三报文握手&…...
计算机毕业设计SpringBoot+Vue.js多媒体素材库系统(源码+文档+PPT+讲解)
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
MC9S12单片机的内存映射机制
地址空间 这是个16位的单片机。CPU的寻址空间最大为2^1664K。 这个64K是包括外设、RAM、EEPROM、和FLASH的。现在程序越来越大,64K的空间肯定是不够用的。因此,需要扩展。 扩展方法就是:分页。 把原来的64K空间,划分一块出来&a…...
鸿蒙HarmonyOS评论功能小demo
评论页面小demo 效果展示 1.拆解组件,分层搭建 我们将整个评论页面拆解为三个组件,分别是头部导航,评论项,回复三个部分,然后统一在index界面导入 2.头部导航界面搭建 Preview Component struct HmNavBar {// 属性&a…...
数据仓库为什么要分层
数据仓库分层架构是数据仓库设计中的一个重要概念,其主要目的是为了更好地组织和管理数据,提高数据仓库的可维护性、可扩展性和性能。分层架构将数据仓库划分为多个层次,每个层次都有其特定的职责和功能。以下是数据仓库分层的主要原因和好处…...
【powerjob】 powerjobserver注册服务IP错误
1、问题:powerjobserver 4.3.6 的服务器上有多个网卡对应多个ip,示例 eth0 :IP1 ,docker0:IP2 和worker 进行通信时 正确的应该时IP1 但是注册显示获取的确实IP2,导致 worker 通过ip2和server通信,网络不通,注册不上 2、解决方案 …...
JCRQ1河马算法+四模型对比!HO-CNN-GRU-Attention系列四模型多变量时序预测
JCRQ1河马算法四模型对比!HO-CNN-GRU-Attention系列四模型多变量时序预测 目录 JCRQ1河马算法四模型对比!HO-CNN-GRU-Attention系列四模型多变量时序预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 基于HO-CNN-GRU-Attention、CNN-GRU-Attent…...
智能硬件如何和应用层app连接?
现在比较方便的是一键配置方式,主要是使用蓝牙、smartconfig、ZigBee和声波配置。 蓝牙配置:比如蓝牙耳机、蓝牙鼠标,只能支持点对点连接,且对设备和app距离要求严格。 ZigBee配置方式:无法直接接入网络,…...
深度学习系列78:使用langchain的api进行RAG
用起来很麻烦,看api的工夫都已经能自己写完代码了。但现在有些开源api用的是langchain的接口,还是了解一下。参考官方文档:https://www.langchain.com.cn/docs/how_to/ 1. LLM和langserve示例 以openai接口为例,可以看到分为3步…...
海思Hi3516DV300交叉编译opencv
OpenCV是一个开源的跨平台计算机视觉库,支持C、Python等多种语言,适用于图像处理、目标检测、机器学习等任务。其核心由C编写,高效轻量,提供实时视觉处理功能,广泛应用于工业自动化、医疗影像等领域。 1 环境准备 1…...
责任链模式:优雅处理复杂流程的设计艺术
引言 在软件设计中,我们经常会遇到需要按特定顺序处理请求的场景。例如,一个订单处理系统可能需要经过验证、付款、物流安排和客户通知等多个步骤。如果我们将这些步骤硬编码在一个方法中,代码将变得臃肿且难以维护。这时,责任链…...
【DeepSeek】5分钟快速实现本地化部署教程
一、快捷部署 (1)下载ds大模型安装助手,下载后直接点击快速安装即可。 https://file-cdn-deepseek.fanqiesoft.cn/deepseek/deepseek_28348_st.exe (2)打开软件,点击立即激活 (3)选…...
HTML前端手册
HTML前端手册 记录前端框架在使用过程中遇到的各种问题和解决方案,供后续快速进行手册翻阅使用 文章目录 HTML前端手册1-前端框架1-TypeScript框架2-CSS框架 2-前端Demo1-Html常用代码 2-知云接力3-Live2D平面动画 3-前端运维1-NPM版本管理 1-前端框架 1-TypeScrip…...
【uniapp】图片添加canvas水印
目录 需求&背景实现地理位置添加水印 ios补充 需求&背景 需求:拍照后给图片添加水印, 水印包含经纬度、用户信息、公司logo等信息。 效果图: 方案:使用canvas添加水印。 具体实现:上传图片组件是项目里现有的ÿ…...
Java 大视界 -- Java 大数据在智能金融反欺诈中的技术实现与案例分析(114)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
机器学习数学基础:43.外生变量与内生变量
外生变量与内生变量:模型中的因果角色 在因果模型(像结构方程模型、回归分析这类)里,外生变量和内生变量是用来区分变量来源和相互关系的重要概念。下面从定义、实例、差异以及应用场景四个方面来详细介绍: 一、定义…...
Bean 的生命周期主要包括以下阶段:
Bean 的生命周期主要包括以下阶段: 定义 :在配置文件或注解中定义 Bean,包括其类、作用域等信息。 实例化 :Spring 容器根据定义创建 Bean 的实例。 属性赋值 :容器为 Bean 设置配置的属性值。 初始化 :…...
Unity游戏开发中的网格简化与LOD技术(Mesh Simplification LOD)
在Unity游戏开发中,网格简化(Mesh Simplification)和LOD(Level of Detail)技术是优化渲染性能的关键手段,尤其在处理复杂场景和高精度模型时至关重要。以下是一套系统的实现方案与优化策略: 一、…...
3.7[Q]CV
对于一个由cmake构建的项目,什么时候应该执行cmake指令?什么时候执行make指令?即,一个cmake构建的项目,各步骤的意义是什么?当我修改了部分代码后,重启项目该执行什么命令? view,mod…...
发行思考:全球热销榜的频繁变动
几点杂感: 1、单机游戏销量与在线人数的衰退是剧烈的,有明显的周期性,而在线游戏则稳定很多。 如去年的某明星游戏,最高200多万在线,如今在线人数是48名,3万多。 而近期热门的是MH,在线人数8…...