Android R adb remount 调用流程
目的:调查adb remount 与adb shell进去后执行remount的差异
调试方法:添加log编译adbd,替换system\apex\com.android.adbd\bin\adbd
一、调查adb remount实现
关键代码:system\core\adb\daemon\services.cpp
unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {ADB_LOG(Service) << "transport " << transport->serial_name() << " opening service " << name;#if defined(__ANDROID__) && !defined(__ANDROID_RECOVERY__)if (name.starts_with("abb:") || name.starts_with("abb_exec:")) {return execute_abb_command(name);}
#endif#if defined(__ANDROID__)if (name.starts_with("framebuffer:")) {return create_service_thread("fb", framebuffer_service);} else if (android::base::ConsumePrefix(&name, "remount:")) {std::string cmd = "/system/bin/remount ";cmd += name;return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);} else if (android::base::ConsumePrefix(&name, "reboot:")) {return reboot_device(std::string(name));} else if (name.starts_with("root:")) {return create_service_thread("root", restart_root_service);} else if (name.starts_with("unroot:")) {return create_service_thread("unroot", restart_unroot_service);} else if (android::base::ConsumePrefix(&name, "backup:")) {std::string cmd = "/system/bin/bu backup ";cmd += name;return StartSubprocess(cmd, nullptr, SubprocessType::kRaw, SubprocessProtocol::kNone);} else if (name.starts_with("restore:")) {return StartSubprocess("/system/bin/bu restore", nullptr, SubprocessType::kRaw,SubprocessProtocol::kNone);} else if (name.starts_with("disable-verity:")) {return StartSubprocess("/system/bin/disable-verity", nullptr, SubprocessType::kRaw,SubprocessProtocol::kNone);} else if (name.starts_with("enable-verity:")) {return StartSubprocess("/system/bin/enable-verity", nullptr, SubprocessType::kRaw,SubprocessProtocol::kNone);} else if (android::base::ConsumePrefix(&name, "tcpip:")) {std::string str(name);int port;if (sscanf(str.c_str(), "%d", &port) != 1) {return unique_fd{};}return create_service_thread("tcp",std::bind(restart_tcp_service, std::placeholders::_1, port));} else if (name.starts_with("usb:")) {return create_service_thread("usb", restart_usb_service);}
#endifif (android::base::ConsumePrefix(&name, "dev:")) {return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};} else if (android::base::ConsumePrefix(&name, "jdwp:")) {pid_t pid;if (!ParseUint(&pid, name)) {return unique_fd{};}return create_jdwp_connection_fd(pid);} else if (android::base::ConsumePrefix(&name, "shell")) {return ShellService(name, transport);} else if (android::base::ConsumePrefix(&name, "exec:")) {return StartSubprocess(std::string(name), nullptr, SubprocessType::kRaw,SubprocessProtocol::kNone);} else if (name.starts_with("sync:")) {return create_service_thread("sync", file_sync_service);} else if (android::base::ConsumePrefix(&name, "reverse:")) {return reverse_service(name, transport);} else if (name == "reconnect") {return create_service_thread("reconnect", std::bind(reconnect_service, std::placeholders::_1, transport));} else if (name == "spin") {return create_service_thread("spin", spin_service);}return unique_fd{};
}
根据之前调试adb方法可以得知adb remount会打印如下log
I adbd : transport UsbFfs opening service shell,v2,TERM=xterm-256color,raw:remount
参考文档:Android adb自身调试log开关-CSDN博客
进而会执行上面daemon_service_to_fd函数中的如下else if
else if (android::base::ConsumePrefix(&name, "shell")) {return ShellService(name, transport);
在ShellService中会解析参数和cmd,再调用StartSubprocess
// Shell service string can look like:
// shell[,arg1,arg2,...]:[command]
unique_fd ShellService(std::string_view args, const atransport* transport) {size_t delimiter_index = args.find(':');if (delimiter_index == std::string::npos) {LOG(ERROR) << "No ':' found in shell service arguments: " << args;return unique_fd{};}// TODO: android::base::Split(const std::string_view&, ...)std::string service_args(args.substr(0, delimiter_index));std::string command(args.substr(delimiter_index + 1));// Defaults:// PTY for interactive, raw for non-interactive.// No protocol.// $TERM set to "dumb".SubprocessType type(command.empty() ? SubprocessType::kPty : SubprocessType::kRaw);SubprocessProtocol protocol = SubprocessProtocol::kNone;std::string terminal_type = "dumb";for (const std::string& arg : android::base::Split(service_args, ",")) {if (arg == kShellServiceArgRaw) {type = SubprocessType::kRaw;} else if (arg == kShellServiceArgPty) {type = SubprocessType::kPty;} else if (arg == kShellServiceArgShellProtocol) {protocol = SubprocessProtocol::kShell;} else if (arg.starts_with("TERM=")) {terminal_type = arg.substr(strlen("TERM="));} else if (!arg.empty()) {// This is not an error to allow for future expansion.LOG(WARNING) << "Ignoring unknown shell service argument: " << arg;}}return StartSubprocess(command, terminal_type.c_str(), type, protocol);
}
继续跟踪也没发现adb remount有额外的参数或指令执行,看来只有一个remount,与在串口执行并无差异。
那为何adb remount后可以直接覆盖原文件,而串口执行remount必须先删除原文件才能cp成功呢?
adb remount
#cp system/apex/com.android.adbd/bin/adbd22 system/apex/com.android.adbd/bin/adbd
# sync串口remount
cp system/apex/com.android.adbd/bin/adbd22 system/apex/com.android.adbd/bin/adbd
cp: system/apex/com.android.adbd/bin/adbd: Text file busy
尝试使用adb shell remount,也可以直接覆盖,adb log和adb remount一样
尝试使用adb shell /system/bin/remount,无法覆盖,和串口remount现象一样
adb log如下
03-17 01:19:13.704 8511 8511 I adbd : transport UsbFfs opening service shell,v2,TERM=xterm-256color,raw:/system/bin/remount
03-17 01:19:13.704 8511 8511 I adbd : shell opening service ,v2,TERM=xterm-256color,raw:/system/bin/remount
03-17 01:19:13.704 8511 8511 I adbd : ShellService xterm-256color opening service /system/bin/remount
03-17 01:19:13.704 8511 8511 E adbd : starting raw subprocess (protocol=shell, TERM=xterm-256color): '/system/bin/remount'
说明adb remount并不是调用的/system/bin/remount,而是一个系统集成的函数实现的,相当于调用了一个remount系统函数 ,这也就明白为何adb remount没有走daemon_service_to_fd中的单独remount else if(调用的/system/bin/remount)
走哪个remount是system\core\adb\client\commandline.cpp中如下代码实现的
else if (!strcmp(argv[0], "remount")) {FeatureSet features;std::string error;if (!adb_get_feature_set(&features, &error)) {fprintf(stderr, "error: %s\n", error.c_str());return 1;}if (CanUseFeature(features, kFeatureRemountShell)) {std::vector<const char*> args = {"shell"};args.insert(args.cend(), argv, argv + argc);return adb_shell_noinput(args.size(), args.data());} else if (argc > 1) {auto command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);return adb_connect_command(command);} else {return adb_connect_command("remount:");}}
反转又来了。。。
排查了system/core下remount实现只有一处system\core\fs_mgr\fs_mgr_remount.cpp
查看Android.bp,此文件是编译remount指令的源码,但实现方式的确也和init中的raw命令类似叫do_remount
system\core\init\builtins.cpp中没有remount的实现
// Builtin-function-map start
const BuiltinFunctionMap& GetBuiltinFunctionMap() {constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();// clang-format offstatic const BuiltinFunctionMap builtin_functions = {{"bootchart", {1, 1, {false, do_bootchart}}},{"chmod", {2, 2, {true, do_chmod}}},{"chown", {2, 3, {true, do_chown}}},{"class_reset", {1, 1, {false, do_class_reset}}},{"class_reset_post_data", {1, 1, {false, do_class_reset_post_data}}},{"class_restart", {1, 1, {false, do_class_restart}}},{"class_start", {1, 1, {false, do_class_start}}},{"class_start_post_data", {1, 1, {false, do_class_start_post_data}}},{"class_stop", {1, 1, {false, do_class_stop}}},{"copy", {2, 2, {true, do_copy}}},{"domainname", {1, 1, {true, do_domainname}}},{"enable", {1, 1, {false, do_enable}}},{"exec", {1, kMax, {false, do_exec}}},{"exec_background", {1, kMax, {false, do_exec_background}}},{"exec_start", {1, 1, {false, do_exec_start}}},{"export", {2, 2, {false, do_export}}},{"hostname", {1, 1, {true, do_hostname}}},{"ifup", {1, 1, {true, do_ifup}}},{"init_user0", {0, 0, {false, do_init_user0}}},{"insmod", {1, kMax, {true, do_insmod}}},{"installkey", {1, 1, {false, do_installkey}}},{"interface_restart", {1, 1, {false, do_interface_restart}}},{"interface_start", {1, 1, {false, do_interface_start}}},{"interface_stop", {1, 1, {false, do_interface_stop}}},{"load_persist_props", {0, 0, {false, do_load_persist_props}}},{"load_system_props", {0, 0, {false, do_load_system_props}}},{"loglevel", {1, 1, {false, do_loglevel}}},{"mark_post_data", {0, 0, {false, do_mark_post_data}}},{"mkdir", {1, 6, {true, do_mkdir}}},// TODO: Do mount operations in vendor_init.// mount_all is currently too complex to run in vendor_init as it queues action triggers,// imports rc scripts, etc. It should be simplified and run in vendor_init context.// mount and umount are run in the same context as mount_all for symmetry.{"mount_all", {0, kMax, {false, do_mount_all}}},{"mount", {3, kMax, {false, do_mount}}},{"perform_apex_config", {0, 0, {false, do_perform_apex_config}}},{"umount", {1, 1, {false, do_umount}}},{"umount_all", {0, 1, {false, do_umount_all}}},{"update_linker_config", {0, 0, {false, do_update_linker_config}}},{"readahead", {1, 2, {true, do_readahead}}},{"remount_userdata", {0, 0, {false, do_remount_userdata}}},{"restart", {1, 1, {false, do_restart}}},{"restorecon", {1, kMax, {true, do_restorecon}}},
在fs_mgr_remount.cpp添加log,编译remount二进制,发现执行串口remount和adb remount都会打印这个log,说明两条指令又走到一起了。那为何表现会不同?
又有新的发现,若先串口执行remount,再adb remount,CP覆盖也会报错。。。晕了
反复尝试,发现adb remount后也会覆盖报错,奇怪了,难道是我替换后remount后导致的?
先排查到这里,至少基本理清了adb remount的调用流程,也算是有收获。
真相来了。。。
前面adb remount后可以覆盖,串口remount不能覆盖是因为,adb remount后有push 过system/apex/com.android.adbd/bin/adbd这个文件,然后再手动cp就可以覆盖,而无法覆盖都是因为没有先adb push那个文件。所以导致能不能覆盖不是remount导致的,而是adb push 具备特异功能
二、新版本adb push 无需再手动改权限、selinux标签的原因
在老版本Android系统,若push文件到system/bin等路径下,需要手动改权限,若开启了selinux还需要手动改selinux标签,否则会导致系统启动失败或相应服务启动异常。而在新版本Android系统则无需担心,这些步骤由adb自动完成了。
文件:system\core\adb\daemon\file_sync_service.cpp
先看调试log:
03-17 02:27:30.294 7466 8560 E adbd : sync id_name stat_v2 name:system/apex/com.android.adbd/bin/adbd
03-17 02:27:30.301 7466 8560 E adbd : sync id_name send_v2 name:system/apex/com.android.adbd/bin/adbd
adb push会先查询目标文件的属性信息并记录,然后才发送文件。在发送文件过程还会记录原文件夹、文件的属性,并会修改 push后的文件的属性
大概的实现代码如下:
static bool handle_sync_command(int fd, std::vector<char>& buffer) {D("sync: waiting for request");SyncRequest request;if (!ReadFdExactly(fd, &request, sizeof(request))) {SendSyncFail(fd, "command read failure");return false;}size_t path_length = request.path_length;if (path_length > 1024) {SendSyncFail(fd, "path too long");return false;}char name[1025];if (!ReadFdExactly(fd, name, path_length)) {SendSyncFail(fd, "filename read failure");return false;}name[path_length] = 0;std::string id_name = sync_id_to_name(request.id);LOG(ERROR) << "sync id_name:" << id_name.c_str() << " name:" << name;switch (request.id) {case ID_LSTAT_V1:if (!do_lstat_v1(fd, name)) return false;break;case ID_LSTAT_V2:case ID_STAT_V2:if (!do_stat_v2(fd, request.id, name)) return false;break;case ID_LIST_V1:if (!do_list_v1(fd, name)) return false;break;case ID_LIST_V2:if (!do_list_v2(fd, name)) return false;break;case ID_SEND_V1:if (!do_send_v1(fd, name, buffer)) return false;break;case ID_SEND_V2:if (!do_send_v2(fd, name, buffer)) return false;break;case ID_RECV_V1:if (!do_recv_v1(fd, name, buffer)) return false;break;case ID_RECV_V2:if (!do_recv_v2(fd, name, buffer)) return false;break;case ID_QUIT:return false;default:SendSyncFail(fd, StringPrintf("unknown command %08x", request.id));return false;}return true;
}
static bool do_stat_v2(int s, uint32_t id, const char* path) {syncmsg msg = {};msg.stat_v2.id = id;decltype(&stat) stat_fn;if (id == ID_STAT_V2) {stat_fn = stat;} else {stat_fn = lstat;}struct stat st = {};int rc = stat_fn(path, &st);if (rc == -1) {msg.stat_v2.error = errno_to_wire(errno);} else {msg.stat_v2.dev = st.st_dev;msg.stat_v2.ino = st.st_ino;msg.stat_v2.mode = st.st_mode;msg.stat_v2.nlink = st.st_nlink;msg.stat_v2.uid = st.st_uid;msg.stat_v2.gid = st.st_gid;msg.stat_v2.size = st.st_size;msg.stat_v2.atime = st.st_atime;msg.stat_v2.mtime = st.st_mtime;msg.stat_v2.ctime = st.st_ctime;}return WriteFdExactly(s, &msg.stat_v2, sizeof(msg.stat_v2));
}
static bool handle_send_file(borrowed_fd s, const char* path, uint32_t* timestamp, uid_t uid,gid_t gid, uint64_t capabilities, mode_t mode, bool compressed,std::vector<char>& buffer, bool do_unlink) {int rc;syncmsg msg;__android_log_security_bswrite(SEC_TAG_ADB_SEND_FILE, path);unique_fd fd(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));if (fd < 0 && errno == ENOENT) {if (!secure_mkdirs(Dirname(path))) {SendSyncFailErrno(s, "secure_mkdirs failed");goto fail;}fd.reset(adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode));}if (fd < 0 && errno == EEXIST) {fd.reset(adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode));}if (fd < 0) {SendSyncFailErrno(s, "couldn't create file");goto fail;} else {if (fchown(fd.get(), uid, gid) == -1) {SendSyncFailErrno(s, "fchown failed");goto fail;}#if defined(__ANDROID__)// Not all filesystems support setting SELinux labels. http://b/23530370.selinux_android_restorecon(path, 0);
#endif// fchown clears the setuid bit - restore it if present.// Ignore the result of calling fchmod. It's not supported// by all filesystems, so we don't check for success. b/12441485fchmod(fd.get(), mode);}{rc = posix_fadvise(fd.get(), 0, 0,POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE | POSIX_FADV_WILLNEED);if (rc != 0) {D("[ Failed to fadvise: %s ]", strerror(rc));}bool result;if (compressed) {result = handle_send_file_compressed(s, std::move(fd), timestamp);} else {result = handle_send_file_uncompressed(s, std::move(fd), timestamp, buffer);}if (!result) {goto fail;}if (!update_capabilities(path, capabilities)) {SendSyncFailErrno(s, "update_capabilities failed");goto fail;}msg.status.id = ID_OKAY;msg.status.msglen = 0;return WriteFdExactly(s, &msg.status, sizeof(msg.status));}fail:....
}
调用fchmod改push后文件的属性
相关文章:
Android R adb remount 调用流程
目的:调查adb remount 与adb shell进去后执行remount的差异 调试方法:添加log编译adbd,替换system\apex\com.android.adbd\bin\adbd 一、调查adb remount实现 关键代码:system\core\adb\daemon\services.cpp unique_fd daemon_service_to…...
uvm sequence
UVM Sequence 是验证环境中生成和控制事务(Transaction)流的核心机制,它通过动态生成、随机化和调度事务,实现灵活多样的测试场景。以下是Sequence的详细解析: Sequence 的核心作用 事务流生成:通过 uvm_s…...
Java 代理(一) 静态代理
学习代理的设计模式的时候,经常碰到的一个经典场景就是想统计某个方法的执行时间。 1 静态代理模式的产生 需求1. 统计方法执行时间 统计方法执行时间,在很多API/性能监控中都有这个需求。 下面以简单的计算器为例子,计算加法耗时。代码如下…...
《初级社会工作者》考试题,附答案解析
一、单项选择题(共 60 题,每题 1 分) 1. 社会工作者在社区中开展针对留守儿童的支持小组活动,发现一名儿童因父母长期外出务工而产生严重的分离焦虑。此时,社会工作者应首先采取的介入策略是( )…...
网盘解析工具1.3.0,修改了一些bug,建议更新到此版本
最近问题反馈比较多,本来想着周末再更新了来着,但是账号黑的实在太快了。排查了下应该是某度网盘的一个接口缺少了一些参数,导致一直进黑名单。所幸参数不难找,新版本已经修复了,建议大家赶紧更新到1.3.0版本ÿ…...
Multi-Stage Progressive Image Restoration论文阅读
摘要 图像复原任务在恢复图像时需要在空间细节与高层语境化信息之间取得复杂的平衡。本文提出了一种新颖的协同设计方法,能够最优地平衡这些竞争目标。我们的核心方案是一种多阶段架构,通过逐步学习退化输入的复原函数,将整体恢复过程分解为…...
了解图像质量评价指标PSNR
一、PSNR是什么 1.1 定义与数学公式 峰值信噪比(Peak Signal-to-Noise Ratio,PSNR)是数字图像处理领域最经典的客观质量评价指标之一。其核心思想是通过计算原始图像与失真图像之间的均方误差(MSE)来衡量失真程度&am…...
C++概述
1 什么是面向对象】 概念上来说:就是以对象(具体的变量)为导向的编程思路 专注于:一个对象具体能实现哪些过程(哪些功能) 面向对象 n * 面向过程 结论:面向对象需要做的事情 1:我们要想清楚,我们现在需要编写一个…...
axios文件下载使用后端传递的名称
java后端通过HttpServletResponse 返回文件流 在Content-Disposition中插入文件名 一定要设置Access-Control-Expose-Headers,代表跨域该Content-Disposition返回Header可读,如果没有,前端是取不到Content-Disposition的,可以在统…...
如何让 history 记录命令执行时间?Linux/macOS 终端时间戳设置指南
引言:你真的会用 history 吗? 有没有遇到过这样的情况:你想回顾某个重要命令的执行记录,却发现 history 只列出了命令序号和内容,根本没有时间戳?这在运维排查、故障分析、甚至审计时都会带来极大的不便。 想象一下,你在服务器上误删了某个文件,但不知道具体是几点执…...
使用LLaMAFactory微调Qwen大模型
一、环境配置与工具安装 1. 硬件要求 GPU:至少1块NVIDIA GPU(推荐RTX 4090/A100/H100,显存≥16GB)。内存:≥64GB系统内存。存储:≥100GB硬盘空间用于模型与数据集存储。2. 软件依赖 Python 3.8+:需安装CUDA支持的PyTorch版本(如torch==2.0.1+cu117)。 依赖库:通过以…...
CSS3:现代Web设计的魔法卷轴
一、布局革命:从平面到多维空间 1.1 Grid布局的次元突破 星际战舰布局系统 .galaxy {display: grid;grid-template-areas: "nav nav nav""sidebar content ads""footer footer footer";grid-template-rows: 80px 1fr 120p…...
Netty - 从Nginx 四层(TCP/UDP)流量中获取客户端真实/网络出口IP
文章目录 一、背景与原理1.1 问题场景网络架构影响分析1.1 客户端与Nginx之间存在的NAT/VPN1.2 Nginx与RPC服务之间的NAT 1.2 技术原理 二、环境配置验证2.1 Nginx配置2.2 版本要求 三、Netty服务端实现3.1 Pipeline配置(核心代码)3.2 协议处理器实现3.3…...
基于Spring AI开发本地Jenkins MCP Server服务
前言 首先介绍下MCP是什么? MCP是由开发了 Claude 模型的 Anthropic 公司2024年12月提出并开源的一项开放标准,全称:Model Context Protocol,它是一个开放协议,它使 LLM 应用与外部数据源和工具之间的无缝集成成为可能…...
记录一次TDSQL事务太大拆过binlog阈值报错
记录一次TDSQL事务太大拆过binlog阈值报错处理过程 1、排查任何类型数据库故障的第一步, 同步实例信息、报错内容、报错时间段、当前是否恢复、如何感知到数据库问题的、对应用有什么影响、系统允许的时间窗口。 2、明确报错内容为单次写入binlog量超过阈值 3、登陆…...
1688商品详情接口:深度解析与应用实践
在电商领域,1688作为中国领先的B2B平台,拥有海量的商品信息。对于开发者、商家和数据分析师来说,获取1688商品的详细信息是实现数据分析、竞品研究、自动化管理和精准营销的重要手段。本文将详细介绍1688商品详情接口的使用方法、技术细节以及…...
机试题——村落基站建设
题目描述 假设村落以二叉树的形状分布,我们需要选择在哪些村落建设基站。如果某个村落建设了基站,那么它和它相邻的村落(包括本节点、父节点和子节点)也会有信号覆盖。目标是计算出最少需要建设的基站数。 输入描述 输入为一个…...
2025年高压电工考试真题分享
以下是一些高压电工考试题: 单选题 1、高压架空线路的档距一般为( )。 A. 20 - 30m B. 30 - 50m C. 50 - 80m D. 80 - 100m 答案:B。解析:高压架空线路档距一般在 30 - 50m,这样的档距能较好地保证线…...
T-SQL 语言基础:逆透视转换
概念 -- 把数据从列的转台转为行的状态-- 涉及查询数据的透视状态,将来自单个记录中多个列的值扩展为单个列中具有相同值的多个记录-- 也就是把透视表中的每个源行潜在地转换为多个行示例表继续使用上一篇博客,TempDB dbo.Orders 表。 T-SQL 语言基础&a…...
循环神经网络 - 给网络增加记忆能力
为了处理时序数据并利用其历史信息, 我们需要让网络具有短期记忆能力。而前馈网络是一种静态网络,不具备这种记忆能力。在正式学习循环神经网络之前,我们先来了解一下给网络增加短期记忆能力的三种方法。 一、延时神经网络 延时神经网络&am…...
Docker Desktop 界面功能介绍
Docker Desktop 界面功能介绍 左侧导航栏 Containers(容器): 用于管理容器,包括查看运行中或已停止的容器,检查容器状态、日志,执行容器内命令,启动、停止、删除容器等操作。Images(镜像): 管理本地 Docker 镜像,可查看镜像列表、从 Docker Hub 拉取新镜像、删除镜…...
R001-区块链
1.区块链概念 英文名:blockchain 或block chain what: 是一种块链式存储、不可篡改、安全可信的去中心化分布式账本. 特点:它结合了分布式存储、点对点传输、共识机制、密码学等技术,通过不断增长的数据块链(Blocks)记…...
无人机进行航空数据收集对于分析道路状况非常有用-使用无人机勘测高速公路而不阻碍交通-
无人机进行航空数据收集对于分析道路状况非常有用-使用无人机勘测高速公路而不阻碍交通- 瑞士拥有1,400 多公里长的高速公路网络。这些公路将人和货物从山谷高原运送到阿尔卑斯山的最高山口。维护这些高速公路使国家得以顺利运转。高速公路维护的重要性显而易见,但在…...
StarRocks 证书SRCA和SRCP
目录 引子 SRCA认证 SRCP认证 认证流程 引子 StarRocks介绍:极速全场景 MPP数据库starrocks介绍-CSDN博客 StarRocks中文社区推出了StarRocks 培训与认证,学习并通过考试后,可以得到StarRocks证书。对starrocks感兴趣或需要使用starrocks的…...
String类的模拟实现
我们在使用STL库的时候,不仅需要掌握如何使用,我们还需要了解一些底层的模拟实现。 1:需要模拟实现的string类函数 #pragma once #include<iostream> #include<assert.h> #include<utility> using namespace std;namespa…...
VMware Windows Tools 存在认证绕过漏洞(CVE-2025-22230)
漏洞概述 博通公司(Broadcom)近日修复了 VMware Windows Tools 中存在的一个高危认证绕过漏洞,该漏洞编号为 CVE-2025-22230(CVSS 评分为 9.8)。VMware Windows Tools 是一套实用程序套件,可提升运行在 VM…...
【计算机网络ICMP协议详解】
文章目录 一、前言二、ICMP协议概述2.1 ICMP 与 IP 协议的关系2.2 ICMP 的作用 三、ICMP报文格式3.1 字段解释: 四、常见ICMP类型与代码五、ICMP协议工作原理与示例5.1 ping 命令5.2 traceroute 命令 六、ICMP与网络安全6.1 ICMP的安全隐患6.2 防御措施 七、ICMP协议…...
WPF 自定义路由事件
WPF 路由事件的基础 什么是路由事件? 路由事件是一种特殊的事件机制,允许事件在可视化树中传播。它支持三种路由策略: 冒泡(Bubbling):事件从源元素向上传播到根元素。隧道(Tunneling…...
从零开始跑通3DGS教程:(一)数据(采集)
写在前面 本文内容 本文所属《从零开始跑通3DGS教程》系列文章; 本文介绍数据准备或者采集准备方式 平台/环境 linux, nvidia GPU, docker 转载请注明出处: https://blog.csdn.net/qq_41102371/article/details/146533367 目录 写在前面系列文章公开数据自己的数…...
DATEDIFF 函数
DATEDIFF 函数概述 DATEDIFF 函数用于计算两个日期之间的差值。 不同的数据库系统对 DATEDIFF 函数的实现和语法可能略有不同,但基本原理是相同的。 通用语法 DATEDIFF(datepart, startdate, enddate)datepart: 指定要计算的日期部分。 例如,day、wee…...
Java 大视界 -- 基于 Java 的大数据隐私计算在医疗影像数据共享中的实践探索(158)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
在Windows下VSCodeSSH远程登录到Ubuntu
Window用VSCode通过SSH远程登录Ubuntu SSH 服务开启Windows远程登录 SSH 服务开启 首先要确保 Ubuntu 的 SSH 服务开启了,开启 Ubuntu 的 SSH 服务以后我们就可以在 Windwos 下使用终端软件登陆到 Ubuntu 开启 SSH sudo apt-get install openssh-serverWindows远…...
MATLAB 控制系统设计与仿真 - 31
二次型最优控制 考虑到系统如果以状态空间方程的形式给出,其性能指标为: 其中F,Q,R是有设计者事先选定。线性二次最优控制问题简称LQ(Linear Quadractic)问题,就是寻找一个控制,使得系统沿着由指定初态出发的相应轨迹,其性能指标J取得最小值。 LQ问题分…...
基于SpringBoot + Vue 的考勤管理系统
系统环境 开发工具:IntelliJ IDEAJava 版本:JDK 1.8数据库:MySQL项目构建工具:Maven 项目主要技术 后端技术 Spring Boot:简化 Spring 应用开发流程,实现快速搭建和部署。MyBatis:用于实现数…...
JavaScript 中Object.assign()和展开运算符在对象合并时的区别,各自的适用场景是什么?
JavaScript 中Object.assign()和展开运算符在对象合并时的区别,各自的适用场景是什么? 在 JavaScript 里,咱们常常要把多个对象合并成一个新对象。Object.assign()和展开运算符(...)就像两个得力小助手,能…...
鸿蒙北向应用开发:deveco 5.0 kit化文件相关2
鸿蒙北向应用开发:deveco 5.0 kit化文件相关 在kit化时,有时候会出现这样一种场景即你想把已有的d.ts导出换个名字,这样从名字上更贴合你的kit聚合 什么意思呢?比如现在有 ohos.hilog.d.ts 导出了hilog,现在你想kit化hilog,使得hilog导出名字为usrhilog,这样用户在使用你的k…...
北斗导航 | 改进伪距残差矢量的接收机自主完好性监测算法原理,公式,应用,RAIM算法研究综述,matlab代码
改进伪距残差矢量的接收机自主完好性监测算法研究 摘要 接收机自主完好性监测(RAIM)是保障全球卫星导航系统(GNSS)可靠性的核心技术。本文针对传统伪距残差矢量法在微小故障检测和多故障隔离中的不足,提出一种融合加权奇偶空间与动态阈值调整的改进算法。通过理论推导验证…...
Postman 如何发送 Post 请求上传文件? 全面指南
写一个后端接口,肯定离不开后续的调试,所以我使用了 Postman 来进行上传图片接口的调试,调试步骤也很简单: 第一步:填写请求 URL第二步:选择请求类型第三步:选择发送文件第四步:点击…...
Python 装饰模式
在软件开发中,随着系统的复杂性增加,需求的变化往往会导致代码的频繁修改。为了提高代码的灵活性和可维护性,设计模式应运而生。其中,装饰模式(Decorator Pattern)是一种非常实用的结构型设计模式ÿ…...
JVM 面经
1、什么是 JVM? JVM 就是 Java 虚拟机,它是 Java 实现跨平台的基石。程序运行之前,需要先通过编译器将 Java 源代码文件编译成 Java 字节码文件;程序运行时,JVM 会对字节码文件进行逐行解释,翻译成机器码指令&#x…...
java对pdf文件分页拆分
文章目录 pdf文件拆分指定分页大小 pdf文件拆分 导入依赖 <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.32</version></dependency>2. 大文件拆分public static boolean …...
【PGCCC】PostgreSQL Certified Master 个人专访 | 第二期 何雄
由PGCCC发起的“PostgreSQL Certified Master个人专访”栏目,旨在挖掘PCM们对数据库行业的深度洞察,分享他们对行业发展的思考和个人感悟,对广大PGer们具有实际借鉴意义。 1.请简单介绍一下自己,您的爱好、您的事业。 大家好,我…...
什么是具身智能
具身智能(Embodied Intelligence)是人工智能与机器人学交叉的前沿领域,强调智能体通过身体与环境的动态交互实现自主学习和进化,其核心在于将感知、行动与认知深度融合。通俗地讲,就是机器人或者智能系统在物理环境中…...
Android开发EmojiCompat 初始化
Android开发EmojiCompat 初始化 报错信息: ensure spannable:java.lang.IllegalStateException: EmojiCompat is not initialized 在Application上写上下面代码即可: EmojiCompat.Config config new BundledEmojiCompatConfig(this);EmojiCompat.in…...
k近邻算法K-Nearest Neighbors(KNN)
算法核心 KNN算法的核心思想是“近朱者赤,近墨者黑”。对于一个待分类或预测的样本点,它会查找训练集中与其距离最近的K个样本点(即“最近邻”)。然后根据这K个最近邻的标签信息来对当前样本进行分类或回归。 在分类任务中&#…...
TextGrad:案例
原文:Yuksekgonul, M., Bianchi, F., Boen, J. et al. Optimizing generative AI by backpropagating language model feedback. Nature 639, 609–616 (2025). https://doi.org/10.1038/s41586-025-08661-4 目录 Solution optimizationPrompt optimization for rea…...
位运算算法:解锁高效编程的钥匙
常见位运算场景: 5.消失的两个数字 1.判定字符是否唯一 解法一:使用HashSet 借助 HashSet 存储字符。HashSet 不允许有重复元素,在遍历字符串时尝试添加字符,若添加失败就表明有重复字符,返回 false;若遍…...
Burp Suite抓包实战:SQL注入漏洞挖掘
本文系统解析如何利用Burp Suite专业版开展SQL注入漏洞的定向挖掘,涵盖手动探测、自动化利用、WAF绕过等进阶技巧。通过电商、金融等行业的真实渗透案例,详解从流量拦截到漏洞利用的全链路方法论,实现单日最高挖掘23个高危注入点的实战成果。…...
使用HTML5和CSS3实现3D旋转相册效果
使用HTML5和CSS3实现3D旋转相册效果 这里写目录标题 使用HTML5和CSS3实现3D旋转相册效果项目介绍技术栈核心功能实现思路1. HTML结构2. CSS样式解析2.1 基础样式设置2.2 3D效果核心样式2.3 卡片样式 3. JavaScript交互实现3.1 旋转控制3.2 自动播放功能 技术要点总结项目亮点总…...
MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案
✅ MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案 前言一、问题现象二、原因分析1. 使用了 strictInsertFill/strictUpdateFill 导致更新失效2. 实体类注解配置错误3. MetaObjectHandler 未生效4. 使用自定义 SQL 导致自动填充失效5. 字段类型不匹配 三、…...