android HAL层崩溃排查记录

要最近在调试系统HDMI CEC功能时,遇到一个奇怪的崩溃问题,这边记录下。

初步分析

先上日志:

--------- beginning of crash
03-06 10:48:25.503  1133  1133 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
03-06 10:48:25.503  1133  1133 F DEBUG   : Build fingerprint: ':13/TD1A.220804.031/3582:userdebug/release-keys'
03-06 10:48:25.503  1133  1133 F DEBUG   : Revision: '0'
03-06 10:48:25.503  1133  1133 F DEBUG   : ABI: 'arm64'
03-06 10:48:25.503  1133  1133 F DEBUG   : Timestamp: 2024-03-06 10:48:25.490260378-0500
03-06 10:48:25.503  1133  1133 F DEBUG   : Process uptime: 6s
03-06 10:48:25.503  1133  1133 F DEBUG   : Cmdline: /vendor/bin/hw/android.hardware.tv.cec@1.0-service
03-06 10:48:25.503  1133  1133 F DEBUG   : pid: 615, tid: 615, name: cec@1.0-service  >>> /vendor/bin/hw/android.hardware.tv.cec@1.0-service <<<
03-06 10:48:25.503  1133  1133 F DEBUG   : uid: 1000
03-06 10:48:25.503  1133  1133 F DEBUG   : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
03-06 10:48:25.503  1133  1133 F DEBUG   : signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
03-06 10:48:25.503  1133  1133 F DEBUG   : Abort message: 'stack corruption detected (-fstack-protector)'
03-06 10:48:25.503  1133  1133 F DEBUG   :     x0  0000000000000000  x1  0000000000000267  x2  0000000000000006  x3  0000007fe8d61420
03-06 10:48:25.503  1133  1133 F DEBUG   :     x4  0000000000808080  x5  0000000000808080  x6  0000000000808080  x7  8080808080808080
03-06 10:48:25.503  1133  1133 F DEBUG   :     x8  00000000000000f0  x9  00000077cc5b4a00  x10 0000000000000001  x11 00000077cc5f2ce4
03-06 10:48:25.503  1133  1133 F DEBUG   :     x12 0101010101010101  x13 000000007fffffff  x14 0000000000001686  x15 0000000000000030
03-06 10:48:25.503  1133  1133 F DEBUG   :     x16 00000077cc657d60  x17 00000077cc634b70  x18 00000077d3ae2000  x19 0000000000000267
03-06 10:48:25.504  1133  1133 F DEBUG   :     x20 0000000000000267  x21 00000000ffffffff  x22 0000000000000030  x23 00000077d302a000
03-06 10:48:25.504  1133  1133 F DEBUG   :     x24 0000000000000004  x25 00000077d302a000  x26 00000077d302a000  x27 b40000763c5972c8
03-06 10:48:25.504  1133  1133 F DEBUG   :     x28 0000000000000000  x29 0000007fe8d614a0
03-06 10:48:25.504  1133  1133 F DEBUG   :     lr  00000077cc5e4868  sp  0000007fe8d61400  pc  00000077cc5e4894  pst 0000000000001000
03-06 10:48:25.504  1133  1133 F DEBUG   : backtrace:
03-06 10:48:25.504  1133  1133 F DEBUG   :       #00 pc 0000000000051894  /apex/com.android.runtime/lib64/bionic/libc.so (abort+164) (BuildId: 058e3ec96fa600fb840a6a6956c6b64e)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #01 pc 00000000000664e8  /apex/com.android.runtime/lib64/bionic/libc.so (__stack_chk_fail+20) (BuildId: 058e3ec96fa600fb840a6a6956c6b64e)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #02 pc 0000000000006954  /vendor/lib64/hw/android.hardware.tv.cec@1.0-impl.so (android::hardware::tv::cec::V1_0::implementation::HdmiCec::getPortInfo(std::__1::function<void (android::hardware::hidl_vec<android::hardware::tv::cec::V1_0::HdmiPortInfo> const&)>)+376) (BuildId: 647cc2659b38df33f681ae1d58a04c74)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #03 pc 0000000000016540  /vendor/lib64/android.hardware.tv.cec@1.0.so (android::hardware::tv::cec::V1_0::BnHwHdmiCec::_hidl_getPortInfo(android::hidl::base::V1_0::BnHwBase*, android::hardware::Parcel const&, android::hardware::Parcel*, std::__1::function<void (android::hardware::Parcel&)>)+252) (BuildId: 8ca54579dc40d30a62824bb0a91d98f4)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #04 pc 0000000000017668  /vendor/lib64/android.hardware.tv.cec@1.0.so (android::hardware::tv::cec::V1_0::BnHwHdmiCec::onTransact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function<void (android::hardware::Parcel&)>)+1132) (BuildId: 8ca54579dc40d30a62824bb0a91d98f4)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #05 pc 000000000008ee40  /apex/com.android.vndk.v33/lib64/libhidlbase.so (android::hardware::BHwBinder::transact(unsigned int, android::hardware::Parcel const&, android::hardware::Parcel*, unsigned int, std::__1::function<void (android::hardware::Parcel&)>)+156) (BuildId: 3fafcf3a9734f0d41045c2b5f828b363)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #06 pc 0000000000093dfc  /apex/com.android.vndk.v33/lib64/libhidlbase.so (android::hardware::IPCThreadState::executeCommand(int)+2784) (BuildId: 3fafcf3a9734f0d41045c2b5f828b363)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #07 pc 00000000000931bc  /apex/com.android.vndk.v33/lib64/libhidlbase.so (android::hardware::IPCThreadState::getAndExecuteCommand()+224) (BuildId: 3fafcf3a9734f0d41045c2b5f828b363)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #08 pc 0000000000094388  /apex/com.android.vndk.v33/lib64/libhidlbase.so (android::hardware::IPCThreadState::joinThreadPool(bool)+172) (BuildId: 3fafcf3a9734f0d41045c2b5f828b363)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #09 pc 00000000000010e4  /vendor/bin/hw/android.hardware.tv.cec@1.0-service (main+144) (BuildId: f6a65dc725b06643501c269fa219b717)
03-06 10:48:25.504  1133  1133 F DEBUG   :       #10 pc 000000000004a0f4  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+96) (BuildId: 058e3ec96fa600fb840a6a6956c6b64e)
03-06 10:48:26.344  1267  1267 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

 初步看了下,崩溃在android.hardware.tv.cec@1.0-service 服务进程中。那么简单,上addr2line工具。

