APEX:开启Android系统新篇章的应用扁平化技术

news2024/11/26 18:51:06

APEX:开启Android系统新篇章的应用扁平化技术

Android Pony Express (APEX) 是在 Android Q 中引入的一种容器格式,用于安装流程中较低级系统模块的更新。该格式方便了系统组件的更新,这些组件不适合标准的 Android 应用程序模型。一些示例组件包括原生服务和库、硬件抽象层(HALs)、运行时(ART)和类库。

术语 “APEX” 也可以指代 APEX 文件。

背景

尽管 Android 支持通过包安装程序应用(例如 Google Play 商店应用)来更新符合标准应用模型的模块(例如服务、活动),但对于较低级的操作系统组件使用类似的模型存在以下缺点:

  • 基于 APK 的模块无法在引导序列的早期使用。包管理器是关于应用程序的信息的中央存储库,并且只能从活动管理器启动,而活动管理器在引导过程的较后阶段变为可用。
  • APK 格式(特别是清单)是为 Android 应用程序设计的,而系统模块并不总是适合这种格式。

设计

本部分介绍 APEX 文件格式和 APEX 管理器的高级设计,其中 APEX 管理器是管理 APEX 文件的服务。

APEX 格式

这是 APEX 文件的格式。

Apex格式

在顶层,APEX 文件是一个 zip 文件,其中文件以未压缩方式存储,并位于 4 KB 边界处。

APEX 文件中的四个文件包括:

  • apex_manifest.json
  • AndroidManifest.xml
  • apex_payload.img
  • apex_pubkey

apex_manifest.json 文件包含标识 APEX 文件的包名和版本信息。

AndroidManifest.xml 文件允许 APEX 文件使用与 APK 相关的工具和基础设施,例如 ADB、PackageManager 和包安装程序应用(例如 Play Store)。例如,APEX 文件可以使用现有的工具(如 aapt)从文件中提取基本元数据。该文件包含包名和版本信息,这些信息通常也可以在 apex_manifest.json 中找到。AndroidManifest.xml 可能包含其他定位信息,这些信息可以被现有的应用发布工具使用。

对于处理 APEX 的新代码和系统,建议使用 apex_manifest.json 而不是 AndroidManifest.xml

apex_payload.img 是由 dm-verity 支持的 ext4 文件系统映像。该映像在运行时通过循环设备挂载。具体来说,哈希树和元数据块使用 libavb 创建。文件系统负载不需要解析(因为映像应该可以在原地挂载)。常规文件包含在 apex_payload.img 文件中。

apex_pubkey 是用于签名文件系统映像的公钥。在运行时,此密钥确保下载的 APEX 与内置分区中相同的实体签名了相同的 APEX。

APEX 管理器

APEX 管理器(或 apexd)是负责验证、安装和卸载 APEX 文件的本地守护进程。这个进程在引导序列的早期启动并准备好工作。APEX 文件通常预先安装在设备的 /system/apex 目录下。如果没有更新可用,APEX 管理器默认使用这些包。

APEX 的更新序列使用 PackageManager class,具体如下:

  1. 通过包安装程序应用、ADB 或其他源下载 APEX 文件。

  2. 包管理器启动安装过程。一旦识别出文件是 APEX 文件,包管理器将控制权转移到 APEX 管理器。

  3. APEX 管理器验证 APEX 文件。

  4. 如果 APEX 文件经过验证,APEX 管理器的内部数据库会更新以反映该 APEX 文件将在下一次启动时被激活。

  5. 安装请求者在包成功验证后接收一个广播信号。

  6. 为了继续安装,系统自动重新启动设备。

  7. 在重新启动时,APEX 管理器启动,读取内部数据库,并对每个列出的 APEX 文件执行以下操作:

    1. 验证 APEX 文件。
    2. 从 APEX 文件创建一个循环设备。
    3. 在循环设备顶部创建一个设备映射器块设备。
    4. 将设备映射器块设备安装到一个唯一的路径上(例如,/apex/name@ver)。

