【Android 10 源码】healthd 模块 HAL 1.0 分析

2024-05-01 20:58

本文主要是介绍【Android 10 源码】healthd 模块 HAL 1.0 分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

health@1.0:android.hardware.health@1.0 的缩写。指的是 Android 8.0 中发布的运行状况 HIDL 的 1.0 版 HAL。

Android 8.x 中的“运行状况”服务

在 Android 8.x 中,运行状况组件的工作原理详情如下图所示:

在这里插入图片描述
在此图中:

  1. 框架通过一次 Binder 调用和一次 hwbinder 调用与硬件进行通信。
  2. healthd 静态关联到 libhealthd_android、libbatterymonitor 和 libbatteryservice。
  3. health@1.0-impl 静态关联到 libhealthd.BOARD。

每个开发板都可以自定义不同的 libhealthd.BOARD;charger、health@1.0-impl 和 recovery 关联到哪个开发板是在构建时确定的。

对于其他模式:

在这里插入图片描述
charger 静态关联到 libhealthd.BOARD、libhealthd_charger 和 libbatterymonitor。

recovery 静态关联到 libhealthd.BOARD 和 libbatterymonitor。

health@1.0 HAL 中的定义:

hardware/interfaces/health/1.0/types.hal

package android.hardware.health@1.0;/*** Possible return values for optional HAL method(s) like* IHealth::energyCounter()* 可选HAL方法的可能返回值*/
enum Result : int32_t {SUCCESS,NOT_SUPPORTED,UNKNOWN,
};/*** Possible values for Battery Status.* “电池状态”的取值范围。* Note: These are currently in sync with BatteryManager and must not* be extended / altered.* 注意:这些目前与 BatteryManager 同步,不能扩展/更改。*/
@export(name="", value_prefix="BATTERY_STATUS_")
enum BatteryStatus : int32_t {UNKNOWN = 1,CHARGING = 2,DISCHARGING = 3,/*** Battery is *not* charging - special case when charger is present* but battery isn't charging*/NOT_CHARGING = 4,FULL = 5,
};/*** Possible values for Battery Health.* 电池运行状况的可能值。* Note: These are currently in sync with BatteryManager and must not* be extended / altered.* 注意:这些目前与 BatteryManager 同步,不能扩展/更改。*/
@export(name="", value_prefix="BATTERY_HEALTH_")
enum BatteryHealth : int32_t {UNKNOWN = 1,GOOD = 2,OVERHEAT = 3,DEAD = 4,OVER_VOLTAGE = 5,/*** Battery experienced an unknown/unspecifid failure.*/UNSPECIFIED_FAILURE = 6,COLD = 7,
};struct HealthConfig {/*** periodicChoresIntervalFast is used while the device is not in* suspend, or in suspend and connected to a charger (to watch for battery* overheat due to charging)* 当设备不处于挂起状态或挂起并连接到充电器时使用 periodicChoresIntervalFast* (观察电池因充电而过热)*/int32_t periodicChoresIntervalFast;/*** periodicChoresIntervalSlow is used when the device is in suspend and* not connected to a charger (to watch for a battery drained to zero* remaining capacity).* 当设备处于挂起状态且未连接充电器时,* 使用 periodicChoresIntervalSlow (观察电池耗尽至剩余容量为零)。*/int32_t periodicChoresIntervalSlow;/*** power_supply sysfs attribute file paths. Set these to specific paths* to use for the associated battery parameters. Clients must search* for appropriate power_supply attribute files to use, for any paths* left empty after the HAL is initialized.*//*** batteryStatusPath - file path to read battery charging status.* 读取电池充电状态的文件路径。* (POWER_SUPPLY_PROP_STATUS)*/string batteryStatusPath;/*** batteryHealthPath - file path to read battery health.* 读取电池运行状况的文件路径。* (POWER_SUPPLY_PROP_HEALTH)*/string batteryHealthPath;/*** batteryPresentPath - file path to read battery present status.* 读取电池当前状态的文件路径。* (POWER_SUPPLY_PROP_PRESENT)*/string batteryPresentPath;/*** batteryCapacityPath - file path to read remaining battery capacity.* 读取剩余电池容量的文件路径。* (POWER_SUPPLY_PROP_CAPACITY)*/string batteryCapacityPath;/*** batteryVoltagePath - file path to read battery voltage.* 读取电池电压的文件路径。* (POWER_SUPPLY_PROP_VOLTAGE_NOW)*/string batteryVoltagePath;/*** batteryTemperaturePath - file path to read battery temperature in tenths* of degree celcius. (POWER_SUPPLY_PROP_TEMP)* 读取电池温度摄氏度乘以10后的文件路径。*/string batteryTemperaturePath;/*** batteryTechnologyPath - file path to read battery technology.* 读取电池技术的文件路径。* (POWER_SUPPLY_PROP_TECHNOLOGY)*/string batteryTechnologyPath;/*** batteryCurrentNowPath - file path to read battery instantaneous current.* 读取电池瞬时电流的文件路径。* (POWER_SUPPLY_PROP_CURRENT_NOW)*/string batteryCurrentNowPath;/*** batteryCurrentAvgPath - file path to read battery average current.* 读取电池平均电流的文件路径。* (POWER_SUPPLY_PROP_CURRENT_AVG)*/string batteryCurrentAvgPath;/*** batteryChargeCounterPath - file path to read battery accumulated charge.* 读取电池累计充电电量的文件路径。* (POWER_SUPPLY_PROP_CHARGE_COUNTER)*/string batteryChargeCounterPath;/*** batteryFullChargerPath - file path to read battery charge value when it* is considered to be full. (POWER_SUPPLY_PROP_CHARGE_FULL)* 读取电池充满时的对应值文件路径。*/string batteryFullChargePath;/*** batteryCycleCountPath - file path to read battery charge cycle count.* 读取电池充电周期计数文件路径。* (POWER_SUPPLY_PROP_CYCLE_COUNT)*/string batteryCycleCountPath;
};/*** The parameter to healthd mainloop update calls* healthd 主循环更新调用的参数*/
struct HealthInfo {/** AC charger state - 'true' if online */ /** 交流充电状态 */bool chargerAcOnline;/** USB charger state - 'true' if online */ /** USB 充电状态 */bool chargerUsbOnline;/** Wireless charger state - 'true' if online */ /** 无线充电状态 */bool chargerWirelessOnline;/** Maximum charging current supported by charger in uA *//** 充电器支持的最大充电电流(uA) */int32_t maxChargingCurrent;/** Maximum charging voltage supported by charger in uV *//** 充电器支持的最大充电电压(uV) */int32_t maxChargingVoltage;BatteryStatus batteryStatus;BatteryHealth batteryHealth;/** 'true' if battery is present *//** 如果有电池,则为 true */bool batteryPresent;/** Remaining battery capacity in percent *//** 剩余电池容量百分比 */int32_t batteryLevel;/*** Instantaneous battery voltage in millivolts (mV).* 瞬间电池电压(毫伏)。** Historically, the unit of this field is microvolts (uV), but all* clients and implementations uses millivolts in practice, making it* the de-facto standard.*/int32_t batteryVoltage;/** Instantaneous battery temperature in tenths of degree celcius *//** 瞬间电池温度 */int32_t batteryTemperature;/** Instantaneous battery current in uA *//** 瞬时电池电流(uA) */int32_t batteryCurrent;/** Battery charge cycle count *//** 电池充电周期计数 */int32_t batteryCycleCount;/** Battery charge value when it is considered to be "full" in uA-h *//** 当认为电池“满”时的电池充电值(uA-h) */int32_t batteryFullCharge;/** Instantaneous battery capacity in uA-h *//** 瞬时电池容量(uA-h) */int32_t batteryChargeCounter;/** Battery technology, e.g. "Li-ion, Li-Poly" etc. *//** 电池技术 */string batteryTechnology;
};

