1、准备材料

正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0

Keil µVision5 IDE(MDK-Arm

野火DAP仿真器

XCOM V2.6串口助手

2、学习目标

本文主要学习 FreeRTOS 中断管理的相关知识,包括系统硬件中断、 FreeRTOS 可管理的中断、中断屏蔽和一些其他注意事项等知识

3、前提知识

3.1、STM32 的硬件中断

根据STM32CubeMX教程4 EXTI 按键外部中断实验 “3、中断系统概述表” 小节内容可知

  1. STM32F4 系列有 10 个系统中断和82个可屏蔽的外部中断
  2. 嵌套向量中断控制器(NVIC)采用 4 位二进制数表示中断优先级,这 4 位二进制数表示的中断优先级又分为了抢占优先级和次优先级

当启用FreeRTOS之后,NVIC中断分组策略采用 4 位抢占优先级且不可修改,对于 STM32 的硬件优先级来说,优先级数字越小表示优先级越高,最高优先级为0,如下所示为 STM32 的中断列表

3.2、FreeRTOS 可管理的中断

对于 STM32 处理器所有的硬件中断来说,其中有些可以被 FreeRTOS 软件管理,而有些特别重要的中断则不能够被 FreeRTOS 软件所管理,这很好理解,比如系统的硬件 Reset 中断,如果 Reset 中断可以被FreeRTOS所管理,那么在系统死机时用户需要硬件复位,但 FreeRTOS 不能响应最终导致无法复位从而卡死

那么哪些硬件中断可以被 FreeRTOS 所管理呢?

这由 configLIBRARY_LOWEST_INTERRUPT_PRIORITY (中断的最低优先级数值) 和 configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY (FreeRTOS可管理的最高优先级) 两个参数决定,由于 NVIC 中断分组策略采用 4 位抢占优先级,因此中断最低优先级数值为 15 ,而 FreeRTOS 可管理的最高优先级默认设置为 5

当配置参数 configLIBRARY_LOWEST_INTERRUPT_PRIORITY = 15 , configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY = 5 时,则表示在 STM32 的所有硬件中断中优先级为 0~4 的中断 FreeRTOS 不可管理,而对于中断优先级为 5~15 的中断 FreeRTOS 可以管理,具体如下图所示

3.3、何为上下文?

在操作系统和嵌入式系统中,上下文(Context)是指程序执行过程中的当前状态,包括所有的寄存器值、程序计数器(PC)值以及其他与执行环境相关的状态信息。上下文记录了程序执行的位置和状态,使得程序可以在中断、任务切换或函数调用等场景下进行正确的恢复和继续执行

在 FreeRTOS 中,上下文通常与任务(Task)或中断处理函数相关联。当任务切换发生时,当前任务的上下文会被保存,然后将控制权转移到下一个任务,该任务的上下文会被恢复以便继续执行。类似地,当中断发生时,处理器会保存当前执行任务的上下文,并在中断处理完毕后,恢复之前任务的上下文以继续执行。

3.4、在 ISR 中使用 FreeRTOS API 函数

3.4.1、中断安全版本 API

通常需要在中断服务例程 (ISR) 中使用 FreeRTOS API 函数提供的功能,但许多 FreeRTOS API 函数执行的操作在 ISR 内无效,比如能够让任务进入阻塞状态的 API 函数,如果从 ISR 调用这些 API 函数,因为它不是从任务调用,所以没有有效的调用任务使其进入阻塞状态

因此对于一些 API 函数,FreeRTOS 提供了两种不同版本,一种版本供任务使用,另一种版本供 ISR 使用,在 ISR 中使用的函数名称后面带有 “FromISR” 的后缀,关于这种设计的优缺点,感兴趣的读者可以自行阅读 “Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf” 6.2小节内容

3.4.2、xHigherPriorityTaskWoken 参数

xHigherPriorityTaskWoken 参数是中断安全版本 API 中常见的一个参数,该参数用于通知应用程序编写者在退出 ISR 时是否应该进行上下文切换,因为在执行某个中断期间,在进入中断时和退出中断后多个任务的状态可能发生了改变,也即可能存在中断某个任务,但返回另外一个任务的情况发生

如果通过 FreeRTOS API 函数解锁的任务的优先级高于运行状态任务的优先级,则根据 FreeRTOS 调度策略,应切换到更高优先级的任务,但究竟何时实际切换到更高优先级的任务则取决于调用 API 函数的上下文,有以下两种情况

  1. 如果 API 函数是从任务中调用的,那么在抢占式调度策略下,在 API 函数退出之前,API 函数内会自动切换到更高优先级的任务
  2. 如果 API 函数是从 ISR 中调用的,那么在中断中不会自动切换到更高优先级的任务,但是可以设置一个变量来通知应用程序编写者应该执行上下文切换,也就是 FreeRTOS 中断安全版本的 API 函数中经常见到的 xHigherPriorityTaskWoken 参数

如果应执行上下文切换,则中断安全 API 函数会将 pxHigherPriorityTaskWoken 设置为 pdTRUE ,而且只能将其设置为 pdTRUE ,所以 pxHigherPriorityTaskWoken 指向的变量必须在第一次使用之前初始化为 pdFALSE

如果不通过上述的方法在退出 ISR 前执行上下文切换,那么最坏的情况就是本来应该在退出 ISR 时切换到某个高优先级的任务进行执行,但现在只能将其转为就绪状态,直到下一个滴答定时器到来进行上下文切换其才会转为运行状态

3.4.3、portYIELD_FROM_ISR() 和 portEND_SWITCHING_ISR() 宏

FreeRTOS教程2 任务管理 文章 "3.8、任务调度方法" 小节中,介绍了主动让位于另一项同等优先级任务的 API 函数 taskYIELD() ,它是一个可以在任务中调用来请求上下文切换的宏,portYIELD_FROM_ISR() 和 portEND_SWITCHING_ISR() 都是 taskYIELD() 的中断安全版本,他们两个的使用方式相同,并且执行相同的操作

3.4.4、简单总结

所以根据上面几个小节的叙述,如果我们希望在 ISR 中使用 FreeRTOS 提供的 API 函数,则应该使用这些 API 函数的中断安全版本,并且通过 xHigherPriorityTaskWoken 参数和 portYIELD_FROM_ISR() 宏在退出 ISR 之前进行可能的上下文切换,其可能的一种应用结构如下所示

/*一个可能的在中断中使用FreeRTOS API函数,然后进行上下文切换的例子*/
void An_Interrupt_Instance_Function(void)
{
//定义一个用于通知应用程序编程者是否应该进行上下文切换的变量,必须初始化为pdFALSE
BaseType_t highTaskWoken = pdFALSE;
//使用二值信号量API函数做演示
if(BinarySem_Handle != NULL)
{
//将中断安全版本API函数的pxHigherPriorityTaskWoken参数指向 highTaskWoken
xSemaphoreGiveFromISR(BinarySem_Handle, &highTaskWoken);
//根据highTaskWoken决定是否要进行上下文切换
portYIELD_FROM_ISR(highTaskWoken);
}
}

但是不是所有中断中都可以使用 FreeRTOS 提供的 API 函数,在 ISR 中使用 FreeRTOS API 函数总结如下所述

  1. 对于FreeRTOS可屏蔽的ISR中,如果要调用 FreeRTOS API 函数,则应该使用 FreeRTOS API 的中断安全版本函数(函数名末尾为FromISR或FROM_ISR),不可以使用任务级的API函数
  2. 对于FreeRTOS不可屏蔽的ISR中,不能够调用任何 FreeRTOS API函数

另外在 STM32CubeMX 软件 NVIC 配置界面中,如果在某个中断后面勾选了 “Uses FreeRTOS functions” 选项,根据上面的两点描述可知,只能在 FreeRTOS 可屏蔽的ISR中使用 FreeRTOS API 函数,所以该中断优先级可选范围会被强制到 15~5 之间,具体如下图所示

3.6、任务优先级和中断优先级

任务优先级为软件设置的一个属性,设置范围为1~(configMAX_PRIORITIES-1),数字越大优先级越高,在抢占式调度方式中高优先级的任务可以抢占低优先级的任务

中断优先级为硬件响应优先级,中断分组策略4位全用于抢占优先级的中断优先级数字设置范围为0-15,数字越小优先级越高

对于大多数的系统,其既会存在多个不同优先级的任务,同时也会存在多个不同优先级的中断,它们之间的执行顺序应该如下图所示

3.7、延迟中断处理

通常认为最佳实践是使 ISR 尽可能短,下面列出了可能的几条原因

  1. 即使任务被分配了非常高的优先级,它们也只有在硬件没有中断服务时才会运行
  2. ISR 会扰乱(添加“抖动”)任务的开始时间和执行时间
  3. 应用程序编写者需要考虑任务和 ISR 同时访问变量、外设和内存缓冲区等资源的后果,并防范这些资源
  4. 某些 FreeRTOS 端口允许中断嵌套,但中断嵌套会增加复杂性并降低可预测性,中断越短,嵌套的可能性就越小

什么时延迟中断处理?

中断服务程序必须记录中断原因,并清除中断。中断所需的任何其他处理通常可以在任务中执行,从而允许中断服务例程尽可能快地退出,这称为“延迟中断处理”,因为中断所需的处理从 ISR “延迟” 到任务。举个例子,比如在 ADC 周期采集中,当一轮采集完成之后,ADC 采集完成中断回调函数只负责将采集完成的值写入缓存区,然后由其他任务对缓存区中的数据进行更复杂处理

将中断处理推迟到任务还允许应用程序编写者相对于应用程序中的其他任务确定处理的优先级,并能够使用所有 FreeRTOS API 函数

如果中断处理被推迟的任务的优先级高于任何其他任务的优先级,则处理将立即执行,就像处理已在 ISR 本身中执行一样。这种场景如下图所示,其中任务 1 是普通应用程序任务,任务 2 是中断处理被推迟的任务

那么什么情况下需要进行延迟中断处理操作呢?

没有具体绝对的规则,在以下列出的几点情况下,将处理推迟到任务可能比较有用:

  1. 中断所需的处理并不简单。比如上面的举例,如果 ADC 仅仅需要采集值,那么在采集完成中断回调函数中将采集值写入缓存区即可,但是如果还需要对采集值进行复杂处理,那么最好推迟到任务中完成
  2. 中断处理是不确定的 - 这意味着事先不知道处理需要多长时间。

3.8、进行中断屏蔽

FreeRTOS 中为什么要屏蔽中断?

想象这样一个场景,当一个中等优先级的任务 TASK1 正在通过串口输出字符串 “Hello world!” 并且刚好输出到 ”Hello“ 时,另外一个高级优先级的任务 TASK2 突然抢占 TASK1 ,然后通过串口输出字符串 “lc_guo” ,当两个任务均执行完毕之后,你可能会在串口接受框中看到 ”Hellolc_guo world!“ 字符串

上述场景最终的结果与我们期望任务输出的字符串不符,在操作系统中称 TASK1 输出字符串的操作不是原子的,可能被打断的,因此在某些时候需要我们屏蔽掉中断以保证某些操作为原子的,可以连续执行完不被打断的,能够连续执行完且不被打断的程序段称其为临界段

那 FreeRTOS 中应该如何屏蔽中断?

在 FreeRTOS 中提供了三组宏函数方便用户在合适的位置屏蔽中断,在功能上屏蔽中断和定义临界代码段几乎是相同的,这几组函数通常成对使用

/**
* @brief 屏蔽FreeRTOS可管理的MCU中断
* @retval None
*/
void taskDISABLE_INTERRUPTS(void); /**
* @brief 解除屏蔽FreeRTOS可管理的MCU中断
* @retval None
*/
void taskENABLE_INTERRUPTS(void); /**
* @brief 开始临界代码段
* @retval None
*/
void taskENTER_CRITICAL(void); /**
* @brief 退出临界代码段
* @retval None
*/
void taskEXIT_CRITICAL(void); /**
* @brief 开始临界代码段的中断安全版本
* @retval 返回中断屏蔽状态uxSavedInterruptStatus,作为参数用于匹配的taskEXIT_CRITICAL_FROM_ISR()调用
*/
UBaseType_t taskENTER_CRITICAL_FROM_ISR(void); /**
* @brief 退出临界代码段的中断安全版本
* @param uxSavedInterruptStatus:进入临界代码段时返回的中断屏蔽状态,taskENTER_CRITICAL_FROM_ISR()返回的值
* @retval None
*/
void taskEXIT_CRITICAL_FROM_ISR(UBaseType_t uxSavedInterruptStatus);

4、实验一:中断各种特性测试

4.1、实验目的

  1. 启动 RTC 周期唤醒中断,在周期唤醒中通过串口 USART1 不断输出当前 RTC 时间
  2. 创建任务 TASK_TEST ,在该任务中通过串口 USART1 输出提示信息即可

4.2、CubeMX相关配置

首先读者应按照 “FreeRTOS教程1 基础知识” 章节配置一个可以正常编译通过的 FreeRTOS 空工程,然后在此空工程的基础上增加本实验所提出的要求

本实验需要初始化 USART1 作为输出信息渠道,具体配置步骤请阅读 “STM32CubeMX教程9 USART/UART 异步通信” ,如下图所示

本实验需要配置 RTC 周期唤醒中断,具体配置步骤和参数介绍读者可阅读 ”STM32CubeMX教程10 RTC 实时时钟 - 周期唤醒、闹钟A/B事件和备份寄存器“ 实验,此处不再赘述,这里参数、中断、时钟如下图所示

配置 Clock Configuration 和 Project Manager 两个页面,接下来直接单击 GENERATE CODE 按钮生成工程代码即可

4.3、添加其他必要代码

按照 “STM32CubeMX教程9 USART/UART 异步通信” 实验 “6、串口printf重定向”小节增加串口 printf 重定向代码,具体不再赘述

然后在 rtc.c 文件下方重新实现 RTC 的周期唤醒回调函数,在该函数体内获取当前 RTC 时间并通过 USART1 将时间输出到串口助手,具体如下所述

/*周期唤醒回调函数*/
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
if(HAL_RTC_GetTime(hrtc, &sTime, RTC_FORMAT_BIN) == HAL_OK)
{
HAL_RTC_GetDate(hrtc, &sDate, RTC_FORMAT_BIN);
char str[22];
sprintf(str,"RTC Time= %2d:%2d:%2d\r\n",sTime.Hours,sTime.Minutes,sTime.Seconds);
printf("%s", str);
}
}

