Android分区挂载原理介绍(上)

一、 device-mapper基本原理介绍       

1.1 dm工作原理       

1.2 dm实现动态卷(逻辑分区)功能介绍(dm-linear)       

1.3 dm 实现完整性校验功能介绍(dm-verity)       

1.4 元数据加密(default-key)       

1.5 dm实现快照功能介绍(snapshot,snapshot-origin,dm-snapshot-merge,bow)       

二、vold介绍       

2.1 vold结构总览       

2.2 encryptFstab(元数据加解密)     

2.3 mountFstab(挂载分区)  

2.4 fbeEnable(使能fbe加密)   

2.5 initUser0      

三、分区挂载流程介绍    

3.1 分区挂载顺序总览   

3.2 metadata分区挂载流程   

3.3 system分区挂载流程    

3.4 userdata分区挂载流程

四、 常见问题汇总     

4.1 set_policy_failed问题  

4.2 init_user0_failed问题    

4.3 enablefilecrypto_failed问题   

4.4 userdata挂载失败问题   

4.5 关机时ServiceManager crash导致vold shutdown超时死机重启      

前言:

还没开始深入了解分区挂载原理时,觉得分区挂载涉及的内容应该不会很多。就是在分区表中找到对应的物理块,然后直接mount就完成了,最多就是需要了解一些流程顺序上的内容。

当真正开始走读分区挂载流程代码时,才发现之前的想法太天真了。如果要深入了解分区挂载原理,需要了解的内容很多。

在远古android时期,挂载真的如上面描述的,仅仅是一个挂载(一个物理分区由文件系统管理起来)

但是随着对分区使用效率,安全等提出了越来越多的要求,分区挂载涉及的内容也越来越多。

例如:为了解决system和vender等分区size不能动态调整的问题引入动态分区概念(逻辑分区),将system,vendor等分区打包放在了super分区下;system等关键分区为了防止篡改,在挂载或使用时,需要这些分区进行完整性校验;为了用户数据的安全,对userdata分区中的数据需要加密,加密方式也有较早的FDE( Full-disk encryption全盘加密),发展到现在更精细化的FBE(File-based Encryption文件级加密),并且针对userdata还增加了  metadata(元数据)级别的加密;系统分区也有之前的单分区进recovery下升级,到A/B分区到recovery下升级,再到现在的VAB分区架构,借用snapshot(快照)技术完成升级及回滚等等。

如果要对分区挂载有一个完整系统的了解,上面提到的那些技术都是绕不开的。但是每一项技术深入到代码细节介绍的话是不现实的,而且也不是我们这篇文章的重点。    

所以下面我们先对用到的技术做一些原理介绍,了解他们是怎么工作的,不深入代码。对这些技术有基本的了解后,我们对整个分区挂载逻辑深入到代码级别去分析。

一、device-mapper基本原理介绍

1.1 dm工作原理

device-mapper是linux块设备映射技术框架。我们挂载用到的动态卷(逻辑分区),完整性校验(dm-verity),vab升级用到snapshot(快照)技术都离不开它。

它是在块设备上的一层映射,对外来看,它也是一个块设备(虚拟块设备)。它有三个重要概念,映射设备(mapped device),映射表(map table),目标设备(traget device)。这样说可能比较抽象。

我们可以类别成图书馆场景来了解一下它的工作原理。

图书馆中摆着一排排书,每一本书就像是我们块设备中的物理块。一排书架可以看做是一个块设备(由一个个物理块组成)。我们在存放书时,按照书的特性进行分类存放,例如经济类的书存放在一个书架,人文历史的书存放在另一个书架。这样的好处就是我们可以根据我们要拿书的种类去快速找到我们需要的书。    

9c0535a7801665dc6cd34c2a4ee4baa7.png

但是某一天图书馆的领导换了,他觉得根据书种类搜索的方法太单一了,还希望能通过书名首字母方式快速找到需要的书。这应该怎么解决呢?有一个办法就是再建一个图书馆,买一模一样的书。然后书架上按照首字母的方式排列。这样你想按首字母找也行,想按类型找也行,显然是不可能的。