addr2line

addr2line --help
Usage: addr2line [option(s)] [addr(s)]Convert addresses into line number/file name pairs.If no addresses are specified on the command line, they will be read from stdinThe options are:@<file>                Read options from <file>-a --addresses         Show addresses-b --target=<bfdname>  Set the binary file format-e --exe=<executable>  Set the input file name (default is a.out)-i --inlines           Unwind inlined functions-j --section=<name>    Read section-relative offsets instead of addresses-p --pretty-print      Make the output easier to read for humans-s --basenames         Strip directory names-f --functions         Show function names-C --demangle[=style]  Demangle function names-R --recurse-limit     Enable a limit on recursion whilst demangling.  [Default]-r --no-recurse-limit  Disable a limit on recursion whilst demangling-h --help              Display this information-v --version           Display the program's versionaddr2line: supported targets: elf64-x86-64 elf32-i386 elf32-iamcu elf32-x86-64 pei-i386 pe-x86-64 pei-x86-64 elf64-l1om elf64-k1om elf64-little elf64-big elf32-little elf32-big pe-bigobj-x86-64 pe-i386 srec symbolsrec verilog tekhex binary ihex plugin
Report bugs to <https://sourceware.org/bugzilla/>

addr2line -ife out/target/product/aosp/symbols/vendor/lib64/hw/android.hardware.tv.cec@1.0-impl.so 0000000000006954

llvm-addr2line

记得android编译链接工具更新了,确实不能用这个版本了。下面切成llvm-addr2line工具。