最后在 freertos.c 中添加任务函数体内代码即可,这里无需实现具体功能,仅通过 USART1 串口输出信息告知用户该任务已执行即可,具体如下所述

/*测试任务函数*/
void TASK_TEST(void *argument)
{
/* USER CODE BEGIN TASK_TEST */
/* Infinite loop */
for(;;)
{
printf("TASK_TEST\r\n");
osDelay(pdMS_TO_TICKS(500));
}
/* USER CODE END TASK_TEST */
}

4.4、烧录验证

烧录程序,打开串口助手,由于周期唤醒中断每隔 1s 执行依次,TASK_TEST 任务大概每隔 500ms 执行有一次,因此通过串口助手输出信息可以发现,每输出两次 ”TASK_TEST“ 就会输出一次当前 RTC 时间,和预期一致,具体如下图所示

上述任务流程应该如下图所示

4.5、各种特性测试

4.5.1、中断如果处理时间较长呢?

修改 RTC 周期唤醒中断函数体,在函数体末尾增加 1s 延时函数 HAL_Delay(1000); 模拟中断处理时间较长的情况,注意由于 RTC 周期唤醒中断优先级为 1 ,因此不能调用任何 FreeRTOS API 函数,包括延时函数,任务 TASK_TEST 不做任何改动,将修改后的程序重新编译烧录,观察串口助手的输出信息,具体如下图所示

