车载 Android之 核心服务 - CarPropertyService 解析

Android汽车服务篇(三) CarPropertyService下篇 我们继续看一看看CarPropertyService, 这个服务也是很重要的, 绝大部分与车辆硬件功能相关联的属性,如空调, 车舱功能, 车辆传感器等都是通过CarPropertyService来读取或者设置的. CarPropertyManager 是CarPropertyService在客户端的代理, 通过CarPropertyManager提供的API,可以设置和获取车辆各个属性的状态. 阅读详情
AI摘要

本文详细介绍了CarPropertyManager和CarPropertyService在AndroidAutomotiveOS中的作用,展示了CarPropertyManager在不同版本的API中角色转变,以及它们与其他服务的关联。文章还涵盖了CarPropertyManager的方法、使用技巧、相关辅助类以及其背后的工作原理,包括与VehicleHAL的通信机制。

重要类的源码文件名及位置:

  • CarPropertyManager.java

packages/services/Car/car-lib/src/android/car/hardware/property/

  • CarPropertyService.java

packages/services/Car/service/src/com/android/car/

类的介绍:

CarPropertyManager:是CarPropertyService在客户端的代理,通过 CarPropertyManager中 提供的 API,可以设置和获取车辆各个属性的状态。但在实际使用时,CarPropertyManager 却未必是开发者使用最频繁的对象。尤其是在 Android9平台上开发时,当开发者想控制 空调相关的功能的时候,也许会使用 CarHvacManager;当想获取车辆信息的时候,也许会 使用 CarInfoManager;当想获取车辆传感器数据的时候,会使用 CarSensorManager。但其 实无论是 CarHvacManager还是 CarInfoManager或是 CarSensorManager,它们最后都会 通过 CarPropertyManager来获取设置属性,在服务端对应的都是 CarPropertyService。通 过ICarImpl中getCarService方法也可以很清楚地发现这一点,在Android 10中,谷歌官方直接推荐使用CarPropertyManager;

CarPropertyService:绝大部分与车辆硬件相关联的属性,如空调、车舱功能、车辆传感器等都是通过CarPropertyService来读取或者设置的。

类的使用:

CarPropertyManager:在安卓9中CarPropertyManger还是隐藏(hide)接口,所以不会在公开的SDK中出现,但是它十分重要。而在Android 10中,CarPropertyManger变成了车辆属性的主要API,并允许任何运行在Android Automotive OS上的应用进行调用。初看CarPropertyManger会觉得很熟悉,它的方法包括(但不限于)以下这些:

boolean registerListener(CarPropertyEventCallback callback, int prop, float rate)
boolean isPropertyAvailable(int propId, int area) 
boolean getBooleanProperty(int prop, int area)
float getFloatProperty(int prop, int area)
int getIntProperty(int prop, int area)
int[] getIntArrayProperty(int prop, int area)
<E> CarPropertyValue <E> getProperty(Class <E> clazz, int propId, int area) 
<E> CarPropertyValue <E> getProperty(int prop, int area)
<E> void setProperty()(Class <E> clazz, int propId, int area,E val) 
void setBooleanProperty(int prop, int area, boolean val)
void setFloatProperty (int prop int area, float val)
void setIntProperty (int prop, int area, int val) 

看到这些方法,就会发现和 CarHvacManager、CarVendorExtensionManager等服务中 的方法定 义 很 类 似。在 使 用 方 法 上 和 之 前 提 到 的 几 个 服 务 也 是 一 样 的。其 实,无 论 是 CarInfoManager,还是 CarSensorManager或 CarHvacManager,它们的功能都可以直接通 过 CarPropertyManager来完成。

1.CarPropertyManager的用法

熟悉了 CarHvacManager、CarVendorExtensionManager等几个相关服务的用法之后, 在 CarPropertyManager的使用上,相信读者对相关方法已经很了解了。这里再做一些简单 的补充。 关于属 性 的 获 取,在 CarPropertyManager 中 除 了 getProperty 方 法 之 外,还 有 像 getBooleanProperty、getIntProperty这样明确属性类型的获取方法。其实这些方法只是对 于getProperty方法的封装,以getIntProperty为例,它的实现是这样的:

看上去在明确知道属性类型的情况下,getBooleanProperty、getIntProperty等方法在 使用上更加简洁。但是在这里,依然推荐开发者们使用getProperty来获取相应的属性值, 因为getProperty方法返回的是 CarPropertyValue对象,其不仅包含属性值,还包含属性的 状态,而getIntProperty等方法在属性不可用的情况下,返回的是默认值,这在有的时候会 导致读取的数据不正确。 下面以 NIGHT_MODE(昼夜模式)属性为例,说明使用getProperty方法的好处。

从这段源码中,可以很直观地看到使用getProperty方法,与getBooleanProperty方法 获取昼夜状态相比,可以更准确地判断当前属性的状态,并在属性不支持或不可用时,使用 更合理的处理逻辑。因此,虽然 getProperty方法会增加源码的数量,但在大部分情况下, 依然推荐大家使用该方式获取属性。

        在注册 监 听 属 性 变 化 方 面,CarPropertyManager 提 供 更 细 颗 粒 度 的 监 听 方 法, registerListener① 方法可以监听单个属性值的变化,开发者可以通过在注册监听器时传入 属性ID指定监听器所对应的属性。同时,可以指定数据上报的频率,与5.2节介绍的一样, 该频率与属性类型和其他监听器的频率有关,并不能保证数据会以传入的期望频率进行上 报。监听属性的方式,可参考以下源码:

CarPropertyManager.CarPropertyEventListener mCarPropertyEventListener = new CarPropertyManager.CarPropertyEventListener() {
        @Override
        public void onChangeEvent(CarPropertyValue value) {

        }

        @Override
        public void onErrorEvent(int propId, int zone) {
        }
    };

    mCarPropertyManager.registerListener(mCarPropertyEventListener,VehiclePropertyIds.PERF_VEHICLE_SPEED,/ * rate=* / 5);

2.CarPropertyManager的相关类

除了和 CarPropertyManager相关的这几个 Manager之外,在之前的例子中,还出现了 如 VehiclePropertyIds、CarPropertyValue、CarPropertyConfig等相关的辅助类,由于种类 繁多,有必要在这里梳理一下各个辅助类的作用。

(1)VehiclePropertyIds,CarPropertyManager都是通过属性ID来对应具体的功能的, 不同功能对应不同的ID,VehiclePropertyIds中列出了所有在 VehicleHAL 中定义的功能 属性,是AndroidAutomotiveOS官方定义的属性集合。

(2)VehicleAreaDoor,许多功能点都分多个区域,在设置、获取相应属性时,需要传入区域 参数,VehicleAreaDoor定义了与车门相关的区域值,在使用与车门相关的属性时配套使用。

(3)VehicleAreaMirror,与 VehicleAreaDoor类似,多区域定义,后视镜区域值。

(4)VehicleAreaSeat,多区域定义,座位区域值。

(5)VehicleAreaWheel,多区域定义,车胎区域值。

(6)VehicleAreaWindow,多区域定义,车窗区域值。

(7)VehicleAreaType,区域类型是用以区分一个属性所对应的位置的。对于非多区域 属性,往往使用 VEHICLE_AREA_TYPE_GLOBAL 作为其区域ID。每个区域属性都必 须使用预定义的区域类型,即车门、车窗、座椅、轮胎、后视镜中的一个。每种区域类型都有 一组在区域类型的枚举中定义的位标记,也就是前文中使用的像SEAT_ROW_1_LEFT 这 53 第 5 章 CarPropertyService———车辆属性服务 样具体的区域值。

(8)VehicleLightState,灯光状态,开、关、日间。

(9)VehicleLightSwitch,灯光切换,开、关、日间、自动。

(10)VehicleOilLevel,油量状态。

以上这些辅助类中,都定义了相关的静态变量,同时,这些值都与 VehicleHAL 的相关 定义一一对应,在 CarAPI中将其再次定义是为了方便上层应用使用。

        除了以上 几 个 定 义 静 态 变 量 的 辅 助 类 以 外,还 会 经 常 用 到 CarPropertyConfig 和 CarPropertyValue这两个模板类。CarPropertyConfig和 CarPropertyValue非常有用,通 过前者能获取到一个属性的静态参数,如取值范围、类型、支持的区域等;通过后者能获取 一个属性的值和状态。

        这里举两个简单的例子。

        (1)通过 CarPropertyManager获取当前车辆支持的属性(注意,需要拥有对应属性的 权限才能获取)。