这时候有一种解决方案就是建立了一个虚拟书架(虚拟块设备),这个虚拟书架对外来看,和其他书架没有区别,但是实际上面摆放的只是一张张小卡片,这些小卡片上面写的书名以及这本书真正摆放的物理位置(映射表),并且是按照拼音首字母排序的。当我们去这个书架上拿书的时候,图书管理员(device mapper驱动)会根据卡片上的内容,快速到这本书真正摆放的位置(目标设备),拿到真正的书,并给到我们。对我们来说,我们也可以在这个虚拟书架上拿到真正的书,所以用起来和其他实际的物理书架也没有什么区别。这个就是device-mapper的工作原理。

所以我们看到device-mapper工作只是增加了一层映射,对外来看它也是一个块设备,在实际访问时,device-mapper的区别会根据映射表,去真正块设备(目标设备)上的物理块上帮我们拿到需要的数据返回给我们。    

961a0392489df9a815f12ef8b23fddb3.png

Device-mapper使用起来也比较灵活

一个虚拟书架的目标设备也可以是另一个虚拟书架,这也很好理解,因为对外来看,虚拟书架和物理书架使用起来并没有什么区别。

也可以只映射一个物理分区的部分块,同样也可以将两个物理分区中的内容映射到同一个虚拟块设备中。后面的章节会介绍这种特性的使用。

dmctl list targets

可以查看dm设备支持的不同类型,后面章节介绍的一些功能其实都是不同dm设备类型的应用。dmctl list targets可以看到手机中支持的不同targets    

cdc6b7f0f8d4e7608f85310166ec99a0.png

手机中的dm设备及targets列表如下

dm设备名

target

my_engineering_a

linear

my_heytap_a

linear

system_ext_a

linear

userdata

default-key

vendor_dlkm-verity

verity

odm_a

linear

system_a

linear

vendor-verity

verity

vendor_dlkm_a

linear

vendor_a

linear

system_ext-verity

verity

my_region_a

linear

my_preload_a

linear

my_bigball_a        

linear

my_carrier_a

linear

odm_dlkm_a

linear

my_product_a

linear

product-verity

verity

system-verity

verity

product_a

linear

my_manifest_a

linear

my_company_a

linear

my_stock_a

linear

1.2 dm实现动态卷(逻辑分区)功能介绍(dm-linear)

上面一节介绍了device-mapper的基本原理,了解到device-mapper虚拟设备是通过映射表映射到目标设备的,那在映射物理设备时,是否可以只映射某个物理设备的部分块呢?答案是可以的,逻辑分区就是借助这个功能实现的

物理分区和逻辑分区有什么区别呢?简单理解如下

物理分区是SMT刷机的时候就规划好的,也就是我们常说的分区表里面划分的分区,物理分区大小是固定的,轻易不会改变

逻辑分区是一个动态卷的概念,一个物理分区可以划分为多个逻辑分区,并且这些逻辑分区的大小是随时可以改变的。    

/dev/block/bootdevice路径下面,sd*开头的都是一个个物理分区

/dev/block/by-name是对应的分区名称

b157b178b909be5ebb121cab22656d6c.png

我们在/dev/block/by-name下并没有看到system_ext,vendor之类的分区。是因为Android将system_ext,vendor这些分区看做逻辑分区,实际存放位置都存放在了super这个物理分区中。在机器开机时,借助device-mapper的技术,通过映射表将super分区中的system_ext.img,vendor.img映射成dm设备,之后再去挂载对应的dm设备(其实还有一个verity过程,之后我们再介绍,为了更好理解本解内容,我们先通过adb disable-verity跳过这个过程,重启手机)。

我们通过如下命令查看一下现在system_ext 和vendor的挂载结构

a.查看挂载点

mount | grep -e  “/system_ext” -e “/vendor ”

f409ba8d79343f35939c74569c0e23c4.png

可以看到/system_ext /vendor实际挂载的是dm这个虚拟设备,类似如下图    

4b5719a835acc6df36c4513d649890ae.png

b.查看dm devices

