Android HAL HIDL

1 Android HAL HIDL
1.1?Android中查看有哪些HIDL HAL
HIDL是Treble Interface的一部分。
adb root
adb shell
# lshal

1.2 Android打印C++調用棧
#include <utils/CallStack.h>?
在需要打印的地方加如下的定義。
android::CallStack stack("oem");

logcat | grep oem

1.3?GNSS和Sensors
Refer to gnss and sensors
hardware/interfaces/gnss/1.0/default
hardware/interfaces/sensors/1.0/default

1.4?產生HAL框架步驟
1)生成androidmk和hidl-gen
在Android項目根目錄下:

. build/envsetup.sh
lunch
make blueprint_tools
make hidl-gen
make c2hal // 將傳統HAL .h頭文件轉換成hidl .hal文件工具

2)產生.cpp和.h文件
mkdir -p hardware/interfaces/oem1/1.0/default
路徑中出現的1.0表示HAL當前版本

仿照GNSS或者Sensors增加一個IOem1.hal
in hardware/interfaces/oem1/1.0/IOem1.hal

在Android項目源碼根目錄下編寫腳本my_oem1.sh,調用hidl-gen產生.cpp和.h文件
in my_oem1.sh
PACKAGE=android.hardware.oem1@1.0
LOC=hardware/interfaces/oem1/1.0/default
hidl-gen -o $LOC -Lc++-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE
hidl-gen -o $LOC -Landroidbp-impl -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport $PACKAGE

執行:
./my_oem1.sh

3)產生.bp和.mk文件
執行:
./hardware/interfaces/update-makefiles.sh

4)
編譯最終在out/target/common/gen/JAVA_LIBRARIES目錄下生成Java源文件。?

1.5?mk文件轉換為bp文件
. build/envsetup.sh
make blueprint_tools
androidmk Android.mk > Android.bp

1.6 Java HIDL
[28th-Mar-2022]
./hardware/interfaces/update-makefiles.sh
Android.mk
LOCAL_STATIC_JAVA_LIBRARIES += \
android.hardware.foo-V1.0-java
Android.bp
static_libs: [
"android.hardware.foo-V1.0-java",
],

// out/target/common/gen/JAVA_LIBRARIES
import android.hardware.foo.V1_0.IFoo;
IFoo server = IFoo.getService();

2 VTS測試步驟
1) 安裝必須的python工具和adb - Linux需要
apt-get install android-tools-adb

2)?
source build/envsetup.sh
lunch
make vts

3) 編譯完成后
in out/host/linux-x86/vts/
$cd android-vts/tools
$vts-tradefed
> run vts
or
> run vts-hal
or
> run vts-kernel

如果要在Windows上測試,需要將文件夾android-vts拷貝到windows下 ?- 待完善

4) 測試完成后
查看測試結果
android-vts/results
android-vts/logs

3 LinkToDeath
3.1 Principle
Client很容易監控Service的died;但是Service監控Client的died,需要Client實現使用IBinder接口的ICallback,傳給Service,然后Service可以監控這個使用IBinder接口的ICallback的died,這樣就實現了監控Client的died。

1)一個BpBinder可以注冊多個死亡回調;但Kernel只允許注冊一個死亡通知(ref->death只能為空或者指向一個指針)
2)BC_REQUEST_DEATH_NOTIFICATION - linkToDeath()
3)BC_CLEAR_DEATH_NOTIFICATION - unlinkToDeath()
4)當process exit時會觸發系統關閉該進程已經打開的文件節點/dev/hwbinder,從而調用binder_node_release();通知died - BINDER_WORK_DEAD_BINDER
5)
echo 0x18 > /sys/module/binder/parameters/debug_mask
dmesg -C
dmesg -w | grep binder &
kill -9 $PID
6)ftrace as shown below
echo 0 > /d/tracing/tracing_on
echo nop > /d/tracing/current_tracer

echo function_graph > /d/tracing/current_tracer
#echo function > /d/tracing/current_tracer
echo funcgraph-proc > /d/tracing/trace_options

echo binder_cleanup_ref_olocked > /d/tracing/set_graph_function
echo 1 > /d/tracing/tracing_on

cat /d/tracing/trace

debuggerd -b $PID

3.2 JAVA實施步驟
import android.os.IHwBinder.DeathRecipient;