当内部数据库中列出的所有 APEX 文件都被挂载时,APEX 管理器为其他系统组件提供一个绑定器服务,以查询安装的 APEX 文件的信息。例如,其他系统组件可以查询设备中安装的 APEX 文件列表或查询特定 APEX 安装的确切路径,以便访问这些文件。

APEX 文件是 APK 文件

APEX 文件是有效的 APK 文件,因为它们是使用 APK 签名方案签名的 Zip 归档文件,其中包含一个 AndroidManifest.xml 文件。这使得 APEX 文件可以使用 APK 文件的基础设施,如软件包安装程序应用、签名实用工具和包管理器。

APEX 文件内部的 AndroidManifest.xml 文件非常简单,只包含包名、版本号和可选的 targetSdkVersionminSdkVersionmaxSdkVersion,用于定位到更精细的 SDK 版本。这些信息允许通过现有的通道(例如软件包安装程序应用和 ADB)传递 APEX 文件。

支持的文件类型

APEX 格式支持以下文件类型:

  • 本地共享库
  • 本地可执行文件
  • JAR 文件
  • 数据文件
  • 配置文件

APEX 格式只能更新其中的一些文件类型,能否更新某个文件类型取决于平台以及文件类型的接口定义的稳定程度。

签名

APEX 文件以两种方式进行签名。首先,apex_payload.img 文件(特别是附加在 apex_payload.img 上的 vbmeta 描述符)使用密钥进行签名。然后,整个 APEX 使用 APK 签名方案 V3 进行签名。这个过程中使用了两个不同的密钥。

在设备端,会安装与用于签署 vbmeta 描述符的私钥对应的公钥。APEX 管理器使用该公钥来验证请求安装的 APEX。每个 APEX 必须使用不同的密钥进行签名,在构建时和运行时都会强制执行此要求。

内置分区中的 APEX

APEX 文件可以位于内置分区(如 /system)中。分区已经过 dm-verity,因此 APEX 文件直接挂载在循环设备上。

如果内置分区中存在一个 APEX 文件,则可以通过提供具有相同包名和更高版本号的 APEX 包来更新该 APEX。新的 APEX 存储在 /data 中,并且类似于 APK 文件,较新版本会遮盖内置分区中已有的版本。但与 APK 文件不同的是,较新版本的 APEX 只有在重新启动后才会被激活使用。

内核要求

为了支持 Android 设备上的 APEX 主线模块,需要满足以下 Linux 内核特性:loop 驱动程序和 dm-verity。loop 驱动程序用于挂载 APEX 模块中的文件系统映像,dm-verity 用于验证 APEX 模块。

在使用 APEX 模块时,loop 驱动程序和 dm-verity 的性能对于实现良好的系统性能非常重要。

支持的内核版本

支持在使用内核版本 4.4 或更高的设备上运行 APEX 主线模块。新设备在使用 Android Q 或更高版本时,必须使用内核版本 4.9 或更高版本来支持 APEX 模块。

必需的内核补丁

支持 APEX 模块的必需内核补丁已包含在 Android 公共树中。要获取支持 APEX 的补丁,请使用最新版本的 Android 公共树。

内核版本 4.4

此版本仅支持从 Android 9 升级到 Android Q 并希望支持 APEX 模块的设备。建议从 android-4.4 分支进行 down-merge 以获取所需的补丁。以下是内核版本 4.4 所需的个别补丁列表。

  • UPSTREAM: loop: add ioctl for changing logical block size
    (4.4{: .external})
  • BACKPORT: block/loop: set hw_sectors
    (4.4{: .external})
  • UPSTREAM: loop: Add LOOP_SET_BLOCK_SIZE in compat ioctl
    (4.4{: .external})
  • ANDROID: mnt: Fix next_descendent
    (4.4{: .external})
  • ANDROID: mnt: remount should propagate to slaves of slaves
    (4.4{: .external})
  • ANDROID: mnt: Propagate remount correctly
    (4.4{: .external})
  • Revert “ANDROID: dm verity: add minimum prefetch size”
    (4.4{: .external})
  • UPSTREAM: loop: drop caches if offset or block_size are changed
    (4.4{: .external})
内核版本 4.9/4.14/4.19