dmctl list devices 命令可以查看现在活动的dm设备

015c6b805ae94e36cc71f2d5a88dd38f.png

Dmctl getpath可以获取对应dm设备的路径

c323b00d62fb43d9cbed868e250eaf11.png

c.查看对应设备的映射表

dmctl table 命令可以查看现在dm设备的映射表内容

ddf7729433602b76d9ee74098aa3b55c.png    

以system_ext_a为例

输出内容含义如下

35e6f5f868f179dc68d350c911ff0ab5.png

super分区的设备号为8:6

6b944c20d8c73cfcadf2549f335e64c4.png

所以根据上面信息,可以看到system_ext_a为dm映射出来的虚拟设备,这个虚拟设备的LBA 0到2048144 线性映射了super这个物理分区,起始LBA地址为1347584的块(super物理分区)

可以得出如挂载图    

bdbdc22961f0b9732d1322893f47eb19.png

以及如下映射图

e4344454e0b5917af8ccc89b971a7137.png

LBA为逻辑地址,单位应该为512字节,我们来验证一下    

super分区的LBA:1347584开始的内容是否和映射出来的虚拟dm-1设备完全一样

取super分区LBA:1347584 开始的1024*512字节的内容与dm-1 LBA:0 开始的1024*512字节的内容对比

dd if=/dev/block/by-name/super of=/sdcard/super_1347584.bin bs=512 count=1024 skip=1347584

dd if=/dev/block/dm-1 of=/sdcard/dm_1.bin bs=512 count=1024

可以看到内容是完全一样的

ce3ee9b310a6098518313e7d514c3a9d.png

1.3 dm 实现完整性校验功能介绍(dm-verity)

在之前一节介绍动态卷功能时,我们执行了一条命令adb disable-verity。这条命令的作用是关闭dm-verity 功能。那这个功能又是做什么的呢?

dm-verity是Device mapper架构下的一种目标设备类型,该功能提供对块设备的透明完整性检查。

他工作原理如下

dm设备会把它自己按照4K单位进行分割,之后计算每个4K数据的hash值并保存起来,生成第0层,之后再把第0层的hash值放在一起,依旧按照4K大小继续计算hash值。生成第1层,以此类推,之后计算成一个root hash值。

Hash tree是保存在对应的分区中的(system,vendor等)。root hash保存到另一个有签名认证的分区中(vbmeta_system,vbmeta_vendor分区)。在开机引导的时候,会对root hash只的vbmeta分区进行签名校验,保证root hash是没有被篡改的。进一步保证整个用于校验的hash tree没有被篡改。

在运行时,当访问到某个块时,会计算这个块的hash值,之后与hash tree中的hash值对比,以此保证镜像的完整性。

0722cf22bae6dcf16dca3b08d84e31cb.png

下面我们依旧以vendor分区为例,看看整个挂载的结构是什么样的(没有执行adb disable-verity)

先看看vendor分区挂载的是哪个块设备

mount | grep "/vendor "

f628ec0dc9306123e85b4eefca0777d7.png

Vendor分区挂载的是dm-20设备,对应的dm名称为vendor-verity

dmctl getpath vendor-verity    

ce6e8f3c023d1d1792ac53c46258a187.png

dm-20的目标设备是另一个dm设备,这个也很好理解,dm设备对外来看,也是一个块设备,使用起来和其他块设备没有什么区别,当然在dm映射的时候,目标设备也可以是另一个dm设备

dmctl list devices

dmctl getpath vendor-verity

dmctl getpath vendor_a

dmctl table vendor-verity

dmctl table vendor_a

c6090ecd85666b40e0f2a3564a8e654a.png

按照上面我们查看的结果,可以得出如下的vendor分区挂载结构。

a6f1cb6aac32c787d100fc3136851619.png

1.4 元数据加密(default-key)

在第一节中,我们看到了userdata dm设备的target类型为default-key。这个又是什么功能呢?    

7e3af2697f3ffe22c086759f76787491.png

default-key 为元数据加密功能。