hardware/interfaces/health/1.0/IHealth.hal

package android.hardware.health@1.0;interface IHealth {/*** This function lets you change healthd configuration from default if* desired. It must be called exactly once at startup time.* 如果需要,这个功能可以让你改变默认的 healthd 配置。它必须在启动时调用一次。** The configuration values are described in 'struct HealthConfig'.* To use default configuration, simply return without modifying the* fields of the config parameter.* 配置值在“struct HealthConfig”中描述。* 要使用默认配置,只需返回而不修改 config 参数的字段。** @param default healthd configuration.*/init(HealthConfig config) generates (HealthConfig configOut);/*** This function is a hook to update/change device's HealthInfo (as described* in 'struct HealthInfo').* 这个函数是一个 hook 来更新/改变设备的 HealthInfo** 'HealthInfo' describes device's battery and charging status, typically* read from kernel. These values may be modified in this call.* “HealthInfo”描述设备的电池和充电状态,通常从内核读取。* 这些值可以在这个调用中修改。** @param   Device Health info as described in 'struct HealthInfo'.* @return  skipLogging Indication to the caller to add 'or' skip logging the health*          information. Return 'true' to skip logging the update.* @return  infoOut HealthInfo to be sent to client code. (May or may*          not be modified).*/update(HealthInfo info) generates (bool skipLogging, HealthInfo infoOut);/*** This function is called by healthd when framework queries for remaining* energy in the Battery through BatteryManager APIs.* 当框架通过 BatteryManager API 查询电池中的剩余电量时,* healthd 会调用这个函数。** @return  result Result of querying enery counter for the battery.* @return  energy Battery remaining energy in nanowatt-hours.*          Must be '0' if result is anything other than Result::SUCCESS.*/energyCounter() generates (Result result, int64_t energy);
};

