【OpenHarmony开发】 tracepoint的机制总结

一、tracepoint 的机制

1.1 DECLARE_HOOK 解析

DECLARE_HOOK(vendor_bond_check_dev_link,TP_PROTO(const struct bonding *bond, const struct slave *slave, int *state), TP_ARGS(bond, slave, state));
// 在已经实现如下宏定义的前提下
// CONFIG_TRACEPOINTS 和 CONFIG_VENDOR_HOOKS
#include <trace/hooks/vendor_hooks.h> // 没有的化自行添加
#define DECLARE_HOOK DECLARE_TRACE#include <linux/tracepoint.h>
#define DECLARE_TRACE(name, proto, args) \__DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \cpu_online(raw_smp_processor_id()), \PARAMS(void *__data, proto))#define PARAMS(args...) args
#define TP_PROTO(args...)   args
#define TP_ARGS(args...)    args

经过转换后

__DECLARE_TRACE(vendor_bond_check_dev_link, PARAMS(const struct bonding *bond, const struct slave *slave, int *state), PARAMS(bond, slave, state), \cpu_online(raw_smp_processor_id()), \PARAMS(void *__data, const struct bonding *bond, const struct slave *slave, int *state))|||||||||||||||\|||/\|/|
__DECLARE_TRACE(vendor_bond_check_dev_link, \PARAMS(const struct bonding *bond, const struct slave *slave, int *state), \PARAMS(bond, slave, state), \cpu_online(raw_smp_processor_id()), \PARAMS(void *__data, const struct bonding *bond, const struct slave *slave, int *state))

进一步解析

#define raw_smp_processor_id() (current_thread_info()->cpu) // 获取运行当前线程的CPUID
#define cpu_online(cpu)     cpumask_test_cpu((cpu), cpu_online_mask) // 测试 CPU 掩码中的 CPU
#define __DECLARE_TRACE(name, proto, args, cond, data_proto)            \extern int __traceiter_##name(data_proto);                          \DECLARE_STATIC_CALL(tp_func_##name, __traceiter_##name);            \extern struct tracepoint __tracepoint_##name;                       \static inline void trace_##name(proto)                              \{                                                                   \if (static_key_false(&__tracepoint_##name.key))                 \__DO_TRACE(name,                                            \TP_ARGS(args),                                          \TP_CONDITION(cond), 0);                                 \if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) {                     \rcu_read_lock_sched_notrace();                              \rcu_dereference_sched(__tracepoint_##name.funcs);           \rcu_read_unlock_sched_notrace();                            \}                                                               \}                                                                   \__DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args),              \PARAMS(cond))                                           \static inline int                                                   \register_trace_##name(void (*probe)(data_proto), void *data)        \{                                                                   \return tracepoint_probe_register(&__tracepoint_##name,          \(void *)probe, data);                           \}                                                                   \static inline int                                                   \register_trace_prio_##name(void (*probe)(data_proto), void *data,   \int prio)                                            \{                                                                   \return tracepoint_probe_register_prio(&__tracepoint_##name,     \(void *)probe, data, prio);                   \}                                                                   \static inline int                                                   \unregister_trace_##name(void (*probe)(data_proto), void *data)      \{                                                                   \return tracepoint_probe_unregister(&__tracepoint_##name,        \(void *)probe, data);                           \}                                                                   \static inline void                                                  \check_trace_callback_type_##name(void (*cb)(data_proto))            \{                                                                   \}                                                                   \static inline bool                                                  \trace_##name##_enabled(void)                                        \{                                                                   \return static_key_false(&__tracepoint_##name.key);              \}

转换后结果