private class xxxDeathRecipient implements DeathRecipient {
? ? @Override
? ? public void serviceDied(long cookie) {
? ? ? ? Log.i(TAG, "serviceDied, re-connect XXX");
? ? ? ? if (xxxService != null) {
? ? ? ? ? ? xxxService.unlinkToDeath(this);
? ? ? ? }

? ? ? ? // TODO: 重連service
? ? }
};
xxxDeathRecipient mxxxDeathRecipient = new xxxDeathRecipient();

獲取xxxService成功后:
try {
? ? xxxService.linkToDeath(mxxxDeathRecipient, 0);
} catch (RemoteException e) {
? ? e.printStackTrace();
}

3.3 CPP實施步驟
using android::hardware::hidl_death_recipient;

class MyDeathRecipient : public android::hardware::hidl_death_recipient {
? ? virtual void serviceDied(uint64_t cookie,
? ? ? ? const android::wp<::android::hidl::base::V1_0::IBase>& who) {
? ? ? ? // Deal with the fact that the service died
? ? }
}
MyDeathRecipient mDeathRecipient = new MyDeathRecipient();

獲取xxxService成功后:
xxxService->linkToDeath(mDeathRecipient, 0);

4 strace解析binder驅動數據插件
4.1 知識
A進程給B進程發送數據:A進程使用BC_TRANSACTION發送,經過binder驅動轉換,B進程接收到是BR_TRANSACTION
B進程給A進程回復數據:B進程使用BC_REPLY發送,經過binder驅動轉換,A進程接收到是BR_REPLY。

4.2 代碼
#include "defs.h"
#include <linux/android/binder.h>

static inline unsigned int get_my_le32(
? ??const unsigned char *p)
{
? ? return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
}

static const char *cmd_to_str(unsigned int cmd)
{
? ? switch(cmd) {
? ? ? ? case BC_TRANSACTION:
? ? ? ? ? ? return "BC_TRANSACTION";
? ? ? ? ? ? break;
? ? ? ? case BC_REPLY:
? ? ? ? ? ? return "BC_REPLY";
? ? ? ? ? ? break;
? ? ? ? case BR_TRANSACTION:
? ? ? ? ? ? return "BR_TRANSACTION";
? ? ? ? ? ? break;
? ? ? ? case BR_REPLY:
? ? ? ? ? ? return "BR_REPLY";
? ? ? ? ? ? break;
? ? }
? ? return "UNDEFINED";
}