现在重点来分析 hardware/interfaces/health/1.0/default/ 下的实现。Android.mk 中编译了两个模块,分别为 android.hardware.health@1.0-impl 和 android.hardware.health@1.0-service(可执行文件)。android.hardware.health@1.0-impl 主要使用了 Health.cpp 源文件,android.hardware.health@1.0-service 则使用了 HealthService.cpp 源文件。

hardware/interfaces/health/1.0/default/Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)
LOCAL_MODULE := android.hardware.health@1.0-impl
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_C_INCLUDES := system/core/base/include
LOCAL_SRC_FILES := \Health.cpp \LOCAL_HEADER_LIBRARIES := libhealthd_headersLOCAL_SHARED_LIBRARIES := \libcutils \libhidlbase \libhidltransport \liblog \libutils \android.hardware.health@1.0 \LOCAL_STATIC_LIBRARIES := android.hardware.health@1.0-convertLOCAL_HAL_STATIC_LIBRARIES := libhealthdinclude $(BUILD_SHARED_LIBRARY)include $(CLEAR_VARS)
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE := android.hardware.health@1.0-service
LOCAL_INIT_RC := android.hardware.health@1.0-service.rc
LOCAL_SRC_FILES := \HealthService.cpp \LOCAL_SHARED_LIBRARIES := \liblog \libcutils \libdl \libbase \libutils \libhidlbase \libhidltransport \android.hardware.health@1.0 \include $(BUILD_EXECUTABLE)include $(call first-makefiles-under,$(LOCAL_PATH))

android.hardware.health@1.0-impl 包含了 HAL 的实现以及一个导出函数 HIDL_FETCH_IHealth(…) ,HIDL_FETCH_IHealth(…) 获取 HAL 实现的对象,只是 new 了一个 Health 结构体返回。

Health::init(…) 实现主要流程:

  1. 创建一个 healthd_config struct;
  2. 为了使得 healthd 静态 HAL 工作正常,调用 convertFromHealthConfig(…) 将 HealthConfig 转换为 healthd_config;
  3. 调用 healthd_board_init(…) 进一步板级初始化;
  4. 给 mGetEnergyCounter 字段赋值;
  5. 调用 convertToHealthConfig(…) 再将 healthd_config 转换为 HealthConfig 结构,并返回。

Health::update(…) 实现主要流程:

  1. 创建 android::BatteryProperties 结构;
  2. 调用 convertFromHealthInfo(…) 将 HealthInfo 转为 android::Batteryproperties;
  3. 调用板级更新 healthd_board_battery_update(…);
  4. 调用 convertToHealthInfo(…) 将 android::Batteryproperties 转为 HealthInfo。

Health::energyCounter(…) 实现非常简单主要调用了 mGetEnergyCounter 指向的函数指针获取剩余电量。

hardware/interfaces/health/1.0/default/Health.cpp

using ::android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
using ::android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
using ::android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;// Methods from ::android::hardware::health::V1_0::IHealth follow.
Return<void> Health::init(const HealthConfig& config, init_cb _hidl_cb)  {struct healthd_config healthd_config = {};HealthConfig configOut;// To keep working with existing healthd static HALs,// convert the new HealthConfig to the old healthd_config// and back.convertFromHealthConfig(config, &healthd_config);healthd_board_init(&healthd_config);mGetEnergyCounter = healthd_config.energyCounter;convertToHealthConfig(&healthd_config, configOut);_hidl_cb(configOut);return Void();
}Return<void> Health::update(const HealthInfo& info, update_cb _hidl_cb)  {struct android::BatteryProperties p = {};HealthInfo infoOut;// To keep working with existing healthd static HALs,// convert the new HealthInfo to android::Batteryproperties// and back.convertFromHealthInfo(info, &p);int skipLogging = healthd_board_battery_update(&p);convertToHealthInfo(&p, infoOut);_hidl_cb(!!skipLogging, infoOut);return Void();
}Return<void> Health::energyCounter(energyCounter_cb _hidl_cb) {int64_t energy = 0;Result result = Result::NOT_SUPPORTED;if (mGetEnergyCounter) {int status = mGetEnergyCounter(&energy);if (status == 0) {result = Result::SUCCESS;}}_hidl_cb(result, energy);return Void();
}IHealth* HIDL_FETCH_IHealth(const char* /* name */) {return new Health();
}