可以发现,只有最开始测试任务 TASK_TEST 执行了两次,一旦 RTC 周期唤醒被执行那么之后测试任务便得不到执行,为什么会这样?RTC 周期唤醒每隔 1s 执行一次,执行一次之后延时 1s 占用处理器,不断循环,导致处理器没有任何机会去处理 TASK_TEST

上述任务流程应该如下图所示

4.5.2、任务如果处理时间较长呢?

修改测试任务 TASK_TEST 函数体,将其可以进入阻塞状态的延时函数 osDelay() 修改为 HAL_Delay() 函数,同时将延时时间从 500ms 增加至 2s ,用于模拟任务一直运行的情况,RTC 周期唤醒中断函数与 “4.3、添加其他必要代码” 小节一致,具体如下所示

void TASK_TEST(void *argument)
{
/* USER CODE BEGIN TASK_TEST */
/* Infinite loop */
for(;;)
{
printf("TASK_TEST\r\n");
HAL_Delay(2000);
}
/* USER CODE END TASK_TEST */
}

将修改后的程序重新编译烧录,观察串口助手的输出信息,具体如下图所示,从图中可知 RTC 运行正常,本来应该连续运行 2s 的 TASK_TEST 并没有影响到每隔 1s 输出 RTC 时间的周期唤醒中断,说明中断抢占了 TASK_TEST 得到了执行,也就是说虽然我们希望 TASK_TEST 测试任务连续运行 2s ,但是其并没有真正连续运行 2s,其在大概 1s 的时候被中断了