__DECLARE_TRACE( \vendor_bond_check_dev_link, \PARAMS(const struct bonding *bond, const struct slave *slave, int *state), \PARAMS(bond, slave, state), \cpu_online(raw_smp_processor_id()), \PARAMS(void *__data, const struct bonding *bond, const struct slave *slave, int *state) \
)|||||||||||||||\|||/\|/|
extern int __traceiter_vendor_bond_check_dev_link(void *__data, const struct bonding *bond, const struct slave *slave, int *state);
DECLARE_STATIC_CALL(tp_func_vendor_bond_check_dev_link, __traceiter_vendor_bond_check_dev_link);
extern struct tracepoint __tracepoint_vendor_bond_check_dev_link;static inline void trace_vendor_bond_check_dev_link(const struct bonding *bond, const struct slave *slave, int *state)
{if (static_key_false(&__tracepoint_vendor_bond_check_dev_link.key))__DO_TRACE(vendor_bond_check_dev_link,TP_ARGS(bond, slave, state),TP_CONDITION(cpu_online(raw_smp_processor_id())), 0);if (IS_ENABLED(CONFIG_LOCKDEP) && (cpu_online(raw_smp_processor_id()))) {rcu_read_lock_sched_notrace();rcu_dereference_sched(__tracepoint_vendor_bond_check_dev_link.funcs);rcu_read_unlock_sched_notrace();}
}__DECLARE_TRACE_RCU( \vendor_bond_check_dev_link, \PARAMS(const struct bonding *bond, const struct slave *slave, int *state), \PARAMS(bond, slave, state), \PARAMS(cpu_online(raw_smp_processor_id()))
)static inline int register_trace_vendor_bond_check_dev_link(void (*probe)(void *__data, const struct bonding *bond, const struct slave *slave, int *state),void *data)
{return tracepoint_probe_register(&__tracepoint_vendor_bond_check_dev_link, (void *)probe, data);
}static inline int register_trace_prio_vendor_bond_check_dev_link(void (*probe)(void *__data, const struct bonding *bond, const struct slave *slave, int *state),void *data, int prio)
{return tracepoint_probe_register_prio(&__tracepoint_vendor_bond_check_dev_link, (void *)probe, data, prio);
}static inline int unregister_trace_vendor_bond_check_dev_link(void (*probe)(void *__data, const struct bonding *bond, const struct slave *slave, int *state),void *data)
{return tracepoint_probe_unregister(&__tracepoint_vendor_bond_check_dev_link, (void *)probe, data);
}static inline void check_trace_callback_type_vendor_bond_check_dev_link(void (*cb)(void *__data, const struct bonding *bond, const struct slave *slave, int *state))
{
}static inline bool trace_vendor_bond_check_dev_link_enabled(void)
{return static_key_false(&__tracepoint_vendor_bond_check_dev_link.key);
}

1.2 DECLARE_STATIC_CALL 解析

 

#define DECLARE_STATIC_CALL(name, func) \extern struct static_call_key STATIC_CALL_KEY(name); \extern typeof(func) STATIC_CALL_TRAMP(name);#define STATIC_CALL_KEY(name)       __PASTE(STATIC_CALL_KEY_PREFIX, name)
#define __PASTE(a,b) ___PASTE(a,b)
#define ___PASTE(a,b) a##b
#define STATIC_CALL_KEY_PREFIX      __SCK__#define STATIC_CALL_TRAMP(name)     __PASTE(STATIC_CALL_TRAMP_PREFIX, name)
#define STATIC_CALL_TRAMP_PREFIX    __SCT__|||||||||||||||\|||/\|/|
#define DECLARE_STATIC_CALL(name, func) \extern struct static_call_key __SCK__##name; \extern typeof(func) __SCT__##name;

转换后

extern int __traceiter_vendor_bond_check_dev_link(void *__data, const struct bonding *bond, const struct slave *slave, int *state);
DECLARE_STATIC_CALL(tp_func_vendor_bond_check_dev_link, __traceiter_vendor_bond_check_dev_link);|||||||||||||||\|||/\|/|
extern int __traceiter_vendor_bond_check_dev_link(void *__data, const struct bonding *bond, const struct slave *slave, int *state);
extern struct static_call_key __SCK__tp_func_vendor_bond_check_dev_link;
extern typeof(__traceiter_vendor_bond_check_dev_link) __SCT__tp_func_vendor_bond_check_dev_link; // 定义一个和__traceiter_vendor_bond_check_dev_link相同类型的变量

1.3 trace_vendor_bond_check_dev_link 函数解析---执行钩子函数

struct tracepoint {const char *name;struct static_key key;struct static_call_key *static_call_key;void *static_call_tramp;void *iterator;int (*regfunc)(void);void (*unregfunc)(void);struct tracepoint_func __rcu *funcs;
};extern struct tracepoint __tracepoint_vendor_bond_check_dev_link;static inline void trace_vendor_bond_check_dev_link(const struct bonding *bond, const struct slave *slave, int *state)
{// 使用了全局变量__tracepoint_vendor_bond_check_dev_link,必定有地方会初始化了该变量if (static_key_false(&__tracepoint_vendor_bond_check_dev_link.key))__DO_TRACE(vendor_bond_check_dev_link,TP_ARGS(bond, slave, state),TP_CONDITION(cpu_online(raw_smp_processor_id())), 0);if (IS_ENABLED(CONFIG_LOCKDEP) && (cpu_online(raw_smp_processor_id()))) {rcu_read_lock_sched_notrace();rcu_dereference_sched(__tracepoint_vendor_bond_check_dev_link.funcs);rcu_read_unlock_sched_notrace();}
}