/*
?* bc: binder command, from userland to driver
?* br: binder return, from driver to userland
?*/
static void handle_bx_transaction(
? ? ? ??struct tcb *const tcp,
? ? ? ? struct binder_write_read *bwr,
? ? ? ? struct binder_transaction_data *txn)
{
? ? binder_size_t ? txn_data_size = 0;
? ? binder_size_t ? txn_offsets_size = 0;
#if defined (FEATURE_PRINT_DETAIL)
? ? int n = 0;
? ? unsigned char buf[256], buf_offsets[256];
#else
? ? binder_uintptr_t ? ?txn_buffer;
? ? binder_uintptr_t ? ?txn_offsets;
#endif

? ??txn_data_size = txn->data_size;
? ? txn_offsets_size = txn->offsets_size;
? ? tprintf("handle=%d, ptr=%llx, "
? ? ? ? ? ? "target_cookie=0x%llx,\n"
? ? ? ? ? ? "code=%d, flags=0x%02x, "
? ? ? ? ? ? "sender_pid=%d, sender_euid=%d",
? ? ? ? ? ? txn->target.handle,
? ? ? ? ? ??txn->target.ptr,
? ? ? ? ? ??txn->cookie,
? ? ? ? ? ? txn->code,
? ? ? ? ? ? txn->flags,
? ? ? ? ? ? txn->sender_pid,
? ? ? ? ? ? txn->sender_euid);
? ? if (txn_data_size <= 8) {
? ? ? ? tprintf(", data_size=%llu, "
? ? ? ? ? ? ? ?"%02x %02x %02x %02x "
? ? ? ? ? ? ? ??"%02x %02x %02x %02x\n",
? ? ? ? ? ? ? ? txn_data_size,
? ? ? ? ? ? ? ? txn->data.buf[0], txn->data.buf[1],
? ? ? ? ? ? ? ? txn->data.buf[2], txn->data.buf[3],
? ? ? ? ? ? ? ? txn->data.buf[4], txn->data.buf[5],
? ? ? ? ? ? ? ? txn->data.buf[6], txn->data.buf[7]);
? ? } else {
#if defined (FEATURE_PRINT_DETAIL)
? ? ? ? txn_data_size = (txn_data_size > 256) ?
? ? ? ? ? ? ? ??256 : txn_data_size;
? ? ? ? if (umoven(tcp,
? ? ? ? ? ? ? ??txn->data.ptr.buffer,
? ? ? ? ? ? ? ??txn_data_size, buf) < 0)
? ? ? ? ? ? return;
? ? ? ? txn_offsets_size = (txn_offsets_size > 256) ?
? ? ? ? ? ? ? ??256 : txn_offsets_size;
? ? ? ? if (umoven(tcp,
? ? ? ? ? ? ? ??txn->data.ptr.offsets,
? ? ? ? ? ? ? ??txn_offsets_size,
? ? ? ? ? ? ? ??buf_offsets) < 0)
? ? ? ? ? ? return;

? ? ? ??for (; n < (txn_offsets_size /
? ? ? ? ? ? ? ??sizeof(binder_size_t)); n++)
? ? ? ? {
? ? ? ? ? ? struct flat_binder_object* pbinder =
? ? ? ? ? ? (struct flat_binder_object*)((char*)buf +
? ? ? ? ? ? ? ? ? ? ((int*)(buf_offsets))[n]);

? ? ? ? ? ? unsigned long type = pbinder->type;
? ? ? ? ? ? switch (type)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? case BINDER_TYPE_BINDER:
? ? ? ? ? ? ? ? case BINDER_TYPE_WEAK_BINDER:
? ? ? ? ? ? ? ? ? ? tprintf("binder=0x%llx, "
? ? ? ? ? ? ? ? ? ? ? ? ? ? "cookie=0x%llx\n",
? ? ? ? ? ? ? ? ? ? ? ? ? ? pbinder->binder,
? ? ? ? ? ? ? ? ? ? ? ? ? ? pbinder->cookie);
? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ??case BINDER_TYPE_HANDLE:
? ? ? ? ? ? ? ? case BINDER_TYPE_WEAK_HANDLE:
? ? ? ? ? ? ? ? ? ? tprintf("handle=0x%08x\n",
? ? ? ? ? ? ? ? ? ? ? ? ? ? pbinder->handle);
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? default:
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
#else
? ? ? ? txn_buffer = txn->data.ptr.buffer;
? ? ? ? txn_offsets = txn->data.ptr.offsets;
? ? ? ? tprintf(", \ndata_size=%llu, "
? ? ? ? ? ? ? ?"txn_buffer=0x%llx\n",
? ? ? ? ? ? ? ? txn_data_size, txn_buffer);
? ? ? ? dumpstr(tcp,
? ? ? ? ? ? ? ??(long) txn_buffer,
? ? ? ? ? ? ? ??txn_data_size);

? ? ? ??tprintf("\noffsets_size=%llu, "
? ? ? ? ? ? ? ??"txn_offsets=0x%llx\n",
? ? ? ? ? ? ? ? txn_offsets_size, txn_offsets);
? ? ? ? dumpstr(tcp,
? ? ? ? ? ? ? ?(long) txn_offsets,
? ? ? ? ? ? ? ?txn_offsets_size);
#endif
? ? }
}

/*
?* mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
?* GET_SERVICE_TRANSACTION <-> struct binder_transaction_data.code
?* data ? ? ? ? ? ? ? ? ? ?<-> struct binder_transaction_data.data
?*
?* write_bufer: CMD + binder_transaction_data + CMD + binder_transaction_data...
?* byte 0-3: command, offset0 - nr, offset1 - magic 'c' = 0x63
?* byte 4-7: target
?*
?* read_bufer: BR_NOOP + CMD + binder_transaction_data + CMD + binder_transaction_data...
?* byte 0-3: ?BR_NOOP, 0c 72 00 00, offset0 - nr, offset1 - magic 'r' = 0x72
?*
?*/
static void decode_bwr(struct tcb *const tcp,
? ? ? ??const kernel_ulong_t addr)
{
? ? struct binder_write_read bwr;
? ? struct binder_transaction_data *txn;
? ? int read_len, write_len, offset;
? ? unsigned char buf[256], *p;
? ? unsigned int cmd, cmd_data_len;
? ? static int ioctl_count = 1;

? ? if (umove_or_printaddr(tcp, addr, &bwr))
? ? ? ? return;
? ? if (abbrev(tcp)) {
? ? ? ? tprints(", ");
? ? ? ? tprintf("{BC_TRANS=0x%08x, "
? ? ? ? ? ? ? ??"BR_REPLY=0x%08x, "
? ? ? ? ? ? ? ? "write_size=%llu, "
? ? ? ? ? ? ? ??"write_consumed=%llu, "
? ? ? ? ? ? ? ? "read_size=%llu, "
? ? ? ? ? ? ? ? "read_consumed=%llu}",
? ? ? ? ? ? ? ? BC_TRANSACTION, BR_REPLY,
? ? ? ? ? ? ? ? bwr.write_size, bwr.write_consumed,
? ? ? ? ? ? ? ? bwr.read_size, bwr.read_consumed);
? ? ? ? return;
? ? }

? ??/* VERBOSE mode */
? ? tprints(",\n");
? ? tprintf("%d) ###?WRITE ###\n",
? ? ? ? ? ? ioctl_count++);
? ? tprintf("write_size=%llu, "
? ? ? ? ? ??"write_consumed=%llu, "
? ? ? ? ? ? ?"write_buffer=\n",
? ? ? ? ? ? bwr.write_size,
? ? ? ? ? ??bwr.write_consumed);

? ??write_len = (bwr.write_size > 256) ?
? ? ? ? ? ? 256 : bwr.write_size;
? ? if (umoven(tcp,
? ? ? ??bwr.write_buffer,
? ? ? ??write_len, buf) < 0)
? ? ? ? goto out;

? ??offset = 0;
? ? while (offset < write_len) {
? ? ? ? cmd = get_my_le32(buf + offset);
? ? ? ? cmd_data_len = _IOC_SIZE(cmd);

? ? ? ? switch (cmd) {
? ? ? ? ? ? case BC_TRANSACTION:
? ? ? ? ? ? case BC_REPLY:
? ? ? ? ? ? ? ? tprintf("%s--->\n", cmd_to_str(cmd));
? ? ? ? ? ? ? ? p = buf + offset + 4;
? ? ? ? ? ? ? ? txn = (struct binder_transaction_data *)p;
? ? ? ? ? ? ? ? handle_bx_transaction(tcp, &bwr, txn);
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? offset += (4 + cmd_data_len);
? ? }

? ??dumpstr(tcp,
? ? ? ??(long) bwr.write_buffer,
? ? ? ??bwr.write_size);
? ? tprints("\n");

? ??tprintf("%d) ###?READ ###\n",
? ? ? ? ? ? ioctl_count++);
? ? tprintf("read_size=%llu, "
? ? ? ? ? ? "read_consumed=%llu,\n",
? ? ? ? ? ? bwr.read_size,
? ? ? ? ? ??bwr.read_consumed);
? ? read_len = (bwr.read_size > 256) ?
? ? ? ? ? ? ? ? ? ? ? ??256 : bwr.read_size;
? ? if (umoven(tcp,
? ? ? ??bwr.read_buffer,
? ? ? ??read_len, buf) < 0)
? ? ? ? goto out;

? ??offset = 0;
? ? while (offset < read_len) {
? ? ? ? cmd = get_my_le32(buf + offset);
? ? ? ? cmd_data_len = _IOC_SIZE(cmd);

? ? ? ??switch (cmd) {
? ? ? ? ? ? case BR_TRANSACTION:
? ? ? ? ? ? case BR_REPLY:
? ? ? ? ? ? ? ? tprintf("%s--->\n", cmd_to_str(cmd));
? ? ? ? ? ? ? ? p = buf + offset + 4;
? ? ? ? ? ? ? ? txn = (struct binder_transaction_data *)p;
? ? ? ? ? ? ? ? handle_bx_transaction(tcp, &bwr, txn);
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? offset += (4 + cmd_data_len);
? ? }

? ??tprints("\n");
? ? dumpstr(tcp,
? ? ? ??(long) bwr.read_buffer,
? ? ? ??bwr.read_size);
out:
? ? tprints("}");
}

int binder_ioctl(struct tcb *const tcp,
? ??const unsigned int code,
? ? const kernel_ulong_t arg)
{
? ? switch (code) {
? ? ? ? case BINDER_WRITE_READ:
? ? ? ? ? ? decode_bwr(tcp, arg);
? ? ? ? ? ? break;

? ? ? ? default:
? ? ? ? ? ? return RVAL_DECODED;
? ? }
? ? return RVAL_DECODED | 1;
}

4.3 查看hwbinder的數據
ps -A| grep hwservicemanager
strace -tt -T -x -v -p $PID 2>&1 |grep -vE "writev|futex|getuid|ppoll"

5 Abbreviations
VTS:Vendor Test Suite

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/77356.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77356.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77356.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【AI 加持下的 Python 編程實戰 2_11】DIY 拓展:從掃雷小游戲開發再探問題分解與 AI 代碼調試能力(下)

&#xff08;接 上篇&#xff09; 5 復盤與 Copilot 的交互過程 前面兩篇文章分別涵蓋了掃雷游戲的問題分解和代碼實現過程&#xff0c;不知道各位是否會有代碼一氣呵成的錯覺&#xff1f;實際上&#xff0c;為了達到最終效果&#xff08;如下所示&#xff09;&#xff0c;我…

游戲狀態管理:用Pygame實現場景切換與暫停功能

游戲狀態管理:用Pygame實現場景切換與暫停功能 在開發游戲時,管理游戲的不同狀態(如主菜單、游戲進行中、暫停等)是非常重要的。這不僅有助于提升玩家的游戲體驗,還能使代碼結構更加清晰。本文將通過一個簡單的示例,展示如何使用Pygame庫來實現游戲中的場景切換和暫停功…

Java后端開發day36--源碼解析:HashMap

&#xff08;以下內容均來自上述課程&#xff09; 1. HashMap&#xff08;一&#xff09; 底層&#xff1a;數組鏈表紅黑樹 1.1 前提準備 查看源碼&#xff1a;選中HashMap–ctrlB 小細節&#xff1a;快捷鍵ctrlf12–跳出目錄結構 藍色圓圈&#xff1a;class 證明是類名粉…

RT-Thread學習筆記(四)

RT-Thread學習筆記 線程間同步信號量信號量的使用和管理動態創建信號量靜態創建信號量獲取信號量信號量同步實列互斥量互斥量的使用和管理互斥量動態創建互斥量靜態創建互斥量獲取和釋放互斥量實例事件集事件集的使用和管理動態創建事件集靜態初始化事件集發送和接收事件事件集…

element ui el-col的高度不一致導致換行

問題&#xff1a;ell-col的高度不一致導致換行&#xff0c;刷新后審查el-col的高度一致 我這邊是el-col寫的span超過了24&#xff0c;自行換行&#xff0c;測試發現初次進入里面的高度渲染的不一致&#xff0c;有的是51px有的是51.5px 問題原因分析 Flex布局換行機制 Elemen…

現代化Android開發:Compose提示信息的最佳封裝方案

在 Android 開發中&#xff0c;良好的用戶反饋機制至關重要。Jetpack Compose 提供了現代化的 UI 構建方式&#xff0c;但提示信息(Toast/Snackbar)的管理往往顯得分散。本文將介紹如何優雅地封裝提示信息&#xff0c;提升代碼可維護性。 一、基礎封裝方案 1. 簡單 Snackbar …

【C++語法】類和對象(2)

4.類和對象&#xff08;2&#xff09; 文章目錄 4.類和對象&#xff08;2&#xff09;類的六個默認成員函數(1)構造函數&#xff1a;構造函數特點含有缺省參數的構造函數構造函數特點&#xff08;續&#xff09;注意事項構造函數補充 前面總結了有關對象概念&#xff0c;對比 C…

【自然語言處理與大模型】vLLM部署本地大模型②

舉例上一篇文章已經過去了幾個月&#xff0c;大模型領域風云變幻&#xff0c;之前的vLLM安裝稍有過時&#xff0c;這里補充一個快速安裝教程&#xff1a; # 第一步&#xff1a;創建虛擬環境并激活進入 conda create -n vllm-0.8.4 python3.10 -y conda activate vllm-0…

26 Arcgis軟件常用工具有哪些

一、畫圖改圖工具&#xff08;矢量編輯&#xff09;? ?挪位置工具&#xff08;移動工具&#xff09;? 干哈的&#xff1f;?選中要素?&#xff08;比如地塊、道路&#xff09;直接拖到新位置&#xff0c;或者用坐標?X/Y偏移?批量移動&#xff0c;適合“整體搬家”。 ?磁…

QNX/LINUX/Android系統動態配置動態庫.so文件日志打印級別的方法

背景 通常我們會在量產的產品上&#xff0c;配置軟件僅打印少量日志&#xff0c;以提升產品的運行性能。同時我們要考慮預留方法讓軟件能夠擁有能力可以在燒錄版本后能夠通過修改默寫配置&#xff0c;打印更多日志。因為量產后的軟件通常開啟熔斷與加密&#xff0c;不能夠輕松…

WebGL圖形編程實戰【4】:光影交織 × 逐片元光照與渲染技巧

現實世界中的物體被光線照射時&#xff0c;會反射一部分光。只有當反射光線進人你的眼睛時&#xff0c;你才能夠看到物體并辯認出它的顏色。 光源類型 平行光&#xff08;Directional Light&#xff09;&#xff1a;光線是相互平行的&#xff0c;平行光具有方向。平行光可以看…

【Hive入門】Hive基礎操作與SQL語法:DDL操作全面指南

目錄 1 Hive DDL操作概述 2 數據庫操作全流程 2.1 創建數據庫 2.2 查看數據庫 2.3 使用數據庫 2.4 修改數據庫 2.5 刪除數據庫 3 表操作全流程 3.1 創建表 3.2 查看表信息 3.3 修改表 3.4 刪除表 4 分區與分桶操作 4.1 分區操作流程 4.2 分桶操作 5 最佳實踐與…

YOLO數據處理

YOLO&#xff08;You Only Look Once&#xff09;的數據處理流程是為了解決目標檢測領域的核心挑戰&#xff0c;核心目標是為模型訓練和推理提供高效、規范化的數據輸入。其設計方法系統性地解決了以下關鍵問題&#xff0c;并對應發展了成熟的技術方案&#xff1a; 一、解決的問…

Ubuntu-Linux中vi / vim編輯文件,保存并退出

1.打開文件 vi / vim 文件名&#xff08;例&#xff1a; vim word.txt &#xff09;。 若權限不夠&#xff0c;則在前方添加 sudo &#xff08;例&#xff1a;sudo vim word.txt &#xff09;來增加權限&#xff1b; 2.進入文件&#xff0c;按 i 鍵進入編輯模式。 3.編輯結…

PCL繪制點云+法線

讀取的點云ASCII碼文件&#xff0c;每行6個數據&#xff0c;3維坐標3維法向 #include <iostream> #include <fstream> #include <vector> #include <string> #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pc…

如何在學習通快速輸入答案(網頁版),其他學習平臺通用,手機上快速粘貼

目錄 1、網頁版&#xff08;全平臺通用&#xff09; 2、手機版&#xff08;學習通&#xff0c;其他平臺有可能使用&#xff09; 1、網頁版&#xff08;全平臺通用&#xff09; 1、首先CtrlC復制好答案 2、在學習通的作業里輸入1 3、對準1&#xff0c;然后鼠標右鍵 &#xff…

002 六自由度舵機機械臂——姿態解算理論

00 DH模型的核心概念 【全程干貨【六軸機械臂正逆解計算及仿真示例】】 如何實現機械臂的逆解計算-機器譜-robotway DH模型是機器人運動學建模的基礎方法&#xff0c;通過??四個參數??描述相鄰關節坐標系之間的變換關系。其核心思想是將復雜的空間位姿轉換分解為繞軸旋轉…

pymongo功能整理與基礎操作類

以下是 Python 與 PyMongo 的完整功能整理&#xff0c;涵蓋基礎操作、高級功能、性能優化及常見應用場景&#xff1a; 1. 安裝與連接 (1) 安裝 PyMongo pip install pymongo(2) 連接 MongoDB from pymongo import MongoClient# 基礎連接&#xff08;默認本地&#xff0c;端口…

Trae+DeepSeek學習Python開發MVC框架程序筆記(四):使用sqlite存儲查詢并驗證用戶名和密碼

繼續通過Trae向DeepSeek發問并修改程序&#xff0c;實現程序運行時生成數據庫&#xff0c;用戶在系統登錄頁面輸入用戶名和密碼后&#xff0c;控制器通過模型查詢用戶數據庫表來驗證用戶名和密碼&#xff0c;驗證通過后顯示登錄成功頁面&#xff0c;驗證失敗則顯示登錄失敗頁面…

如何識別金融欺詐行為并進行分析預警

金融行業以其高效便捷的服務深刻改變了人們的生活方式。然而,伴隨技術進步而來的,是金融欺詐行為的日益猖獗。從信用卡盜刷到復雜的龐氏騙局,再到網絡釣魚和洗錢活動,金融欺詐的形式層出不窮,其規模和影響也在不斷擴大。根據全球反欺詐組織(ACFE)的最新報告,僅2022年,…