4.5.3、进行中断屏蔽

上述 ”4.5.2、任务如果处理时间较长呢?“ 小节阐述了一个问题,有时候我们希望我们的 TASK_TEST 任务是原子式执行的,不希望被中断打断,所以我们需要在任务函数体内屏蔽中断,修改 TASK_TEST 任务函数体如下所示

void TASK_TEST(void *argument)
{
/* USER CODE BEGIN TASK_TEST */
/* Infinite loop */
for(;;)
{
//进入临界段
//taskDISABLE_INTERRUPTS();
taskENTER_CRITICAL();
printf("TASK_TEST\r\n");
HAL_Delay(2000);
//退出临界段
//taskENABLE_INTERRUPTS();
taskEXIT_CRITICAL();
}
/* USER CODE END TASK_TEST */
}

同时别忘记,FreeRTOS能够屏蔽中断优先级为5~15,因此我们还需要在 STM32CubeMX 软件的 NVIC 中将 RTC 周期唤醒中断优先级设置到该范围内,这里笔者将其设置为了 7 ,具体如下图所示

将修改后的程序重新编译烧录,观察串口助手的输出信息,具体如下图所示,可以发现 RTC 周期唤醒函数每隔 2s 才会得到一次输出,这说明 TASK_TEST 任务整个函数体得到了连续运行,成功屏蔽掉了 RTC 周期唤醒中断