1.4 __DECLARE_TRACE_RCU 解析

#define __DECLARE_TRACE_RCU(name, proto, args, cond) \static inline void trace_##name##_rcuidle(proto) \{ \if (static_key_false(&__tracepoint_##name.key)) \__DO_TRACE(name, \TP_ARGS(args), \TP_CONDITION(cond), 1); \}

1.5 register_trace_vendor_bond_check_dev_link 函数介绍---注册钩子函数

static inline int register_trace_vendor_bond_check_dev_link(void (*probe)(void *__data, const struct bonding *bond, const struct slave *slave, int *state),void *data)
{return tracepoint_probe_register(&__tracepoint_vendor_bond_check_dev_link, (void *)probe, data);
}
int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data)
{return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO);
}
int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, int prio)
{struct tracepoint_func tp_func;int ret;mutex_lock(&tracepoints_mutex);tp_func.func = probe;tp_func.data = data;tp_func.prio = prio;ret = tracepoint_add_func(tp, &tp_func, prio, true); // 整个过程就是显示tp = tp_funcmutex_unlock(&tracepoints_mutex);return ret;
}
static int tracepoint_add_func(struct tracepoint *tp,struct tracepoint_func *func, int prio, bool warn)
{struct tracepoint_func *old, *tp_funcs;int ret;if (tp->regfunc && !static_key_enabled(&tp->key)) {ret = tp->regfunc();if (ret < 0)return ret;}// 核心代码1,拿到钩子列表tp_funcs = rcu_dereference_protected(tp->funcs,lockdep_is_held(&tracepoints_mutex));// 核心代码2,注册新的钩子到列表old = func_add(&tp_funcs, func, prio);if (IS_ERR(old)) {WARN_ON_ONCE(warn && PTR_ERR(old) != -ENOMEM);return PTR_ERR(old);}/** rcu_assign_pointer has as smp_store_release() which makes sure* that the new probe callbacks array is consistent before setting* a pointer to it.  This array is referenced by __DO_TRACE from* include/linux/tracepoint.h using rcu_dereference_sched().*/switch (nr_func_state(tp_funcs)) {case TP_FUNC_1:        /* 0->1 *//** Make sure new static func never uses old data after a* 1->0->1 transition sequence.*/tp_rcu_cond_sync(TP_TRANSITION_SYNC_1_0_1);/* Set static call to first function */tracepoint_update_call(tp, tp_funcs);/* Both iterator and static call handle NULL tp->funcs */rcu_assign_pointer(tp->funcs, tp_funcs);static_key_enable(&tp->key);break;case TP_FUNC_2:        /* 1->2 *//* Set iterator static call */tracepoint_update_call(tp, tp_funcs);/** Iterator callback installed before updating tp->funcs.* Requires ordering between RCU assign/dereference and* static call update/call.*/fallthrough;case TP_FUNC_N:        /* N->N+1 (N>1) */rcu_assign_pointer(tp->funcs, tp_funcs);/** Make sure static func never uses incorrect data after a* N->...->2->1 (N>1) transition sequence.*/if (tp_funcs[0].data != old[0].data)tp_rcu_get_state(TP_TRANSITION_SYNC_N_2_1);break;default:WARN_ON_ONCE(1);break;}release_probes(old);return 0;
}

1.6 unregister_trace_vendor_bond_check_dev_link 函数解析---注销钩子函数

不做介绍了,和 register 类似

二、tracepiont 其他的功能介绍

【待补充】

三、Demo 实例讲解

后面实现用例的时候补充,当前仅介绍官方的 demo

3.1 驱动侧代码实现

 

#include <trace/hooks/bonding.h>static void vendor_foo(void *data, const struct bonding *bond,const struct slave *slave, int *state)
{pr_info("%s\n", __func__);                                                                                                                                                                                                                                                                            
}static int __init vendor_bond_init(void)
{return register_trace_vendor_bond_check_dev_link(&vendor_foo, NULL);
}static void __exit vendor_bond_exit(void)
{unregister_trace_vendor_bond_check_dev_link(&vendor_foo, NULL);
}module_init(vendor_bond_init);
module_exit(vendor_bond_exit);

3.2 内核侧代码实现

代码合入链接

3.3 测试代码