prebuilts/clang/host/linux-x86/llvm-binutils-stable/llvm-addr2line --help
OVERVIEW: llvm-addr2lineUSAGE: llvm-addr2line [options] addresses...OPTIONS:--addresses           Show address before line information--adjust-vma=<offset> Add specified offset to object file addresses-a                    Alias for --addresses--basenames           Strip directory names from paths-C                    Alias for --demangle--debug-file-directory=<dir>Path to directory where to look for debug files-demangle=false       Alias for --no-demangle-demangle=true        Alias for --demangle--demangle            Demangle function names--dia                 Use the DIA library to access symbols (Windows only)--dwp=<file>          Path to DWP file to be use for any split CUs-e=<file>             Alias for --obj--exe=<file>          Alias for --obj--exe <file>          Alias for --obj-e <file>             Alias for --obj-f=<value>            Alias for --functions=--fallback-debug-path=<dir>Fallback path for debug binaries--functions=<value>   Print function name for a given address--functions           Print function name for a given address-f                    Alias for --functions--help                Display this help--inlines             Print all inlined frames for a given address--inlining=false      Alias for --no-inlines--inlining=true       Alias for --inlines--inlining            Alias for --inlines-i                    Alias for --inlines--no-demangle         Don't demangle function names--no-inlines          Do not print inlined frames--no-untag-addresses  Remove memory tags from addresses before symbolization--obj=<file>          Path to object file to be symbolized (if not provided, object file should be specified for each input line)--output-style=style  Specify print style. Supported styles: LLVM, GNU, JSON--pretty-print        Make the output more human friendly--print-address       Alias for --addresses--print-source-context-lines=<value>Print N lines of source file context-p                    Alias for --pretty-print--relative-address    Interpret addresses as addresses relative to the image base--relativenames       Strip the compilation directory from paths-s                    Alias for --basenames--verbose             Print verbose line info--version             Display the version-v                    Alias for --versionllvm-symbolizer Mach-O Specific Options:--default-arch=<value> Default architecture (for multi-arch objects)--dsym-hint=<dir>      Path to .dSYM bundles to search for debug info for the object filesPass @FILE as argument to read options from FILE.

于是,定位命令行切换成:

prebuilts/clang/host/linux-x86/llvm-binutils-stable/llvm-addr2line -ife out/target/product/aosp/symbols/vendor/lib64/hw/android.hardware.tv.cec@1.0-impl.so 0000000000006954
_ZN7android8hardware2tv3cec4V1_014implementation7HdmiCec11getPortInfoENSt3__18functionIFvRKNS0_8hidl_vecINS3_12HdmiPortInfoEEEEEE
hardware/interfaces/tv/cec/1.0/default/HdmiCec.cpp:0

怎么可能是源码的0行,现在轮到我崩溃了。。

背景知识

看来直接通过上面的通用方式,不能直接定位到崩溃点的代码了。

那从进程名,打印出来的函数名:getPortInfo ,对应的崩溃错误:

Abort message: 'stack corruption detected (-fstack-protector)'

来看看能不能发现些什么。

-fstack-protector 检测到的堆栈损坏

编译器的 -fstack-protector 选项会在具有栈上缓冲区的函数中插入检查机制,以防止缓冲区溢出。默认情况下,系统会为平台代码(而非应用)启用此选项。启用此选项后,编译器会向函数序言添加指令,以在堆栈上写入刚刚超过上一局部值的随机值,并向函数结尾添加指令以进行回读并确认是否发生更改。如果该值已更改,则表示该值已被缓冲区溢出覆盖,因此该结尾会调用 __stack_chk_fail 来记录消息和中止。