要获得内核版本 4.9/4.14/4.19 的所需补丁,请从 android-common 分支进行 down-merge。

必需的内核配置选项

以下列表显示了支持在 Android Q 中引入的 APEX 模块所需的基本配置要求。带有星号(*)的项目是 Android 9 及更低版本的现有要求。

(*) CONFIG_AIO=Y # 支持 AIO(用于循环设备上的直接 I/O)
CONFIG_BLK_DEV_LOOP=Y # 支持循环设备
CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 # 预创建 16 个循环设备
(*) CONFIG_CRYPTO_SHA1=Y # DM-verity 的 SHA1 哈希函数支持
(*) CONFIG_CRYPTO_SHA256=Y # DM-verity 的 SHA256 哈希函数支持
CONFIG_DM_VERITY=Y # 支持 DM-verity

内核命令行参数要求

为了支持 APEX,确保内核命令行参数满足以下要求。

  • loop.max_loop 不能设置
  • loop.max_part 必须小于等于 8

构建 APEX

注意:由于 APEX 的实现细节仍在开发中,本节内容可能会有所变动。

本节描述了如何使用 Android 构建系统构建 APEX。以下是一个名为 apex.test 的 APEX 的 Android.bp 示例。

apex {
    name: "apex.test",
    manifest: "apex_manifest.json",
    file_contexts: "file_contexts",
    // libc.so 和 libcutils.so 包含在 APEX 中
    native_shared_libs: ["libc", "libcutils"],
    binaries: ["vold"],
    java_libs: ["core-all"],
    prebuilts: ["my_prebuilt"],
    compile_multilib: "both",
    key: "apex.test.key",
    certificate: "platform",
}

apex_manifest.json 示例:

{
  "name": "com.android.example.apex",
  "version": 1
}

file_contexts 示例:

(/.*)?           u:object_r:system_file:s0
/sub(/.*)?       u:object_r:sub_file:s0
/sub/file3       u:object_r:file3_file:s0

APEX 中的文件类型和位置

文件类型在 APEX 中的位置
共享库/lib/lib64 (/lib/arm 用于在 x86 上的翻译 ARM)
可执行文件/bin
Java 库/javalib
预构建文件/etc

传递依赖关系

APEX 文件自动包括本地共享库或可执行文件的传递依赖关系。例如,如果 libFoo 依赖于 libBar,那么当只有 libFoonative_shared_libs 属性中列出时,这两个库都会被包含进来。

处理多个 ABI

针对设备的主要 ABI 和次要 ABI 都要安装 native_shared_libs 属性。如果一个 APEX 针对只支持单个 ABI 的设备(即仅支持 32 位或 64 位),那么只会安装相应 ABI 的库。