5、注释详解

注释1:图片来源于 Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf

参考资料

STM32Cube高效开发教程(基础篇)

Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf

FreeRTOS教程3 中断管理的更多相关文章

  1. freeRTOS中文实用教程3--中断管理之中断嵌套

    1.前言 最新的 FreeRTOS 移植中允许中断嵌套.中断嵌套需要在 FreeRTOSConfig.h 中设置configKERNEL_INTERRUPT_PRIORITY 和configMAX_S ...

  2. freeRTOS中文实用教程4--资源管理互斥

    1.前言 访问一个被多任务共享,或是被任务与中断共享的资源时,需要采用”互斥”技术以保证数据在任何时候都保持一致性.这样做的目的是要确保任务从开始访问资源就具有排它性,直至这个资源又恢复到完整状态 F ...

  3. 【MCU】移植AT32库&FreeRTOS教程

    目录 前言 1. 移植AT库 1.1 移植内核相关文件 1.2 移植芯片型号相关文件 1.3 移植芯片外设驱动库 1.4 移植配置文件及中断回调函数文件 2. 移植FreeRTOS源码 2.1 获取 ...

  4. Spring Boot 2.x基础教程:事务管理入门

    什么是事务? 我们在开发企业应用时,通常业务人员的一个操作实际上是对数据库读写的多步操作的结合.由于数据操作在顺序执行的过程中,任何一步操作都有可能发生异常,异常会导致后续操作无法完成,此时由于业务逻 ...

  5. STM32中断管理函数

    CM3 内核支持256 个中断,其中包含了16 个内核中断和240 个外部中断,并且具有256 级的可编程中断设置.但STM32 并没有使用CM3 内核的全部东西,而是只用了它的一部分. STM32 ...

  6. STM32-NVIC中断管理实现[直接操作寄存器]

    源:stm32 NVIC中断管理实现[直接操作寄存器]     cortex-m3支持256个中端,其中包含了16个内核中断,240个外部中断.stm32只有84个中断,包括16个内核中断和68个可屏 ...

  7. Linux中断管理

    CPU和外设之间的交互,或CPU通过轮询机制查询,或外设通过中断机制主动上报. 对大部分外设中断比轮询效率高,但比如网卡驱动采取轮询比中断效率高. 这里重点关注ARM+Linux组合下中断管理,从底层 ...

  8. Linux中断管理 (1)Linux中断管理机制

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  9. Linux中断管理 (2)软中断和tasklet

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

  10. Linux中断管理 (3)workqueue工作队列

    目录: <Linux中断管理> <Linux中断管理 (1)Linux中断管理机制> <Linux中断管理 (2)软中断和tasklet> <Linux中断管 ...