pid: 26717, tid: 26717, name: crasher  >>> crasher <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: 'stack corruption detected'r0 00000000  r1 0000685d  r2 00000006  r3 00000008r4 ffd516d8  r5 0000685d  r6 0000685d  r7 0000010cr8 00000000  r9 00000000  sl 00000000  fp ffd518bcip 00000000  sp ffd516c8  lr ee63ece3  pc ee66ef0c  cpsr 000e0010backtrace:#00 pc 00049f0c  /system/lib/libc.so (tgkill+12)#01 pc 00019cdf  /system/lib/libc.so (abort+50)#02 pc 0001e07d  /system/lib/libc.so (__libc_fatal+24)#03 pc 0004863f  /system/lib/libc.so (__stack_chk_fail+6)#04 pc 000013ed  /system/xbin/crasher (smash_stack+76)#05 pc 00001591  /system/xbin/crasher (do_action+280)#06 pc 00002219  /system/xbin/crasher (main+100)#07 pc 000177a1  /system/lib/libc.so (__libc_init+48)#08 pc 00001144  /system/xbin/crasher (_start+96)

0x00 概述

栈溢出保护是一种缓冲区溢出攻击缓解手段,当函数存在缓冲区溢出攻击漏洞时,攻击者可以覆盖栈上的返回地址来让shellcode能够得到执行。当启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息能否合法,假如不合法就中止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary(以下统一使用canary)。

gcc在4.2版本中增加了-fstack-protector和-fstack-protector-all编译参数以支持栈保护功能,4.9新添加了-fstack-protector-strong编译参数让保护的范围更广。以下是-fstack-protector和-fstack-protector-strong的区别:

原创技术干货 | 解读Linux安全机制之栈溢出保护

Linux系统中存在着三种类型的栈:

  1. 应用程序栈:工作在Ring3,由应用程序来维护;

  2. 内核进程上下文栈:工作在Ring0,由内核在创立线程的时候创立;

  3. 内核中断上下文栈:工作在Ring0,在内核初始化的时候给每个CPU核心创立一个。

看来,是哪里可能存在内存溢出。联系到用户之前在未进行多个hdmi cec端口配置时,未有发现此问题。配置多个口后,出现此问题。而 java层代码一致,有变动的,就是HAL层这块了。

定位改动

因为有比较明确的改动地方引起,就从改动开始排查吧。

HAL被调用的地方,也是上面崩溃指向的函数:

Return<void> HdmiCec::getPortInfo(getPortInfo_cb _hidl_cb) {struct hdmi_port_info* legacyPorts;int numPorts;hidl_vec<HdmiPortInfo> portInfos;mDevice->get_port_info(mDevice, &legacyPorts, &numPorts);portInfos.resize(numPorts);for (int i = 0; i < numPorts; ++i) {portInfos[i] = {.type = static_cast<HdmiPortType>(legacyPorts[i].type),.portId = static_cast<uint32_t>(legacyPorts[i].port_id),.cecSupported = legacyPorts[i].cec_supported != 0,.arcSupported = legacyPorts[i].arc_supported != 0,.physicalAddress = legacyPorts[i].physical_address};}_hidl_cb(portInfos);return Void();
}

初始版本

struct hdmi_cec_context_t {hdmi_cec_device_t device;/* our private state goes below here */event_callback_t event_callback;void* cec_arg;struct hdmi_port_info port;int fd;int en_mask;bool enable;bool system_control;int phy_addr;bool hotplug;bool cec_init;
};

static void hdmi_cec_get_port_info(const struct hdmi_cec_device* dev,struct hdmi_port_info* list[], int* total)
{
...list[0] = &ctx->port;list[0]->type = HDMI_OUTPUT;list[0]->port_id = HDMI_CEC_PORT_ID;list[0]->cec_supported = support;list[0]->arc_supported = 0;list[0]->physical_address = val;*total = 1;
}

问题版本

struct hdmi_cec_context_t {hdmi_cec_device_t device;/* our private state goes below here */event_callback_t event_callback;void* cec_arg;struct hdmi_port_info port[4];int fd;int en_mask;bool enable;bool system_control;int phy_addr;bool hotplug;bool cec_init;
};
static void hdmi_cec_get_port_info(const struct hdmi_cec_device* dev,struct hdmi_port_info* list[], int* total)
{
...list[0] = &ctx->port[0];list[0]->type = HDMI_INPUT;list[0]->port_id = 1;list[0]->cec_supported = support;list[0]->arc_supported = 0;list[0]->physical_address = 0x1000;//CVT_DEF_ARC_PHYSICAL_ADDRESS;list[1] = &ctx->port[1];list[1]->type = HDMI_INPUT;list[1]->port_id = 2;list[1]->cec_supported = support;list[1]->arc_supported = 0;list[1]->physical_address = 0x3000;list[2] = &ctx->port[2];list[2]->type = HDMI_INPUT;list[2]->port_id = 3;list[2]->cec_supported = support;list[2]->arc_supported = 0;list[2]->physical_address = 0x4000;list[3] = &ctx->port[3];list[3]->type = HDMI_INPUT;list[3]->port_id = 4;list[3]->cec_supported = support;list[3]->arc_supported = 1;list[3]->physical_address = 0x2000;*total = 4;
}