CarPropertyConfig对象的成员变量如表5-4所示。

开发者可以通过以上成员变量对应的 get方法获取具体的值。对于区域属性来说, CarPropertyConfig中还封装了额外的方法方便开发者获取特定区域的取值,AreaConfig类 的getMinValue、getMaxValue方法可以返回某一属性特定区域的取值范围。

        (2)通过 CarPropertyManager获取当前的车速。

        CarPropertyValue对象的成员变量如表5-5所示。

虽然看上去很简单,但实际使用过程中会涉及较多的判断,开发者可以进一步对属性进 行封装管理,并总结一些有用的实践。CarPropertyConfig和 CarPropertyValue这两个类 同样 和 VehicleHAL 中 的 定 义 的 结 构 体 相 关 联,CarService 会 将 从 HAL 层 获 取 的 VehiclePropConfig和 VehiclePropValue① 分别转换为CarPropertyConfig和CarPropertyValue。

3.进一步了解 CarPropertyManager 

通过前文的介绍,读者应该已经了解了 CarPropertyManager的重要性。因此有必要进 一步了解 CarPropertyManager背后的原理,更全面地掌握它。 熟悉 Android的读者应该知道,在 Android中往往一个 Manager会对应一个Service,例如 ActivityManager对应着 ActivityManagerService;PackageManager对应着PackageManagerService。 它 们 运 行 在 不 同 的 进 程 中,通 过 Binder 这 一 IPC 机 制 进 行 通 信。 同 样 地,与 CarPropertyManager相对应的是 CarPropertyService这一服务。 同时,读者如果对车辆电子电器的架构有一定了解,那么应该知道,各个具体的功能往 往有对应的电子控制单元(ElectronicControlUnit,ECU)进行控制。例如,控制座椅位置 的命令,最终需要发送到负责控制座椅的 ECU 中才能使座椅移动。 因此,一次控制命令的调用过程大致如图5-1所示。

上层的应用通过 CarAPI提供的接口进行设置,最终通过车辆总线将命令发送给对应 的 ECU,ECU 返 回 结 果 给 CarService,并 通 过 回 调 通 知 相 关 应 用。 这 一 过 程 中 的 ① VehiclePropConfig和 VehiclePropValue定义在/hardware/interfaces/automotive/vehicle/2.0/types.hal文件中。 55 第 5 章 CarPropertyService———车辆属性服务 VehicleHAL非 常 重 要,它 指 的 是 制 造 商 实 现 的 硬 件 抽 象 层 服 务,实 现 了 Android AutomotiveOS定义的相关硬件抽象层接口。由于不同汽车制造商与ECU 的通信方式、标 准、数据格式都不尽相同,所以需要对其进行抽象,统一接口,而具体逻辑则由汽车制造商自 己实现。关于 VehicleHAL的具体内容,会在后面的章节再展开。 下面通过源码,进一步了解 CarPropertyManager中的具体实现,建议读者在阅读的同 时打开源码文件进行查看。 以下是 CarPropertyManager的构造函数实现:

在 CarPropertyManager的构造函数中,获得了ICarProperty的远程对象,通过该远程 对象就可以调用 CarPropertyService。关于 Binder机制的具体实现及 AIDL 的调用过程, 在此就不做展开了①。 再来看看 CarPropertyManager的setProperty的调用过程:

通过 mService对象,调用 CarPropertyService中对应的方法:

这里出现了一个新的对象 mHal,它是 PropertyHalService对象的实例。

接着调用 VehicleHal的set方法,虽然对象命名叫 VehicleHal,但该 VehicleHal对象 依然是在CarService进程中定义并创建的对象。还没有看到对 HAL层的Binder调用。接着往下:

VehicleHal中的set方法只是进一步调用了 HalClient对象的setValue方法。