Userdata存放的是用户的敏感数据,需要进行加密保护。例如我们知道的之前android使用的FDE(全盘加密),到现在使用的FBE(文件系统级加密,后面章节会介绍)。FBE从字面意思也可以看得出,加密的内容是文件内容和文件名,但是其他信息(例如目录布局、文件大小、权限和创建/修改时间)不会被加密。这些其他信息统称为“文件系统元数据”。

借助dm-default-key,就可以对这些”元数据进行加密”。在元数据密钥可用前 ,userdata分区中的所有内容均是无法读取的。所以元数据密钥不能存放在userdata分区,而存放在metadata这个分区中。

在开机过程中,会先挂载metadata分区,之后使用metadata分区中保存的key对userdata先进行元数据解密。然后就可以进行挂载了。(userdata分区元数据加密只能在分区首次进行格式化时设置)

1.5 dm实现快照功能介绍(snapshot,snapshot-origin,dm-snapshot-merge,bow)

dm框架的使用十分灵活,除了上面提到的将一个物理设备的部分区域,映射成一个dm设备。同样也可以将两个物理分区中的内容映射到同一个虚拟块设备中。

类似如下结构    

7be810bcfbdd6084a386e1931d0c0036.png

这样对外来看,是一个独立的块设备,但实际这个块设备中存放的内容,可能是分散在多个不同的物理分区中。

VAB(虚拟A/B分区)升级时,就借助的这一特性。

在A/B分区刚出来时,A/B分区是实实在在的两个物理分区。例如system分区需要2GB,那A/B架构就需要预留两个system分区作为互为备份升级。这种对空间的利用率是极低的。

vab架构就很好的解决了这个问题。

Vab应用了dm-snapshot技术,下面是google文档中的一些说明

使用 dm-snapshot 时,会用到以下四个设备

  • 基础设备是被捕获快照的设备。在此页面上,基础设备始终是动态分区,例如 system 或 vendor。

  • 写入时复制 (COW) 设备,用于向基础设备记录更改。 该设备的大小没有限制,只要足够容纳对基础设备的所有更改即可。    

  • 快照设备,这是使用 snapshot 目标创建的设备。需向快照设备写入的内容将写入 COW 设备。需从快照设备读取的内容将从基础设备或 COW 设备读取,具体取决于所访问的数据是否经过快照更改。

  • 源设备,这是使用 snapshot-origin 目标创建的设备。需从源设备读取的内容将直接从基础设备读取。需向源设备写入的内容将直接写入基础设备,但原始数据将通过写入 COW 设备进行备份。

e8fa1ce4bf6c71daf3f0bf9c77dd39e6.png

二、vold介绍

2.1 vold结构总览

Vold(volume Daemon),既Volume守护进程,这个守护进程作为kernel 和framework之间的桥梁,主要处理如下内容

  • 开关机过程中各分区的挂载/卸载

  • 外部T卡/OTG设备的文件系统挂载/卸载

在mount过程中,涉及的文件系统级加解密(FBE),元数据(metadata)加解密,文件节点创建等也由Vold的进行控制    

Vold架构在整个系统中的位置如下

f91333d8650d29c7750e7e9d57a9a70e.png

Vold服务是通过rc文件的方式启动的

system/vold/vold.rc文件中定义了vold service

f8587cc04fb21adf2ef9af9628575b45.png

之后在init.rc中,early-fs阶段,start vold启动

c9134edb6aa4d73caae5d47d71e191f8.png

Vold相关代码在如下路径下

system/vold/main.cpp

VoldNative service主要处理那些内容呢?

a.StorageManagerService/vdc等通过IVoldListener下发的各种操作命令,从VoldNativeService.h 文件中,我们可以找到VoldNativeService可以处理的操作

80804edb10a486957fe5041cec6c61e5.png

之后的章节,我们会选取一些日常工作中常用到的处理命令,对这些命令提供的能力(机制)进行深入分析,具体这些能力如何使用,在哪里使用等”策略”在后面的章节中讨论

VoldNativeService处理的命令

主要功能总结说明

encryptFstab