上面测试过,只添加2个(list[0],list[1]),也是不会崩溃。看起来,是个内存溢出的问题。排查了相关数量定义,限制,似乎是没有找到有限制2个的。反馈还出现过一次配置3个的可以。

关注下面变量的定义及传递: 

struct hdmi_port_info* legacyPorts;
mDevice->get_port_info(mDevice, &legacyPorts, &numPorts);

hdmi_cec_get_port_info的参数

struct hdmi_port_info* list[] 是一个指针数组,其中每个元素都是指向 struct hdmi_port_info 结构体的指针。list 是一个指针数组,它可以存储 struct hdmi_port_info* 类型的指针。

修正版本

static void hdmi_cec_get_port_info(const struct hdmi_cec_device* dev,struct hdmi_port_info* list[], int* total)
{...ctx->port[0].type = HDMI_INPUT;ctx->port[0].port_id = 1;ctx->port[0].cec_supported = 1;ctx->port[0].arc_supported = 1;ctx->port[0].physical_address = 0x1000;ctx->port[1].type = HDMI_INPUT;ctx->port[1].port_id = 2;ctx->port[1].cec_supported = 1;ctx->port[1].arc_supported = 0;ctx->port[1].physical_address = 0x2000;ctx->port[2].type = HDMI_INPUT;ctx->port[2].port_id = 3;ctx->port[2].cec_supported = 1;ctx->port[2].arc_supported = 0;ctx->port[2].physical_address = 0x3000;ctx->port[3].type = HDMI_INPUT;ctx->port[3].port_id = 4;ctx->port[3].cec_supported = 1;ctx->port[3].arc_supported = 0;ctx->port[3].physical_address = 0x4000;*list = &ctx->port[0];*total = 4;}

问题分析

让我们逐步解释上述过程中涉及到的相关步骤:

1. 定义 `legacyPorts` 指针:

struct hdmi_port_info* legacyPorts;
   这行代码定义了一个名为 `legacyPorts` 的指针,它的类型是 `struct hdmi_port_info*`,即指向 `struct hdmi_port_info` 结构体的指针。

2. 调用 hdmi_cec_get_port_info 函数:

hdmi_cec_get_port_info(mDevice, &legacyPorts, &numPorts);
   在这行代码中,我们将 `legacyPorts` 的地址(即指向 `legacyPorts` 指针的指针)和 `numPorts` 的地址(即指向 `numPorts` 变量的指针)传递给 `hdmi_cec_get_port_info` 函数。

3. 在 `hdmi_cec_get_port_info` 函数中:*list = ctx->port;
   在函数实现中,`list` 是一个指向指针数组的指针,`ctx->port` 是指向 `struct hdmi_port_info` 数组的指针。
   通过 `*list = ctx->port;` 这行代码,我们将 `ctx->port` 数组的起始地址赋值给了 `list` 指针,这样 `list` 指针就指向了 `ctx->port` 数组的内容。
   由于 `legacyPorts` 是 `list` 的地址,所以在函数调用结束后,`legacyPorts` 指向了 `ctx->port` 数组的内容。

总结起来,通过使用 `&legacyPorts` 将 `legacyPorts` 的地址传递给 `hdmi_cec_get_port_info` 函数,在函数内部将 `ctx->port` 的地址赋值给了 `*list`,从而使得 `legacyPorts` 指向了 `ctx->port` 数组的内容。这样,通过 `legacyPorts` 指针,我们可以在函数外部访问和操作 `ctx->port` 数组的填充后的端口信息。

 总结