随机推荐

  1. ChatGenTitle:使用百万arXiv论文信息在LLaMA模型上进行微调的论文题目生成模型

    ChatGenTitle:使用百万arXiv论文信息在LLaMA模型上进行微调的论文题目生成模型 相关信息 1.训练数据集在Cornell-University/arxiv,可以直接使用: 2.正式发 ...

  2. 基于.NET+FreeSql实现的仿掘金专栏前后端分离的CMS

    前言 今天分享一款基于.NET+FreeSql实现的仿掘金专栏前后端分离.支持Docker部署.集成了OAtuh2授权登录.QQ.Github.Gitee快速登录.简单实用的CMS:lin-cms-d ...

  3. 设计模式-1 单例模式 SingletonPattern

    23种设计模式 一.创建型 1,AbstractFactory(抽象工厂,对象模式) 2,Builder(建造者,对象模式) 3,Factory Method(工厂方法,类创模式) 4,Prototy ...

  4. Web 3.0 - 圈里的百科

    Web3.0只是由业内人员制造出来的概念词语,最常见的解释是,网站内的信息可以直接和其他网站相关信息进行交互,能通过第三方信息平台同时对多家网站的信息进行整合使用:用户在互联网上拥有自己的数据,并能在 ...

  5. Docker从认识到实践再到底层原理(七)|Docker存储卷

    前言 那么这里博主先安利一些干货满满的专栏了! 首先是博主的高质量博客的汇总,这个专栏里面的博客,都是博主最最用心写的一部分,干货满满,希望对大家有帮助. 高质量博客汇总 然后就是博主最近最花时间的一 ...

  6. Vulkan学习苦旅04:创建设备(逻辑设备VkDevice)

    设备是对物理设备的一种抽象,使我们更加方便地使用它.更准确地说,应该称其为"逻辑设备",但由于逻辑设备在Vulkan中极为常用,后面几乎所有的API都需要它作为第一个参数,因此在V ...

  7. 解密JavaChassis3:易扩展的多种注册中心支持

    本文分享自华为云社区<JavaChassis3技术解密:易扩展的多种注册中心支持>,作者:liubao68. Java Chassis 的早期版本依赖于 Service Center,提供 ...

  8. NC24623 Tree Decoration

    题目链接 题目 题目描述 Farmer John is decorating his Spring Equinox Tree (like a Christmas tree but popular ab ...

  9. 【OpenGL ES】绘制彩色三角形

    1 前言 ​ [OpenGL ES]绘制三角形 中介绍了绘制普通三角形的方法,本文将介绍绘制彩色三角形的方法. ​ 本文完整代码资源见→[OpenGL ES]绘制彩色三角形 ​ 项目目录如下: 2 案 ...

  10. 【Android】使用Binder实现进程间通讯简单案例

    1 前言 使用AIDL实现进程间通讯简单案例 和 使用AIDL实现进程间传递对象案例 中介绍了使用 AIDL 进行进程间通讯,文中提到在编写完 aidl 文件(如:IMessageManager.ai ...