在 HalClient的setValue方法中,终于发现这个 mVehicle对象是一个 HIDL调用的远 程对象,通过它,实际上调用的是抽象层 VehicleHal的实现。这里涉及了 Android8.0引入 的 HIDL机制,不详细展开了①。随着 HIDL 机制的引入,VehicleHal运行在独立的进程 中,由设备制造商或汽车制造商进行实现。

        以上就是一次完整的设置属性值的调用过程,可以看到设置命令最终将发送给制造商 实现的 VehicleHal进程,并由 VehicleHal最终完成该次调用。

        再来追踪 VehicleHal中的事件的传递过程。

        通过设置的流程,可以发现发起 HIDL调用的远程对象是被 HalClient对象所持有的, 与 VehicleHal的 直 接 交 互 是 在 HalClient 中 完 成 的。 因 此 事 件 的 向 上 传 递 也 是 从 HalClient开始的。在收到上报的事件之前,上层应用首先要注册相应的监听方法。

        当应用调用 CarPropertyManager的registerListener方法时,其会调用 CarPropertyService 的registerListener方法。

上述源码进一步 调 用 PropertyHalService的 subscribeProperty 方 法,中 间 会 再 经 过 VehicleHal.java的调用,最后调用 HalClient中的subscribe方法,调用的路径和设置的流 程是一样的。在此省略一些中间过程,直接来看 HalClient的subscribe方法的实现:

  这里将 mInternalCallback对象传递给了 Hal层。mInternalCallback对象的实例是继 承了IVehicleCallback.Stub的 HIDL桩对象,实现如下:              

通过IVehicleCallback,制造商实现的 VehicleHal进程就可以将事件传递给 CarService 进程了。有兴趣的读者可以进一步追踪当IVehicleCallback的onPropertyEvent方法被调 用后,事件又是如何传递给应用注册的监听器的。

        上文出现了一些新的对象,为了便于理解,整理上述类之间的关系,见图5-2。

在 CarService中虽然有 VehicleHal类,但该类并不直接调用 HIDL 方法,而是进一步 调 用 HalClient 封 装 的 方 法,HalClient 才 是 真 正 与 HAL 层 打 交 道 的 类。 同 时, PropertyHalService处理与 CarPropertyService相关的业务逻辑,在后面的内容中,还会接触 InputHalService、PowerHalService,VehicleHal会将不同的事件分发给对应的类进行处理。 总体来说,通过 CarPropertyService的层层调用,最后通过IVehicle与实现了车辆硬件 抽象层的进程通信。VehicleHal进程由各个厂家进行实现,再进一步将消息发送给关联的 ECU,实现控制功能。

车载 Android 核心服务:深入解析 CarPropertyService 与 VehicleHAL 的通信机制 本文深入解析车载Android系统中CarPropertyService与VehicleHAL的核心通信机制。CarPropertyService作为应用层与硬件层的翻译官,通过统一的属性接口屏蔽硬件差异,而VehicleHAL则负责与车辆硬件直接交互。文章详细介绍了属性订阅、数据流传输和回调机制等关键技术,帮助开发者高效开发车载应用。 阅读详情

相关推荐

Android 车载应用开发指南(4)- CarService 核心服务与通信机制剖析

本文深入剖析了Android车载应用开发中的CarService核心服务与通信机制。作为车载Android的中枢神经系统,CarService协调硬件与软件的交互,涵盖电源管理、音频路由、车辆数据标准化等关键功能。文章详细解析了Binder跨进程通信、Vehicle HAL对接技术,并提供了开发实战技巧与性能优化建议,帮助开发者高效构建安全可靠的车载应用。

weixin_30753873的博客 440

从车窗升降一探 Android 车机的重要 API:车辆属性 CarProperty

一文了解 Android 车机如何处理中控的旋钮输入从实体按键看 Android 车机的自定义事件机制深度入门 Android 车机核心 CarService 的构成和链路本篇文章我们聚焦 Android 车机上最重要、最常用的接口:即车辆属性。并结合车窗升降这种典型的场景来探究它的完整链路。App 先通过 Car lib 拿到CarService的Car实例,CarService 会初始化所有 Car 相关的实现,比如其中车辆属性的化,会初始化和等。

allisonchen的专栏 3217

Android Automotive OS开发实战:CarService核心服务与API调用详解(附避坑指南)

本文深入解析Android Automotive OS中CarService的核心服务架构与实战API调用。详细探讨了CarPropertyService、CarAudioService和CarPowerManagementService等关键模块,提供了从连接到调用、事件监听到异常处理的完整代码示例与避坑指南,帮助开发者高效构建稳定、安全的车载应用。