所以,通过修正版本的分析,就知道问题版本出问题的原因了。

在用问题版本中,我们使用list[0] = &ctx->port[0],对struct hdmi_port_info* list[]中的每个元素进行赋值。

	list[0] = &ctx->port[0];...list[3]->physical_address = 0x2000;

我们在调用时,定义了一个名为 `legacyPorts` 的指针,它的类型是 `struct hdmi_port_info*`,即指向 `struct hdmi_port_info` 结构体的指针。

参考链接:

诊断原生代码崩溃问题  |  Android 开源项目  |  Android Open Source Project

原创技术干货 | 解读Linux安全机制之栈溢出保护 - 送码网

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

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

相关文章

微信小程序 - 基于scroll view 实现下拉刷新

简介 本文会基于scroll view 实现下拉刷新效果&#xff0c;在下拉的时候会进入loading状态。 实现效果 效果如上图所示&#xff0c;在下拉到底部时候&#xff0c;会出现loading条&#xff0c;在处理完成后loading条消失。 具体代码 布局 <scroll-view scroll-y style&qu…

【AIGC调研系列】通义灵码与copilot的对比

通义灵码与GitHub Copilot的对比主要集中在几个方面&#xff1a;代码编写能力、免费性、操作界面和适配性。 首先&#xff0c;在代码编写能力上&#xff0c;虽然GitHub Copilot在整体上要强于通义灵码&#xff0c;但通义灵码的能力也不算弱&#xff0c;并且在某些特定的小类任…

Windows下anaconda下载安装教程,多图预警【步骤详细版】

Windows下anaconda下载安装教程 一、下载anaconda二、安装详细步骤<图示>1、安装Anaconda2、修改环境变量 三、验证是否安装成功1、查看python版本2、查看pip版本 特别致谢大佬的教程 一、下载anaconda 官网下载&#xff0c;速度太感人&#xff0c;所以这里选择清华开源…

01背包 与 emo题目背景(周超人的遗憾) 的爱恨情仇

本题背景有意思&#xff0c;大家当乐子看&#xff0c;目前没有找到题目原题&#xff0c;也没有写过完全是01背包模板的题目&#xff0c;该篇文章大家注意其01背包一维写法的模板就好&#xff0c;注意各个关键点 ✨欢迎来到脑子不好的小菜鸟的文章✨ &#x1f388;创作不易&…

从政府工作报告探计算机行业发展——探索计算机行业发展蓝图

目录 前言 一、政策导向与行业发展 &#xff08;一&#xff09;政策导向的影响 &#xff08;二&#xff09;企业如何把握政策机遇推动创新发展 二、技术创新与产业升级 三、数字经济与数字化转型 四、国际合作与竞争态势 五、行业人才培养与科技创新 &#xff08;一&a…

论文阅读——RemoteCLIP

RemoteCLIP: A Vision Language Foundation Model for Remote Sensing 摘要——通用基础模型在人工智能领域变得越来越重要。虽然自监督学习&#xff08;SSL&#xff09;和掩蔽图像建模&#xff08;MIM&#xff09;在构建此类遥感基础模型方面取得了有希望的结果&#xff0c;但…

相机安装位置固定后开始调试设备供电公司推荐使用方法

摄像头安装位置固定后开始调试 设备供电&#xff1a;无电源设备需要连接12V/2A电源并连接到摄像机的DC端口&#xff0c;而有电源的摄像机可以直接连接到220V电源。 连接设备&#xff1a;如果是有线连接&#xff0c;请使用网线将设备连接到电脑&#xff08;建议直接连接&#…

hcia复习总结7

1&#xff0c;AR2发送2.0网段的信息给AR1&#xff0c;如果&#xff0c;AR1本身并不存在该网段的路由 信息&#xff0c;则将直接 刷新 到本地的路由表中。 Destination/Mask Proto Pre Cost Flags NextHop Interface 2.2.2.0/24 RIP 100…

【LeetCode热题100】54. 螺旋矩阵