生成元数据加密的key,然后对指定分区进行元数据加密,生成对应的dm设备(default-key),之后挂载这个dm设备

mountFstab

encryptFstab类似,不过不需要重新生成key,去指定的路径读取存放的元数据解密key,根据key生成dm设备(default-key),之后挂载这个设备        

fbeEnable

如果是首次开机

创建 System DE Master Key 和生成 System DE Encryption Policy

后续每次开机

加载System DE Master Key,准备System DE Master storage

每次开机还会创建并加载一个新的per_boot Master Key,准备per_boot Master storage。

initUser0

如果是首次开机(根据user DE key存放路径判断),

创建 User 0 DE Master Key 和生成 User 0 DE Encryption Policy;

创建 User 0 CE  Master Key 和生成 User 0 CE Encryption Policy;

创建 User 0 DE Storage,并为这些文件夹设置 User 0 DE Encryption Policy

后续开机

加载 User 0 DE Master Key

准备 User 0 DE Storage,并校验文件夹 Encryption Policy

2.2 encryptFstab(元数据加解密)

011bc07fc57d03358ca160a64d383169.png

f6336f416d45690ba3834f5e83e9256a.png

主要处理函数为

fscrypt_mount_metadata_encrypted。这个函数重点流程如下

重点流程一:

从fstab中读取传入的mount_point,获取挂载点的相关配置参数。然后解析成用于加密的options

主要函数

auto data_rec = GetEntryForMountPoint(&fstab_default, mount_point);

if (!parse_options(data_rec->metadata_encryption_options, &options)) return 

false;         

重点流程二:

在dm设备介绍时,我们了解到了target类型为default-key的dm设备。这类型设备是基于原数据加密的,在metadata解密前,被加密的分区是无法被访问的。所以用于加解密的key就不能存放在被加密的分区。所以encryptFstab进行元数据加密的时候,需要根据指定存解密key的文件夹路径,也就是metadata_key_dir。
这里的重点流程就是根据(needs_encrypt 参数)传入的needs_encrypt参数,判断是新创建一个key还是使用已经存在的key。
read_key函数会处理这两者的区别
情况一,需要进行元数据加密(needs_encrypt=true),那就创建一个KeyGeneration,然后存放到metadata_key_dir下。encryptFstab流程中,needs_encrypt=true,就是这种情况
情况二,不需要进行元数据加密,就会去指定目录读取对应的key,并返回
关键处理函数如下
auto gen = needs_encrypt ? makeGen(options) : neverGen();
KeyBuffer key;
if (!read_key(data_rec->metadata_key_dir, gen, &key))

重点流程三:

前面流程走完以后,我们已经获取到用于元数据加解密的key了(无论是新生成的还是已存在的)。下一步就是创建default-key类型的dm设备

主要处理函数    