gg901的博客 513

Android Car&Source 02 -- Vehicle Property相关管理

目录 1.从UI层开始看property 最后.学习的博客如下 Android Automotive 的硬件抽象层 (HAL) 为 Android 框架提供了一致的接口(无需考虑物理传输层)。此车载 HAL 是开发 Android Automotive 实现的接口。 系统集成商可以将特定于功能的平台 HAL 接口(如 HVAC)与特定于技术的网络接口(如 CAN 总线)连接,以实现车载 HAL 模块。通过车载HAL可以实现车辆属性的接口。 1.HVAC服务 最后.学习的博客如下...

来个芒果1007 2565

车载Android开发核心:CarPropertyService架构、原理与实战调试指南

在Android Automotive OS (AAOS) 车载系统中,车辆硬件抽象层(VHAL)是实现软硬件解耦与标准化的关键设计。其核心原理是通过定义一套统一的车辆属性数据模型,将来自不同ECU(电子控制单元)的异构信号(如车速、车门状态)转换为Android框架层能够识别和处理的标准化接口。这一设计的技术价值在于,它为上层应用提供了稳定、安全的车辆数据访问通道,避免了应用直接与复杂的总线协议(如CAN、LIN)耦合,极大地提升了系统稳定性与开发效率。在应用场景上,无论是车载信息娱乐系统(IVI)的功能

weixin_29186249的博客 365

深入解析Android VehicleHAL与CarPropertyService的交互机制

本文深入解析了Android车载系统中VehicleHAL与CarPropertyService的交互机制,详细介绍了它们的角色定位、初始化流程、属性订阅机制以及属性更新流程。通过实战案例展示了如何新增自定义属性,并提供了调试技巧与常见问题解决方案,帮助开发者更好地理解和应用Android车载系统开发。

weixin_29200741的博客 600

【Android R】车载 Android 核心服务 - CarPropertyService 解析

对比开发车载Android和手机Android应用,最大的区别应该就是许多车载应用需要考虑汽车整体的运行状态,例如,控制车载空调或车速达到一定的阈值时,出于安全的...

linkwj的博客 5134

车载Android CarPropertyService:架构、原理与实战指南

在Android Automotive OS (AAOS) 中,系统服务扮演着连接应用与底层硬件的关键角色,其核心原理在于通过硬件抽象层(HAL)实现标准化的数据访问与控制。这一设计为上层应用提供了统一接口,极大提升了开发效率与系统可维护性,其技术价值在于确保了车载功能的安全性、实时性与稳定性。典型的应用场景包括智能座舱的信息娱乐系统、车身控制及驾驶状态监控等。本文将聚焦于实现这一机制的核心服务——CarPropertyService,它作为车辆属性的“交通警察”,管理着所有传感器与ECU数据的标准化接入与

weixin_29169505的博客 226

【Android R】车载 Android 核心服务 CarPropertyService

对比开发车载Android和手机Android应用,最大的区别应该就是许多车载应用需要考虑汽车整体的运行状态,例如,控制车载空调或车速达到一定的阈值时,出于安全的考虑多媒体应用要主动保持静音;汽车处于行驶状态下,OTA应用要保持静默等等。APP如何从Framework层获取车辆状态的数据,而Framework层又是从哪里获取到数据,它们的运行机制是怎样的,就是本篇要解释的问题了。1.【Android R】车载 Android 核心服务 - CarService 解析。

xiaokangss的博客 972

CarPropertyService调试实战:属性订阅、权限控制与异常处理全解析

本文深入解析Android车载开发中CarPropertyService的核心调试技巧,涵盖属性订阅机制、权限控制模型与异常处理实战。通过分析VehicleHAL层实现细节和常见问题根源,提供属性订阅失败、权限校验异常等解决方案,帮助开发者提升车载系统的稳定性和可靠性。

assembly8low的博客 672

从零到一:实战Android Automotive车辆属性扩展与CarPropertyService深度解析

本文深入解析Android Automotive车辆属性扩展与CarPropertyService的开发实践,从HAL层属性定义到应用层实现,详细介绍了自定义车辆属性的全流程。通过实战案例演示如何扩展车辆属性系统,并深度剖析CarPropertyService的架构设计与访问机制,帮助开发者快速掌握Android Automotive开发核心技术。