只为设备的主要 ABI 安装 binaries 属性,如下所示:

  • 如果设备仅支持 32 位,只会安装 32 位二进制文件的变体。
  • 如果设备支持 32/64 位双 ABI,但配置了 TARGET_PREFER_32_BIT_EXECUTABLES=true,那么只会安装 32 位二进制文件的变体。
  • 如果设备仅支持 64 位,只会安装 64 位二进制文件的变体。
  • 如果设备支持 32/64 位双 ABI,但未配置 TARGET_PREFER_32_BIT_EXECUTABLES=true`,那么只会安装 64 位二进制文件的变体。

为了对本地库和二进制文件的 ABI 进行精细控制,可以使用 multilib.[first|lib32|lib64|prefer32|both].[native_shared_libs|binaries] 属性。

  • first:与设备的主要 ABI 匹配。这是二进制文件的默认配置。
  • lib32:与设备的 32 位 ABI 匹配(如果支持)。
  • lib64:与设备的 64 位 ABI 匹配(如果支持)。
  • prefer32:与设备的 32 位 ABI 匹配(如果支持)。如果不支持 32 位 ABI,则与设备的 64 位 ABI 匹配。
  • both:同时匹配两个 ABI。这是 native_shared_libraries 的默认配置。

javalibrariesprebuilts 属性与 ABI 无关。

以下示例适用于支持 32/64 位并且不偏好 32 位的设备:

apex {
    // 其他属性省略
    native_shared_libs: ["libFoo"], // 安装 32 位和 64 位
    binaries: ["exec1"], // 只安装 64 位,32 位不安装
    multilib: {
        first: {
            native_shared_libs: ["libBar"], // 只安装 64 位,32 位不安装
            binaries: ["exec2"], // 与没有 multilib.first 的 binaries 一样
        },
        both: {
            native_shared_libs: ["libBaz"], // 与没有 multilib 的 native_shared_libs 一样
            binaries: ["exec3"], // 安装 32 位和 64},
        prefer32: {
            native_shared_libs: ["libX"], // 只安装 32 位,64 位不安装
        },
        lib64: {
            native_shared_libs: ["libY"], // 只安装 64 位,32 位不安装
        },
    },
}

vbmeta签名

使用不同的密钥对每个APEX进行签名。当需要新的密钥时,创建一个公私钥对,并制作一个apex_key模块。使用key属性使用密钥对APEX进行签名。公钥会自动包含在具有名称avb_pubkey的APEX中。

创建一个RSA密钥对。

$ openssl genrsa -out foo.pem 4096

从密钥对中提取公钥。

$ avbtool extract_public_key --key foo.pem --output foo.avbpubkey

在Android.bp文件中:

apex_key {
    name: "apex.test.key",
    public_key: "foo.avbpubkey",
    private_key: "foo.pem",
}

在上述例子中,公钥的名称(foo)成为该密钥的ID。用于签署APEX的密钥的ID会写入APEX中。运行时,apexd会使用设备中具有相同ID的公钥验证APEX。

ZIP签名

以与APK相同的方式对APEX进行签名。对APEX进行两次签名,一次是对迷你文件系统(apex_payload.img文件)的签名,一次是对整个文件的签名。

要在文件级别对APEX进行签名,可以通过以下三种方式之一设置certificate属性:

  • 未设置:如果未设置任何值,则使用位于PRODUCT_DEFAULT_DEV_CERTIFICATE路径下的证书对APEX进行签名。如果没有设置标志,则路径默认为build/target/product/security/testkey
  • <name>:使用与PRODUCT_DEFAULT_DEV_CERTIFICATE位于相同目录中的<name>证书对APEX进行签名。
  • :<name>:使用由Soong模块命名为<name>的证书进行签名。证书模块可以定义如下:
android_app_certificate {
    name: "my_key_name",
    certificate: "dir/cert",
    // this will use dir/cert.x509.pem (the cert) and dir/cert.pk8 (the private key)
}

注意:keycertificate的值不需要来自相同的公私钥对。APK签名(由certificate指定)是必需的,因为APEX是一个APK。

安装APEX

要安装APEX,请使用ADB。

$ adb install apex_file_name
$ adb reboot

使用APEX

重启后,APEX会挂载在/apex/<apex_name>@<version>目录下。可以同时挂载多个版本的相同APEX。在挂载路径中,与最新版本对应的路径会以绑定挂载的方式出现在/apex/<apex_name>下。

客户端可以使用绑定挂载的路径从APEX中读取或执行文件。

通常的APEX使用方式如下所示:

  1. OEM或ODM在设备出货时在/system/apex下预装APEX。
  2. 可通过/apex/<apex_name>/路径访问APEX中的文件。
  3. 当在/data/apex中安装了更新版本的APEX后,路径在重启后指向新的APEX。

使用APEX更新服务

要使用APEX更新服务:

  1. 将系统分区中的服务标记为可更新。在服务定义中添加选项updatable

    /system/etc/init/myservice.rc:
    
    service myservice /system/bin/myservice
        class core
        user system
        ...
        updatable
    
  2. 为更新后的服务创建一个新的.rc文件。使用override选项重新定义现有服务。

    /apex/my.apex@1/etc/init.rc:
    
    service myservice /apex/my.apex@1/bin/myservice
        class core
        user system
        ...
        override
    

服务定义只能在APEX的.rc文件中定义。不支持在APEX中使用Action触发器。

如果标记为可更新的服务在APEX被激活之前启动,启动将延迟,直到APEX的激活完成。

配置系统以支持APEX更新

将以下系统属性设置为true以支持APEX文件更新。

<device.mk>:

PRODUCT_PROPERTY_OVERRIDES += ro.apex.updatable=true

BoardConfig.mk:
TARGET_FLATTEN_APEX := false

或者只需要:

<device.mk>:

$(call inherit-product, $(SRC_TARGET_DIR)/product/updatable_apex.mk)

扁平化 APEX

对于一些旧设备来说,更新内核以完全支持 APEX 有时是不可能或不现实的。例如,内核可能是没有使用 CONFIG_BLK_DEV_LOOP=Y 编译的,而这对于在 APEX 中挂载文件系统映像是至关重要的。

扁平化 APEX 是一个特别构建的 APEX,它可以在具有旧内核的设备上激活。扁平化 APEX 中的文件直接安装到内置分区下的目录中。例如,扁平化 APEX my.apex 中的 lib/libFoo.so 被安装到 /system/apex/my.apex/lib/libFoo.so

激活扁平化 APEX 不涉及环回设备。整个目录 /system/apex/my.apex 直接绑定到 /apex/name@ver

无法通过从网络下载已更新的 APEX 的方式更新扁平化 APEX,因为下载的 APEX 无法被扁平化。扁平化 APEX 只能通过常规 OTA 进行更新。

请注意,目前扁平化 APEX 是默认配置。这意味着除非您明确地配置设备以支持可更新的 APEX(如上所述),否则默认情况下所有 APEX 都是扁平化的。

还要注意,在设备中混合扁平化和非扁平化的 APEX 是不受支持的。它应该是全部非扁平化或全部扁平化。这在为 Mainline 等项目提供预签名 APEX 预构建时尤其重要。那些不是预签名的 APEX(即从源代码构建的)也应该是非扁平化的,并在这种情况下使用正确的密钥进行签名。设备应该继承 updatable_apex.mk,如上所述。

在开发 APEX 时考虑的替代方案

以下是在设计 APEX 文件格式时我们考虑过的一些选项,以及为什么包含或排除它们。

常规软件包管理系统

Linux 发行版有像 dpkgrpm 这样的软件包管理系统,它们功能强大、成熟并且稳健。但是,我们没有采用它们作为 APEX 的管理系统,因为它们无法在安装之后保护软件包的完整性。只有在安装软件包时才会进行验证。攻击者可以在不被察觉的情况下破坏已安装软件包的完整性。这是 Android 的一个退化,因为所有系统组件都被存储在只读文件系统中,每个 I/O 都由 dm-verity 保护。任何对系统组件的篡改都必须被禁止或可检测,以便设备在受损时拒绝启动。

用于完整性的 dm-crypt

APEX 容器中的文件来自内置分区(例如 /system 分区),这些分区由 dm-verity 保护,即使在装载分区后也禁止对文件进行修改。为了向文件提供相同的安全性,所有 APEX 中的文件都存储在与哈希树和 vbmeta 描述符配对的文件系统映像中。如果没有了 dm-verity,在 /data 分区中的 APEX 就容易遭受在验证和安装之后的意外修改攻击。

事实上,/data 分区也受到加密层(如 dm-crypt)的保护。虽然这提供了一定程度的篡改保护,但它的主要目的是隐私保护,而不是完整性保护。当攻击者获得访问 data 分区的权限时,就再也没有进一步的保护了,这再次退化了与每个系统组件位于 /system 分区有所不同的情况。APEX 文件中的哈希树加上 dm-verity 提供了相同级别的内容保护。

重定向路径从 /system/apex

APEX 包中打包的系统组件文件可以通过新路径访问,比如 /apex/<name>/lib/libfoo.so。当文件是 /system 分区的一部分时,它们可以通过 /system/lib/libfoo.so 这样的路径访问。APEX 文件的客户端(其他 APEX 文件或平台)应使用新路径。这种路径变更可能需要对现有代码进行更新。

避免路径变化的一种方法是在 APEX 文件中将文件内容覆盖到 /system 分区上。然而,我们决定不在 /system 分区上覆盖文件,因为我们认为随着被覆盖(甚至堆叠在一起)的文件数量的增加,这将对性能产生负面影响。

另一种选择是劫持文件访问函数,如 openstatreadlink,以便以 /system 开头的路径重定向到其在 /apex 下对应的路径。我们放弃了这个选项,因为实际上很难改变接受路径的所有函数。例如,有些应用程序静态链接 Bionic,而 Bionic 实现了这些函数。在这种情况下,重定向不会发生在应用上。

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

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

相关文章

计算机系大学生,可以通过Java做什么副业?这篇文章给你答案!

文章目录 前言发现副业机会提高效率面向人群 如何开启自己的副业价格优势需要课设的人多吗怎么宣传生成器的使用 生成器介绍安装功能介绍文档查询功能生成的JavaWeb系统示例生成的C#生成的Javaswing生成的VueER图 、UML、功能图..生成的C、C系统 前言 计算机系科班出身的学生&a…

轻量服务器2核与1核的区别

​ 1.核心数量 轻量服务器2核与1核最明显的区别在于核心数量。1核服务器只有一个处理器核心&#xff0c;而2核服务器有两个处理器核心。这使得2核服务器在处理数据时能够同时执行更多的任务。 2.并行处理能力 由于只有1个核心&#xff0c;1核服务器不具备并行处理任务的能力。而…

天津专升本文化课考试计算机应用基础考试大纲(2023年9月修订)

天津市高等院校“高职升本科”招生统一考试计算机应用基础考试大纲&#xff08;2023年9月修订&#xff09; 一、考试性质 天津市高等院校“高职升本科”招生统一考试是由合格的高职高专毕业生参加的选拔性 考试。高等院校根据考生的成绩&#xff0c;按照已确定的招生计划&am…

低功耗蓝牙物联网:未来连接的无限可能

物联网是连接各种设备和传感器的网络&#xff0c;其目的是实现信息的交换和共享&#xff0c;提高效率并优化生活。在这个领域&#xff0c;低功耗蓝牙&#xff08;BLE&#xff09;正在发挥着越来越重要的作用。 低功耗蓝牙是一种无线通信技术&#xff0c;它的主要特点是低功耗和…

HarmonyOS之 组件的使用

一 容器 1.1 容器分类 Column表示沿垂直方向布局的容器。Row表示沿水平方向布局的容器。 1.2 主轴和交叉轴 主轴&#xff1a;在Column容器中的子组件是按照从上到下的垂直方向布局的&#xff0c;其主轴的方向是垂直方向&#xff1b;在Row容器中的组件是按照从左到右的水平方向…

TiDB 7.1.0 LTS 特性解读丨关于资源管控 (Resource Control) 应该知道的 6 件事

TiDB 7.1.0 LTS 在前段时间发布&#xff0c;相信很多同学都已经抢先使用了起来&#xff0c;甚至都已然经过一系列验证推向了生产环境。面对 TiDB 7.1 若干重要特性&#xff0c;新 GA 的资源管控 (Resource Control) 是必须要充分理解、测试的一个重量级特性。对于常年奋斗在一线…

编译vtk源码

vtk和opengl关系 VTK&#xff08;Visualization Toolkit&#xff09;和OpenGL&#xff08;Open Graphics Library&#xff09;都是用于图形可视化和渲染的重要工具&#xff0c;但它们在图形编程中的角色和关系略有不同。 OpenGL&#xff1a; OpenGL是一种开放的图形库和API&a…

uniapp自定义播放器

问题描述&#xff1a;我是真无语啊&#xff0c;就是有一个目录切换的地方&#xff0c;然后切换音频&#xff0c;结果你猜怎么着&#xff0c;嘿&#xff0c;音频他不播放了。也就是下面这个方法都不进去了打印的时候&#xff0c;音频播放都播放不了了&#xff0c;我尝试了销毁在…

前端提交规范 ESLint + Prettier + husky + lint-staged

如何统一代码风格&#xff0c;规范提交呢&#xff1f; 推荐使用前端规范全家桶 ESLint Prettier husky lint-staged。 eslint (github.com/eslint/esli…)JavaScript 代码检测工具&#xff0c;检测并提示错误或警告信息prettier (github.com/prettier/pr…) 代码自动化格式…

【面试题】Js数组去重都有哪些方法?

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 表妹一键制作自己的五星红旗国庆头像&#xff0c;超好看 1. indexOf 定义&#xff1a; indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置…

基于SSM的田径运动会成绩管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

秒懂生成式AI—大语言模型是如何生成内容的?

备受关注的大语言模型&#xff0c;核心是自然语言的理解与文本内容的生成&#xff0c;对于此&#xff0c;你是否好奇过它们究竟是如何理解自然语言并生成内容的&#xff0c;其工作原理又是什么呢&#xff1f; 要想了解这个&#xff0c;我们就不得不先跳出大语言模型的领域&…

Hadoop初识及信息安全(大数据的分布式存储和计算平台)

目录 什么是Hadoop Hadoop的特点 Hadoop优点 Hadoop的缺点 Hadoop的重要组成 信息安全 什么是Hadoop Hadoop 是一个适合大数据的分布式存储和计算平台。 Hadoop的广义和狭义区分&#xff1a; 狭义的Hadoop:指的是一个框架&#xff0c;Hadoop是由三部分组成&#xff1a;H…

做测试半年,我已经掉了4个坑……

从事软件测试工作已经半年多了&#xff0c;刚入职的时候还是一个缺乏实际经验的小白&#xff0c;而现在拿到需求之后也能比较快速地熟悉业务并顺利开展测试&#xff0c;虽然不能说掌握了很多技能&#xff0c;但是相比之前也是有不少收获的&#xff0c;在这个过程中我总结了一点…

使用vue-cli搭建SPA项目

一.SPA项目的构建 前提 nodeJS环境已经搭建完毕 node -v npm -v 什么是SPA项目 SPA&#xff08;Single Page Application&#xff09;项目是一种使用单页面架构的Web应用项目。在SPA项目中&#xff0c;整个应用程序只有一个HTML页面&#xff0c;通过动态加载数据和更新DOM来实…

计算机竞赛 深度学习+opencv+python实现昆虫识别 -图像识别 昆虫识别

文章目录 0 前言1 课题背景2 具体实现3 数据收集和处理3 卷积神经网络2.1卷积层2.2 池化层2.3 激活函数&#xff1a;2.4 全连接层2.5 使用tensorflow中keras模块实现卷积神经网络 4 MobileNetV2网络5 损失函数softmax 交叉熵5.1 softmax函数5.2 交叉熵损失函数 6 优化器SGD7 学…

springboot实现发送邮箱验证码

准备工作 在邮箱官网开放SMTP授权&#xff0c;获取相应密钥&#xff0c;才可以进行发送邮件 这里以网易163邮箱为例&#xff0c;登录邮箱后&#xff0c;依次点击“设置-POP3/SMTP/IMAP” &#xff0c;然后开启SMTP服务。这时候会提示一个授权码&#xff0c;例如&#xff1a;H…

I2C子系统、读取温湿度的逻辑及代码

一、IIC子系统 两根线&#xff1a; scl:时钟线 sda:数据线 iic有4种信号&#xff1a; 起始信号&#xff08;start&#xff09;:scl是高电平&#xff0c;sda下降沿 终止信号&#xff08;stop&#xff09;:scl高电平&#xff0c;sda上升沿 应答信号&#xf…

面试官:说说JavaScript中的数据类型?区别?

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 一、概述 二、显示转换 Number() parseInt() String() Boolean() 三、隐式转换 自动转换为布尔值 自动转换…

SOLIDWORKS2024新功能--SOLIDWORKS篇(二)

该章节包括以下主题&#xff1a; 切口工具槽口延伸戳记工具薄片和槽口中的切割法线 切口工具 您可以使用切口工具在空心或薄壁圆柱体和圆锥体中生成切口。通过选择圆柱面或圆锥面上的边线&#xff0c;您可以将零件平展为钣金。 在早期版本中&#xff0c;如果您有圆柱形或圆锥形…