#include <linux/kernel.h>                                                                                                                                                                                                                                                                                       
#include <linux/module.h>
#include <net/bonding.h>
#include <trace/hooks/bonding.h>static void vendor_bond_check_dev_link(void *data, const struct bonding *bond,const struct slave *slave, int *state)
{pr_info("%s\n", __func__);
}static int __init bondingTestInit(void)
{return register_trace_vendor_bond_check_dev_link(&vendor_bond_check_dev_link, NULL);
}static void __exit bondingTestExit(void)
{printk("bonding test exit\n");unregister_trace_vendor_bond_check_dev_link(&vendor_bond_check_dev_link, NULL);
}/* 模块入口和出口函数 */
module_init(bondingTestInit)
module_exit(bondingTestExit)/* 模块信息 */
MODULE_AUTHOR("Wei Yongjun <[email]weiyongjun1@huawei.com[/email]>");
MODULE_LICENSE("GPL");
MODULE_ESCRIPTION("bondtest driver");

最后

有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。 

鸿蒙HarmonyOS Next全套学习资料←点击领取!(安全链接,放心点击

这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

鸿蒙(HarmonyOS NEXT)最新学习路线

有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)与鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

HarmonyOS Next 最新全套视频教程

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

大厂面试必问面试题

鸿蒙南向开发技术

鸿蒙APP开发必备

鸿蒙生态应用开发白皮书V2.0PDF

获取以上完整鸿蒙HarmonyOS学习资料,请点击→

纯血版全套鸿蒙HarmonyOS学习资料

总结
总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

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

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

相关文章

AbMole带你探索颅内压力与肌肉生长的联系:一项突破性研究

在生物医学领域&#xff0c;颅内压力&#xff08;ICP&#xff09;的调控机制一直是研究的热点。最近&#xff0c;一项发表在《PLOS ONE》上的研究为我们揭示了颅内压力与后颅窝肌肉生长之间的潜在联系&#xff0c;为我们理解某些慢性头痛的成因提供了新的视角。 颅内压力的异常…

temu跨境选品师是怎么样的一个项目?

TEMU(特穆)跨境选品师项目&#xff0c;作为一项创新的全球商品采购和选品服务&#xff0c;正在逐步改变消费者对于跨境电商产品的认知和选择方式。这个项目不仅仅是一个简单的商品推荐平台&#xff0c;更是一种以数据驱动的精准选品策略的体现&#xff0c;为消费者提供了全新的…

Spring Boot集成vavr快速入门demo

1.什么是vavr&#xff1f; 初闻vavr&#xff0c;感觉很奇怪&#xff0c;咋这个名字&#xff0c;后面看到它的官网我沉默了&#xff0c;怀疑初创团队付费资讯了UC震惊部如何取名字&#xff0c;好家伙&#xff0c;vavr就是java这四个字倒过来&#xff0c;真的是’颠覆’了java……

为什么Mid journey很容易就能做出很有氛围感的图而SD却容易做图很丑?

前言 6月12日&#xff0c;Midjourney更新了一项新的功能——模型个性化&#xff0c;这一项功能最重要的作用就是能够让生成的图像更加符合你自己的审美标准。就像每个艺术家都有自己的独特风格一样&#xff0c;有了这项模型个性化功能的加持&#xff0c;每个人都能生成具有鲜明…

【机器学习】第5章 朴素贝叶斯分类器

一、概念 1.贝叶斯定理&#xff1a; &#xff08;1&#xff09;就是“某个特征”属于“某种东西”的概率&#xff0c;公式就是最下面那个公式。 2.朴素贝叶斯算法概述 &#xff08;1&#xff09;是为数不多的基于概率论的分类算法&#xff0c;即通过考虑特征概率来预测分类。 …

C#利用SignalR实现通信事例Demo

1.服务端安装SignalR的Nuget包 dotnet add package Microsoft.AspNet.SignalR --version 2.4.3 2.接下来&#xff0c;创建一个ChatHub类&#xff0c;它是SignalR通信的核心&#xff1a; using Microsoft.AspNetCore.SignalR;public class ChatHub : Hub {public static Dict…

MATLAB 二维平面绘图

x 0:0.01:2pi: 大家还记得这个是什么意思吧 就是0到2π 每次所取的数 是相差0.01进行选取的 ysin&#xff08;x&#xff09;: figure (这个意思就是建立一个幕布) plot&#xff08;x&#xff0c;y&#xff09; 这个主要是绘制当前的二维平面的图 但是大家会发现这张图里没有标…

反激开关电源输入电解电容选型及计算

输入电解电容波形如下 计算 1、输入电解电容经验选取法 当输入电压为220V20%&#xff08;AC176-264V&#xff09;时 按照输出功率选取&#xff1a;W/μF 耐压&#xff08;400V&#xff0c;输入176-264V最高DC峰值373V&#xff09; 当输入电压为11020%时&#xff08;AC88-132V…

windows服务器一台机器安装多个mysql实例