weixin_29204121的博客 209

车载 Android之 核心服务 - CarPropertyService 的VehicleHAL

本文是车载Android之核心服务-CarPropertyService的第二篇,了解一下CarPropertyService的VehicleHAL, 第一篇在车载 Android之 核心服务 - CarPropertyService 解析-优快云博客,有兴趣的 朋友可以去看下。本节介绍 AndroidAutomotiveOS中对于 VehicleHAL,即车辆硬件抽象层的定义。前文中多次提到了 VehicleHAL,当提起 VehicleHAL的时候,它可能包含以下含义。

github_37217206的博客 3469

深入解析AAOS核心服务:CarService架构与实现原理

本文深入解析了Android Automotive OS (AAOS) 的核心服务CarService的架构与实现原理。作为连接车辆硬件与上层应用的关键桥梁,CarService通过模块化设计管理音频、电源、属性等核心功能,并借助Vehicle HAL抽象硬件差异。文章详细阐述了其启动流程、与HAL的交互机制,以及开发者如何通过Car API安全地访问和控制车辆功能,是进行AAOS应用开发的重要指南。

p5l2m9n4o6q的博客 462

Android 13车载电源管理服务CPMS启动流程深度解析

整车电源管理是车载系统的关键基础设施,其核心在于通过电源状态机对整车上电、休眠、下电等场景进行统一仲裁。Android 13中的CarPowerManagementService(CPMS)作为SystemServer内的重要系统服务,负责对接CarPropertyService与VehicleHal,在启动阶段完成服务注册、属性订阅与策略加载。理解CPMS的启动流程,有助于解决ACC OFF延时、状态机初始化异常、状态竞态等工程难题。本文从SystemServer拉起、CarServiceHelperSe

weixin_34007886的博客 312

Android 车载开发深度解析:CarPropertyManager 核心机制与实践指南

摘要: Android Automotive OS中,CarPropertyManager作为车载信息娱乐系统的核心组件,连接应用层与车辆硬件(如车速、油量等),其架构基于分层设计(App→CarAPI→VHAL→ECU),采用发布-订阅模式实现高效数据通信。通过HIDL/AIDL跨进程交互及共享内存优化,延迟可降至2ms以下。安全机制包括分级权限控制(VISIBLE/PROTECTED/SYSTEM_RESTRICTED)和HMAC防篡改。开发时需注意监听器生命周期管理、事件合并降负载及低功耗适配。

郑伟强dev的专栏 344

Android 车联网——CarManager管理器(四)

源码位置:/packages/services/Car/car-lib/src/android/car/CarInfoManager.javaCarInfoManager 用于管理车辆信息服务,其中的 API 不多,而且从方法的名称也很容易了解其具体的功能。属性描述权限系统权限车速CAR_SPEED否转速是里程数是油量CAR_ENERGY否驻车制动否档位否白天黑夜否车外环境温度否点火状态否轮距CAR_SPEED否ABS状态是牵引力控制是。

小旭的专栏 1976

深入解析 Android Automotive (AAOS) 启动流程与 CarService 核心机制(基于 Android 16 最新源码视角)

在Android Automotive OS(AAOS)中,CarService是连接上层应用(Cars App/System UI)和底层车载硬件抽象层(Vehicle HAL,简称VHAL)的核心纽带。

龚礼鹏的博客 516

fpga在线升级 linux_仅5000行Verilog代码、可在FPGA上跑轻量级Linux系统的RISC-V内核

本文发布于www.hackster.io,由东京理工大学的计算机学院开发,专用于教学与加速用(苏老师也一直认为这是RISC-V当前的主要方向)。目前市场上开源的RISC-V内核已经很多,但很少有公开的RISC-V计算系统是非常轻型且能跑Linux系统的。这一款RISC-V内核就可以运行在FPGA上,用Verilog编写的,需要很少硬件的资源就能跑起来,所以可以运行在一个低成本的FPGA上。来看一下...

weixin_34083807的博客 1866
上一篇: git clone https的项目出现项目太大无法clone的解决办法
下一篇: 车载 Android之 核心服务 - CarPropertyService 的VehicleHAL
zmybiealex
博客等级 码龄10年 48粉丝 46原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值