一.题目要求 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 二.题目难度 中等 三.输入样例 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5] 示例…

C语言葵花宝典之——文件操作

前言&#xff1a; 在之前的学习中&#xff0c;我们所写的C语言程序总是在运行结束之后&#xff0c;就会自动销毁&#xff0c;那如果我们想将一个结果进行长期存储应该如何操作呢&#xff1f;这时候就需要我们用文件来操作。 目录 1、什么是文件&#xff1f; 1.1 程序文件 1.2…

PyTorch学习笔记之激活函数篇(一)

文章目录 1、Sigmoid函数1.1 公式1.2 对应图像1.2 生成图像代码1.4 优点与不足1.5 torch.sigmoid()函数 1、Sigmoid函数 1.1 公式 Sigmoid函数的公式&#xff1a; f ( x ) 1 1 e − x f(x) \frac{1}{1e^{-x}} f(x)1e−x1​ Sigmoid函数的导函数&#xff1a; f ′ ( x ) e …

Vue 3 + TypeScript 项目中全局挂载并使用工具函数

一、proxy方式 1.封装日期选择工具函数&#xff1a; 在untils文件夹下新建index.ts,并导出工具函数 /*** 获取不同类型日期* param&#xff1a;类型 dateVal: 是否指定*/ export function getSystemDate(param: any, dateVal: any) {let systemDate dateVal ? new Date(da…

【算法篇】七大基于比较的排序算法精讲

目录 排序 1.直接插入排序 2.希尔排序 3.直接选择排序 4.堆排序 5.冒泡排序 6.快速排序 7.归并排序 排序 排序算法的稳定性&#xff1a;假设在待排序的序列中&#xff0c;有多个相同的关键字&#xff0c;经过排序后&#xff0c;这些关键字的先后顺序不发生改变&#…

编程入行指南:从代码小白到技术大牛的“码农”奇幻漂流

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在这个飞速发展的信息时代&#xff0c;技术不断推陈出新&#xff0c;程序员若想保持行业翘楚地位&#xff0c;必须持续汲取新知、…

经典机器学习模型(一)感知机模型

经典机器学习模型(一)感知机模型 感知机可以说是一个相当重要的机器学习基础模型&#xff0c;是神经网络和支持向量机的基础。 感知机是一个二分类的线性分类模型&#xff0c;之所以说是线性&#xff0c;是因为它的模型是线性形式的。 从《统计学习方法》中&#xff0c;我们…

Docker Compose基本配置及使用笔记

Docker Compose基本配置及使用笔记 简介 Docker Compose 是一个用于定义和运行多个 Docker 容器应用程序的工具。它使用 YAML 文件来配置应用程序的服务&#xff0c;并通过简单的命令集管理这些服务的生命周期。 1.步骤1 代码如下&#xff1a;docker-compose.yml放在虚拟机roo…

前端项目,个人笔记(一)【Vue-cli - 定制化主题 + 路由设计】

目录 1、项目准备 1.1、项目初始化 1.2、elementPlus按需引入 注&#xff1a;使用cnpm安装elementplus及两个插件&#xff0c;会报错&#xff1a;vueelement-plus报错TypeError: Cannot read properties of null (reading isCE ) &#xff0c;修改&#xff1a; 测试&#…

Swin—Transformer学习笔记

一、网络框架 二、Patch Merging 图像长和宽减半&#xff0c;通道数增加一倍 三、W-MSA 目的&#xff1a;减少计算量 缺点&#xff1a;窗口之间无法进行信息交互 四、SW-MSA 目的&#xff1a;实现不同window之间的信息交互 为了不增加计算量&#xff0c;移动window并增加Ma…

【数据结构】二叉树OJ题(C语言实现)

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

【C#】int+null=null

C#语法&#xff0c;这玩意不报错 intnullnull&#xff0c;有点不合逻辑 (Int32)(bizRepair0rder.CreateTime. Value - regues.Mlodifylime.Value).TotalMinutes (Int32)(bizRepair0rder.CreateTime. Value - reques.llodifylime.Value).TotalMinutes nullstring是引用类型&…