1、复制安装mysql安装包 2、修改配置文件信息 标注红色部分是需要修改成复制后的包信息 [mysqld] default-time_zone8:00basedirD:/tools/MySQL-Cluster/mysql-53306 datadirD:/tools/MySQL-Cluster/mysql-53306/data default-storage-engineINNODB sql-mode"STRICT_TRANS…

网络运维:企业数字化转型的基石

在数字化时代&#xff0c;网络已经成为企业运营不可或缺的一部分。网络运维作为确保网络稳定、安全和高效运行的关键环节&#xff0c;其重要性不言而喻。本文将探讨网络运维的重要性&#xff0c;并分析其在企业数字化转型中的作用。 网络运维的定义 网络运维&#xff0c;也称…

Amazon Systems Manager中补丁合规性定期扫描

问题 需要使用Amazon Systems Manager对EC2补丁合规性定期扫描。 步骤 点击如下入口界面&#xff1a; 权限使用默认配置&#xff0c;勾选“Scan instances for missing patches daily”每天扫描EC2实例是否存在补丁&#xff0c;来完成合规检查&#xff0c;选择所有实例&…

Zabbix自定义监控JAVA进程

一.定义脚本 二 .ZABBIX得agent允许以root身份执行 三. Zabbix测试自定item是否成功 四.ZABBIX服务端web添加新得item项 五.查看最新数据&#xff0c;取值成功

每日AI资讯-20240618

1. 3D 版 SORA 来了&#xff01; DreamTech 官宣了其高质量 3D 生成大模型 Direct3D&#xff0c;并公开了相关学术论文 Direct3D: Scalable Image-to-3D Generation via 3D Latent Diffusion Transformer。 链接&#xff1a;https://arxiv.org/abs/2405.14832 这是首个公开发布…

分享一下,如何搭建个人网站的步骤

在这段充满探索与创造的奇妙旅途中&#xff0c;我就像一位耐心的建筑师&#xff0c;在数字世界的荒原上精心雕琢&#xff0c;两周的时光缓缓流淌。每天&#xff0c;我与代码共舞&#xff0c;手执HTML、CSS与JavaScript这三大构建魔杖&#xff0c;一砖一瓦地筑起了梦想中的网络城…

JDK与JRE与JVM:它们之间的区别

JDK与JRE与JVM&#xff1a;它们之间的区别 JDK&#xff08;Java开发工具包&#xff09; JDK是JRE的超集&#xff0c;它包含JRE所拥有的一切以及编译器、调试器等开发工具。 JDK代表Java开发工具包。要在您的系统上安装Java&#xff0c;您需要首先在系统上安装JDK。 JDK包含编…

Blazor 中基于角色的授权

介绍 Blazor用于使用 .NET 代码库创建交互式客户端 Web UI。Microsoft 默认在 Blazor 应用程序中提供了一个用于身份验证和授权的身份框架。请注意&#xff0c;他们目前使用 MVC Core Razor 页面作为身份验证 UI。使用“Microsoft.AspNetCore.Identity.UI”包库来实现这一点。…

实战|YOLOv10 自定义目标检测

引言 YOLOv10[1] 概述和使用自定义数据训练模型 概述 由清华大学的研究团队基于 Ultralytics Python 包研发的 YOLOv10&#xff0c;通过优化模型结构并去除非极大值抑制&#xff08;NMS&#xff09;环节&#xff0c;提出了一种创新的实时目标检测技术。这些改进不仅实现了行业领…

基于STM32和人工智能的智能楼宇安防系统

目录 引言环境准备智能楼宇安防系统基础代码实现&#xff1a;实现智能楼宇安防系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统4.4 用户界面与数据可视化应用场景&#xff1a;智能楼宇安防管理与优化问题解决方案与优化收尾与总结 1. 引言 随着物联网和人工智能技术的…

考研数学|做完《660》,做《880》还是吃力,怎么办?

880吃力说明基础还是不太扎实&#xff0c;建议配合知能行再刷880。 强化之前做660&#xff0c;然后在强化的时候再做880。 660整体难度属于基础阶段到强化阶段。而且是选填部分的题目&#xff0c;所以还是要做一些其他题 然后说一下推荐的习题册&#xff1a;基础不好先做1800、…

公司电脑加密软件——【中科数安】电脑文件资料透明加密,防泄密系统

中科数安电脑文件资料透明加密防泄密系统介绍 中科数安提供的电脑文件资料透明加密防泄密系统&#xff0c;是一款专为企业电脑终端设计的数据安全解决方案。该系统通过采用先进的透明加密技术和精细化的权限管理&#xff0c;旨在全方位保护公司电脑中存储、处理、传输的各类文…