if (!create_crypto_blk_dev(kDmNameUserdata, blk_device, key, options, &crypto_blkdev,
&nr_sec)) {
这个函数主要的作用就是

重点流程四:

此时我们已经获得了一个已经完成元数据解密的dm设备了。如果这个dm设备是新创建的(needs_encrypt=true),那就需要根据should_format参数决定是否要格式化这个dm设备了。为什么要格式化它的?

原因是如果一个分区刚刚完成needs_encrypt加密,那这个分区之前保存的任何数据也是无意义的。所以我们可以选择在完整元数据加解密后的第一时间,针对已解密的dm设备进行格式化。

之前dm设备(default-key)介绍时也提到过,数据加密只能在分区首次进行格式化时设置。原因也是一样的。加密会让目标设备中保存的数据无效。

主要代码也比较简单,就直接针对解密后的dm设备进行格式化就可以    

217a4bd23469880da5c072b894c275f0.png

重点流程五:

历经前面的步骤,我们获得了一个解密后的dm设备,并且用于解密的key也保存到了指定的metadata_key_dir目录下。下一步就针对dm设备进行挂载了

主要的处理函数是:

mount_via_fs_mgr(mount_point.c_str(), crypto_blkdev.c_str());

 这个和其他普通分区挂载一样,主要是判断一些挂载参数,最后通过mount进行挂载。就不在这里展开了

2.3 mountFstab(挂载分区)

MountFstab处理函数与encryptFstab 基本一样,只是传入的参数有一些区别。流程和encryptFstab是类似的,只是不去重新创建元数据加密的key,而是直接去指定路径去读取用于元数据解密的key,之后同样是生成dm设备,然后挂载。这里就不再赘述。重点流程可以看encryptFstab 一章    

3b05cd6a80c6f0396591099afa9b2b26.png

2.4 fbeEnable(使能fbe加密)

d30b728af1f9d4aaae2e38b9e06258c3.png

主要处理函数为

fscrypt_initialize_systemwide_keys。这个函数重点流程如下

重点流程一:

设备第一次启动时:

创建 System DE Master Key 和生成 System DE Encryption Policy;

把 System DE Encryption Policy 保存到文件  /data/unencrypted/ref;

后续每次启动时:

加载 System DE Master Key;

主要的函数为

rtn = retrieveOrGenerateKey(device_key_path, device_key_temp, kEmptyAuthentication,
makeGen(options), &device_key);

重点流程二:    

拿到System DE master Key之后,就会使用加载起来的System DE Master Key,安装到对应的/data目录,注意此时并不是真正的解密,解密是在对文件进行I/O操作的时候才会去解密。安装可以理解为我们把账key交给将来负责解密的管理员了。之后如果有用户要对 System DE Storage路径下的文件进行操作,就可以使用安装好的key来完成真正的解密

主要的函数为

install_storage_key(DATA_MNT_POINT, options, device_key, &device_policy);

之后会将key的参考信息及加密策略都存放到/data/unencrypted/ref下,供后续需要设置加密策略的流程中快速读取使用        

重点流程三:

上面提到的System DE加密是在首次开机时完成的加密,只要不恢复出厂设置这个key就一直不会改变。

除了System DE加密,fscrypt_initialize_systemwide_keys还会安装一个每次开机使用的key

per_boot_key。

主要处理函数为:

rtn = generateStorageKey(makeGen(options), &per_boot_key);

rtn = install_storage_key(DATA_MNT_POINT, options, per_boot_key, &per_

boot_policy);

同样会把per_boot_key的参考信息及加密策略都存放到/data/unencrypted/per_boot_ref下,供后续需要设置加密策略的流程中快速读取使用        

2.5 initUser0

381b72fa71ede34228705fb347f7c2f8.png

这个函数的主要作用就是针对user0用户,进行fbe加解密初始化。主要处理函数为fscrypt_init_user0。下面就分析一下这个函数的重点流程

重点流程一:

准备好存放User.0 DE Storage和User.0 CE Storage key的路径

“/data/misc/vold/user_keys/de”

“/data/misc/vold/user_keys/ce”

之后根据/data/misc/vold/user_keys/de 是否存在,来判断机器是否是首次开机

/data/misc/vold这个路径System DE加密的,在之前提到的流程中已经对这个目录安装好所需的解密keyring,此时已经可以正常访问这个目录下的路径了。在后续的挂载流程分析中,会详细分析这些流程。此时可以认为/data/misc/vold已经完成解密就可以了

情况一:/data/misc/vold/user_keys/de 路径不存在(首次开机)

调用create_and_install_user_keys

通过generateStorageKey生成两个key(de_key,ce_key)    

storeKeyAtomically将两个key(de_key,ce_key)存放到对应路径下()/data/misc/vold/user_keys/de,/data/misc/vold/user_keys/ce

之后调用install_storage_key 给指定目录安装对应的storage Encryption Policy

情况二:/data/misc/vold/user_keys/de存在(非首次开机)

正面de_key和ce_key之前已经生成了,就不需要生成了,直接走下面的流程就可以

重点流程二:

至此,两个key已经正常存在了,下一步就是load_all_de_keys,安装de_key

主要处理函数:

if (!load_all_de_keys()) return false;

重点流程三:

fscrypt_prepare_user_storage("", 0, 0, android::os::IVold::STORAGE_FLAG_DE)

准备user 0的DE 目录,并给对应的目录指定Encryption Policy(加密策略)    

d23f3a03182700bff91f941d1150dff2.png

2.6 unlockUserKey

d9016af7765236d308ea8b1fe85ed550.png


 由于篇幅过长,第三、四章节将在下周发布~

Linux内核并发与同步机制解读(arm64)上

Linux内核并发与同步机制解读(arm64)下

crash实战:手把手教你使用crash分析内核dump

89cb654c3892a1dce0e14325c0e77b90.gif

长按关注内核工匠微信

Linux内核黑科技| 技术文章| 精选教程

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

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

相关文章

根据IP查找城市 - 华为OD统一考试

OD统一考试 题解: Java / Python / C 题目描述 某业务需要根据终端的IP地址获取该终端归属的城市,可以根据公开的IP地址池信息查询归属城市。 地址池格式如下: 城市名起始IP,结束IP 起始和结束地址按照英文逗号分隔&#xff0…

非线性最小二乘问题的数值方法 —— 狗腿法 Powell‘s Dog Leg Method (I - 原理与算法)

Title: 非线性最小二乘问题的数值方法 —— 狗腿法 Powell’s Dog Leg Method (I - 原理与算法) 文章目录 I. 前言II. 线搜索类型和信赖域类型1. 线搜索类型 —— 最速下降法2. 信赖域类型3. 柯西点 III. 狗腿法的原理1. 狗腿法的构建2. 狗腿法的优化说明3. 狗腿法的插值权重 I…

Java 全栈知识点问题汇总(上)

Java 全栈知识点问题汇总(上) 1 Java 基础 1.1 语法基础 面向对象特性?a a b 与 a b 的区别3*0.1 0.3 将会返回什么? true 还是 false?能在 Switch 中使用 String 吗?对equals()和hashCode()的理解?final、finalize 和 finally 的不同…

Git 配置与理解

简述 Git 在 Windows 和 Ubuntu 中的配置,以及对 Git 工作区域划分和 Git 中对于文件状态划分的理解。 git 基础安装与配置 基于 WSL 的 Ubuntu 下的 git 打开或关闭Windows功能 -> Hyper-V、Virtual Machine Platform、Windows Subsystem for Linux # 1.必须…

STM32407用汇顶的GT911触摸芯片调试实盘

这个配置很关键 代码 #include "stm32f4xx.h" #include "GT9147.h" #include "Touch.h" #include "C_Touch_I2C.h" #include "usart.h" #include "delay.h" #include "LCD.h" #incl…

基于SSM的图书馆管理系统(有报告)。Javaee项目。ssm项目。

演示视频: 基于SSM的图书馆管理系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring Sp…

win系统环境搭建(十四)——Windows系统下使用docker安装mysql8和mysql5.7

windows环境搭建专栏🔗点击跳转 win系统环境搭建(十四)——Windows系统下使用docker安装mysql8和mysql5.7 文章目录 win系统环境搭建(十四)——Windows系统下使用docker安装mysql8和mysql5.7MySQL81.新建文件夹2.创建…

设计模式篇章(4)——十一种行为型模式

这个设计模式主要思考的是如何分配对象的职责和将对象之间相互协作完成单个对象无法完成的任务,这个与结构型模式有点像,结构型可以理解为静态的组合,例如将不同的组件拼起来成为一个更大的组件;而行为型更是一种动态或者具有某个…

three.js从入门到精通系列教程016 - three.js通过OrbitControls对立方体实现旋转和缩放

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>three.js从入门到精通系列教程016 - three.js通过OrbitControls对立方体实现旋转和缩放</title><script src"ThreeJS/three.js"></script><…

EasyRecovery2024免费电脑数据恢复软件下载

easyrecovery是一款功能强大、易于使用的硬盘数据恢复软件。这款软件可以帮助用户非常方便地恢复丢失的数据。软件非常容易使用和高效的数据恢复。感兴趣的朋友们赶快来下载吧。 无论是因为意外删除、格式化、病毒感染、系统崩溃还是其他原因&#xff0c;该软件可以帮助您恢复…

你还在找PDF转Word的工具?一个好软件推荐,赶紧查收!

前言 前段时间朋友跟小白吐槽&#xff1a;为啥PDF文件转Word文档的工具都要收费&#xff1f; 因为他们都收费啊。 小白之前找了很多类似有这种功能的工具&#xff0c;都发现&#xff1a;不但收费&#xff0c;可能还附带全家桶&#xff0c;而且还有……广告&#xff01; 在一次…

Pytest插件“pytest-selenium” - 让自动化测试更简洁

在现代Web应用的开发中,自动化测试成为确保网站质量的重要手段之一。而Pytest插件 pytest-selenium 则为开发者提供了简单而强大的工具,以便于使用Python进行Web应用的自动化测试。本文将深入介绍 pytest-selenium 插件的基本用法和实际案例,助你轻松进入无忧的Web应用测试之…

中文词向量训练-案例分析

1 数据预处理&#xff0c;解析XML文件并分词 #!/usr/bin/env python # -*- coding: utf-8 -*- # process_wiki_data.py 用于解析XML&#xff0c;将XML的wiki数据转换为text格式 import logging import os.path import sys from gensim.corpora import WikiCorpus import jieba…

phpStorm 设置终端为git bash

环境&#xff1a; windows , PhpStorm 2022 为自己的终端配置git样式的使用&#xff0c; 默认终端样式 一、打开设置&#xff0c;选择git bin 二、重新打开终端 不加--login -i 的终端 加了--login -i 的终端 最重要的一点是什么&#xff0c;他可以像mac一样支持 ctrlv 复…

扎克伯格宣布将购买35万个GPU

Meta公司马克.扎克伯格1月18日在Instagram上发表文章称&#xff0c;该公司正在加强人工智能研究团队的力量&#xff0c;并在充实AI基础设施“弹药库“&#xff0c;计划在今年年底前向芯片设计商英伟达购买35万个H100 GPU芯片&#xff0c;从而使该公司的GPU总量达到约60万个&…

利用预训练模型SKEP进行情感分析

项目地址&#xff1a;文本情感分析 - 飞桨AI Studio星河社区 (baidu.com) baidu/Senta: Baidus open-source Sentiment Analysis System. (github.com) 本项目将详细全面介绍情感分析任务的两种子任务&#xff0c;句子级情感分析和目标级情感分析。 同时演示如何使用情感分析…

线性规划案例分享

今天想写一个最优传输的简单实现&#xff0c;结果学歪了&#xff0c;学到线性规划去了&#xff0c;这里我发现了一个宝藏网站 虽然是讲计量经济的&#xff0c;但是里面提供的公式和代码我很喜欢&#xff0c;有时间可以好好读一下 https://python.quantecon.org/lp_intro.html …

如何一键部署本地Java项目到服务器上

一、背景 我开发了一个Java代码&#xff0c;现在想部署到服务器上&#xff0c;当然可以使用Jenkins部署&#xff0c;但是Jenkins配置和维护成本比较高&#xff0c;所以我今天分享的是轻量级的一键部署脚本 演示&#xff1a;本地Window的Java代码 -> Vmware虚拟机Centos7上…

面试题:RabbitMQ 有哪几种消息模式?

文章目录 前言核心组成Rabbitmq 消息模式3.1 Simple 模式ProductorCustomer 3.2 Fanout 模式ProductorCustomer 3.3 Direct 模式Productor 3.4 Topic 模式Productor 3.5 Work 模式3.5.1 轮询分发ProductorWorker1 3.5.2 公平分发Worker1 防止消息丢失机制4.1 消息确认4.2 持久化…

在WIN从零开始在QMUE上添加一块自己的开发板(一)

文章目录 一、前言二、源码编译&#xff08;一&#xff09;安装Msys2&#xff08;二&#xff09;配置GCC工具链&#xff08;三&#xff09;安装QEMU构建依赖&#xff08;四&#xff09;下载编译QEMU源码 二、QUME编程基础&#xff08;一&#xff09;QOM机制&#xff08;二&…