上面提到的转换适配函数定义在 convert.cpp 中,实现了 healthd_config 和 HealthConfig 互转,
BatteryProperties 和 HealthInfo 互转。

hardware/interfaces/health/1.0/default/convert.cpp

void convertToHealthConfig(const struct healthd_config *hc, HealthConfig& config) {config.periodicChoresIntervalFast = hc->periodic_chores_interval_fast;config.periodicChoresIntervalSlow = hc->periodic_chores_interval_slow;config.batteryStatusPath        = hc->batteryStatusPath.string();config.batteryHealthPath        = hc->batteryHealthPath.string();config.batteryPresentPath       = hc->batteryPresentPath.string();config.batteryCapacityPath      = hc->batteryCapacityPath.string();config.batteryVoltagePath       = hc->batteryVoltagePath.string();config.batteryTemperaturePath   = hc->batteryTemperaturePath.string();config.batteryTechnologyPath    = hc->batteryTechnologyPath.string();config.batteryCurrentNowPath    = hc->batteryCurrentNowPath.string();config.batteryCurrentAvgPath    = hc->batteryCurrentAvgPath.string();config.batteryChargeCounterPath = hc->batteryChargeCounterPath.string();config.batteryFullChargePath    = hc->batteryFullChargePath.string();config.batteryCycleCountPath    = hc->batteryCycleCountPath.string();}void convertFromHealthConfig(const HealthConfig& c, struct healthd_config *hc) {hc->periodic_chores_interval_fast = c.periodicChoresIntervalFast;hc->periodic_chores_interval_slow = c.periodicChoresIntervalSlow;hc->batteryStatusPath =android::String8(c.batteryStatusPath.c_str(),c.batteryStatusPath.size());hc->batteryHealthPath =android::String8(c.batteryHealthPath.c_str(),c.batteryHealthPath.size());hc->batteryPresentPath =android::String8(c.batteryPresentPath.c_str(),c.batteryPresentPath.size());hc->batteryCapacityPath =android::String8(c.batteryCapacityPath.c_str(),c.batteryCapacityPath.size());hc->batteryVoltagePath =android::String8(c.batteryVoltagePath.c_str(),c.batteryVoltagePath.size());hc->batteryTemperaturePath =android::String8(c.batteryTemperaturePath.c_str(),c.batteryTemperaturePath.size());hc->batteryTechnologyPath =android::String8(c.batteryTechnologyPath.c_str(),c.batteryTechnologyPath.size());hc->batteryCurrentNowPath =android::String8(c.batteryCurrentNowPath.c_str(),c.batteryCurrentNowPath.size());hc->batteryCurrentAvgPath =android::String8(c.batteryCurrentAvgPath.c_str(),c.batteryCurrentNowPath.size());hc->batteryChargeCounterPath =android::String8(c.batteryChargeCounterPath.c_str(),c.batteryChargeCounterPath.size());hc->batteryFullChargePath =android::String8(c.batteryFullChargePath.c_str(),c.batteryFullChargePath.size());hc->batteryCycleCountPath =android::String8(c.batteryCycleCountPath.c_str(),c.batteryCycleCountPath.size());// energyCounter is handled through special means so all calls to// the function go across the HALs// boot_min_cap - never used in Android (only in charger-mode).// screen_on - never used in Android (only in charger mode).
}void convertToHealthInfo(const struct android::BatteryProperties *p,HealthInfo& info) {info.chargerAcOnline        = p->chargerAcOnline;info.chargerUsbOnline       = p->chargerUsbOnline;info.chargerWirelessOnline  = p->chargerWirelessOnline;info.maxChargingCurrent     = p->maxChargingCurrent;info.maxChargingVoltage     = p->maxChargingVoltage;info.batteryStatus          = static_cast<BatteryStatus>(p->batteryStatus);info.batteryHealth          = static_cast<BatteryHealth>(p->batteryHealth);info.batteryPresent         = p->batteryPresent;info.batteryLevel           = p->batteryLevel;info.batteryVoltage         = p->batteryVoltage;info.batteryTemperature     = p->batteryTemperature;info.batteryCurrent         = p->batteryCurrent;info.batteryCycleCount      = p->batteryCycleCount;info.batteryFullCharge      = p->batteryFullCharge;info.batteryChargeCounter   = p->batteryChargeCounter;info.batteryTechnology      = p->batteryTechnology;
}void convertFromHealthInfo(const HealthInfo& info,struct android::BatteryProperties *p) {p->chargerAcOnline          = info.chargerAcOnline;p->chargerUsbOnline         = info.chargerUsbOnline;p->chargerWirelessOnline    = info.chargerWirelessOnline;p->maxChargingCurrent       = info.maxChargingCurrent;p->maxChargingVoltage       = info.maxChargingVoltage;p->batteryStatus            = static_cast<int>(info.batteryStatus);p->batteryHealth            = static_cast<int>(info.batteryHealth);p->batteryPresent           = info.batteryPresent;p->batteryLevel             = info.batteryLevel;p->batteryVoltage           = info.batteryVoltage;p->batteryTemperature       = info.batteryTemperature;p->batteryCurrent           = info.batteryCurrent;p->batteryCycleCount        = info.batteryCycleCount;p->batteryFullCharge        = info.batteryFullCharge;p->batteryChargeCounter     = info.batteryChargeCounter;p->batteryTechnology        = android::String8(info.batteryTechnology.c_str());
}

libhealthd 模块 Android.bp 编译主要使用了 healthd_board_default.cpp。

hardware/interfaces/health/1.0/default/libhealthd/Android.bp

cc_library_static {srcs: ["healthd_board_default.cpp"],name: "libhealthd.default",vendor_available: true,recovery_available: true,cflags: ["-Werror"],include_dirs: ["system/core/base/include"],header_libs: ["libhealthd_headers"],
}

healthd_board_init(…) 和 healthd_board_battery_update(…) 仅仅都是空实现。

hardware/interfaces/health/1.0/default/libhealthd/healthd_board_default.cpp

void healthd_board_init(struct healthd_config*)
{// use defaults
}int healthd_board_battery_update(struct android::BatteryProperties*)
{// return 0 to log periodic polled battery status to kernel logreturn 0;
}

android.hardware.health@1.0-service 实现了 HAL service。主要使用了 HealthService.cpp 源文件和,关联了 android.hardware.health@1.0-service.rc 文件。

Binderized 绑定式可以用两种方式来绑定服务,第一种通过 defaultPassthroughServiceImplementation 调用来注册服务,另外一种是直接调用 RegisterAsService 来注册服务。此处显然是通过第一种。

hardware/interfaces/health/1.0/default/HealthService.cpp

using android::hardware::health::V1_0::IHealth;
using android::hardware::defaultPassthroughServiceImplementation;int main() {return defaultPassthroughServiceImplementation<IHealth>();
}

rc 文件中,class 分类为 hal,user 用户是 system,group 组也是 system,capabilities 能力则是 WAKE_ALARM,表明可以闹钟唤醒。系统启动后 vendor.health-hal-1-0 Service 将会注册到系统。

hardware/interfaces/health/1.0/default/android.hardware.health@1.0-service.rc

service vendor.health-hal-1-0 /vendor/bin/hw/android.hardware.health@1.0-serviceclass haluser systemgroup systemcapabilities WAKE_ALARM

Android.bp 文件中编译了 android.hardware.health@1.0-convert 静态库,它主要使用了 convert.cpp 文件。

hardware/interfaces/health/1.0/default/Android.bp

cc_library_static {name: "android.hardware.health@1.0-convert",vendor_available: true,recovery_available: true,srcs: ["convert.cpp"],include_dirs: ["system/core/base/include",],header_libs: ["libhealthd_headers"],export_header_lib_headers: ["libhealthd_headers"],export_include_dirs: ["include"],shared_libs: ["libcutils","libhidlbase","libhidltransport","libutils","android.hardware.health@1.0",],}

这篇关于【Android 10 源码】healthd 模块 HAL 1.0 分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/952651

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

Python利用自带模块实现屏幕像素高效操作

《Python利用自带模块实现屏幕像素高效操作》这篇文章主要为大家详细介绍了Python如何利用自带模块实现屏幕像素高效操作,文中的示例代码讲解详,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、获取屏幕放缩比例2、获取屏幕指定坐标处像素颜色3、一个简单的使用案例4、总结1、获取屏幕放缩比例from

nginx-rtmp-module模块实现视频点播的示例代码

《nginx-rtmp-module模块实现视频点播的示例代码》本文主要介绍了nginx-rtmp-module模块实现视频点播,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录预置条件Nginx点播基本配置点播远程文件指定多个播放位置参考预置条件配置点播服务器 192.

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制