软件工程2021:第2次作业—— 谈谈鸿蒙操作系统
一、概述鸿蒙操作系统
·开发背景
华为鸿蒙系统(英文:HUAWEI Harmony OS)是一款基于微内核的面向全场景的分布式操作系统,于2019年8月9日在东莞华为开发者大会正式发布。
·需求
鸿蒙微内核是基于微内核的全场景分布式OS,可按需扩展,实现更广泛的系统安全,主要用于物联网,特点是低时延,甚至可到毫秒级乃至亚毫秒级。鸿蒙OS实现模块化耦合,对应不同设备可弹性部署,鸿蒙OS有三层架构,第一层是内核,第二层是基础服务,第三层是程序框架。可用于手机、平板、PC、汽车等各种不同的设备上。华为对于鸿蒙系统的定位完全不同于安卓系统,它不仅是一个手机或某一设备的单一系统,而是一个可将所有设备串联在一起的通用性系统,就是多个不同设备比如手机、智慧屏、平板电脑、车载电脑等等,都可使用鸿蒙系统。
·开发历史
2012年,华为开始规划自有操作系统“鸿蒙”。
2019年5月17日,由任教授领导的华为操作系统团队开发了自主产权操作系统——鸿蒙。
2019年8月9日,华为正式发布鸿蒙系统。同时余承东也表示,鸿蒙OS实行开源。
2020年12月16日,华为宣布正式推出鸿蒙OS的手机开发者Beta版。
2021年5月25日,华为技术有限公司对外宣布,定于6月2日晚8时举行线上发布会,正式公布可以覆盖手机等移动终端的鸿蒙操作系统。
2021年6月2日,华为正式发布了 HarmonyOS 2 操作系统。这也意味着“搭载 HarmonyOS(鸿蒙)的手机”已经变成面向市场的正式产品。同时,华为公布了 HarmonyOS 操作系统的 slogan—— 一生万物,万物归一。
·应用场景与发展趋势
鸿蒙操作系统可以应用于手机,平板,家电,智能手表,汽车等种场景中,鸿蒙操作系统展现出了他万物互联的他特性,正如他的宣传语:一生万物,万物归一。HarmonyOS和谷歌最新推出的Fuchsia OS一样,聚焦万物互联,定位不止是物联网操作系统,而是要把智能手机、PC系统都囊括其中。但是作为万物互联时代的操作系统,一定不能忽视的除了智能产品连接的稳定与高效,还有隐私保护。如果鸿蒙系统的生态完全建立,未来鸿蒙系统未必不能成为第三操作系统。
二、关于鸿蒙是否套壳的争议
·什么是创新
创新是指以现有的思维模式提出有别于常规或常人思路的见解为导向,利用现有的知识和物质,在特定的环境中,本着理想化需要或为满足社会需求,而改进或创造新的事物、方法、元素、路径、环境,并能获得一定有益效果的行为.但如今鸿蒙系统代码中也出现了adb,但是余承东在开发者大会上已经说明了,目前鸿蒙部分采用了开源框架,而且在目前应用生态还不完善的今天,贸然全面推进只能死的更快,兼容安卓是必然选择。
·代码复用与创新的关系
人民日报为华为鸿蒙系统回应了鸿蒙套壳安桌的事件,鸿蒙OS的部分代码基于ASOP不假,但大部分人把ASOP与安卓系统的关系搞混了。简单的说,华为使用ASOP的代码有两个原因。第一,华为有权使用ASOP的代码,谷歌管不着。ASOP是由谷歌联合34家手机终端和运营商企业共同发起的项目,全称是安卓开源项目。第二,鸿蒙OS使用ASOP的代码是基于现状的理智选择。据鸿蒙OS负责人王成录表示,安卓系统的全球开发者超过2000万,苹果iOS的开发者超过2400万。而鸿蒙OS的开发者目前才几百万,现阶段跟安卓和iOS“刚正面”是不现实的。
三、代码风格分析
好的代码风格1:
代码示例:
"···
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 uwTaskID)
{
UINTPTR uvIntSave;
LOS_TASK_CB *pstTaskCB;
UINT16 usTempStatus;
UINT32 uwErrRet = OS_ERROR;
if (uwTaskID > LOSCFG_BASE_CORE_TSK_LIMIT)
{
return LOS_ERRNO_TSK_ID_INVALID;
}
pstTaskCB = OS_TCB_FROM_TID(uwTaskID);
uvIntSave = LOS_IntLock();
usTempStatus = pstTaskCB->usTaskStatus;
if (OS_TASK_STATUS_UNUSED & usTempStatus)
{
uwErrRet = LOS_ERRNO_TSK_NOT_CREATED;
OS_GOTO_ERREND();
}
else if (!(OS_TASK_STATUS_SUSPEND & usTempStatus))
{
uwErrRet = LOS_ERRNO_TSK_NOT_SUSPENDED;
OS_GOTO_ERREND();
}
//以上为任务状态检查
pstTaskCB->usTaskStatus &= (~OS_TASK_STATUS_SUSPEND);//清除任务的suspend标志位置
if (!(OS_CHECK_TASK_BLOCK & pstTaskCB->usTaskStatus) )//若任务的还自在阻塞状态则变为就绪状态 ,并调用 LOS_Schedule()进行调度
{
pstTaskCB->usTaskStatus |= OS_TASK_STATUS_READY;
LOS_PriqueueEnqueue(&pstTaskCB->stPendList, pstTaskCB->usPriority);
if (g_bTaskScheduled)
{
(VOID)LOS_IntRestore(uvIntSave);
LOS_Schedule();
return LOS_OK;
}
g_stLosTask.pstNewTask = LOS_DL_LIST_ENTRY(LOS_PriqueueTop(), LOS_TASK_CB, stPendList); /*lint !e413*/
}
(VOID)LOS_IntRestore(uvIntSave);
return LOS_OK;
LOS_ERREND:
(VOID)LOS_IntRestore(uvIntSave);
return uwErrRet;
}
···"
这个函数的处理过程基本分为三步:
任务合法性(TaskId)及任务状态校验:判断任务序号以及任务当前状态是否确实为挂起。
改变任务状态:将任务的suspend状态位清掉
起用任务调度:如果任务被阻塞,则调起LOS_Schedule进行调度。
我们知道完整的LINUX内核是支持将任务指定在某个CPU上运行的,不过鸿蒙OS做为一个微内核的移动操作系统没有继承这些复杂的功能,直接做了减法,实现一个最简模型。
好的代码风格2:
代码示例:
"···
root@5e3abe332c5a:/home/docker/case_code_100/57# gcc -E main.c -o main.i
root@5e3abe332c5a:/home/docker/case_code_100/57# cat main.i
# 1 "main.c"
# 1 "<built-in>"
# 1 "<command-line>"
......
typedef __u_char u_char;
typedef __u_short u_short;
extern int printf (const char *__restrict __format, ...);
......
const int g_const = 10;
int g_init = 57;
int g_no_init;
static int s_exter_init = 58;
static int s_exter_no_init;
int main()
{
static int s_inter_init = 59;
static int s_inter_no_init;
int l_init = 60;
int l_no_init;
const int l_const = 11;
char *heap = (char *)malloc(100);
printf("hello harmonyos \n");
printf("全局常量 g_const:%p\n", &g_const);
printf("全局外部有初值 g_init:%p\n", &g_init);
printf("全局外部无初值 g_no_init:%p\n", &g_no_init);
printf("静态外部有初值 s_exter_init:%p\n", &s_exter_init);
printf("静态外静无初值 s_exter_no_init:%p\n", &s_exter_no_init);
printf("静态内部有初值 s_inter_init:%p\n", &s_inter_init);
printf("静态内部无初值 s_inter_no_init:%p\n", &s_inter_no_init);
printf("局部栈区有初值 l_init:%p\n", &l_init);
printf("局部栈区无初值 l_no_init:%p\n", &l_no_init);
printf("局部栈区常量 l_const:%p\n", &l_const);
printf("堆区地址 heap:%p\n", heap);
printf("代码区地址:%p\n", &main);
return 0;
}
···"
将所有的#define删除,并且展开所有的宏定义;
处理所有条件编译指令,如#if,#ifdef等;
处理#include预处理指令,将被包含的文件插入到该预处理指令的位置。该过程递归进行,及被包含的文件可能还包含其他文件。
删除所有的注释//和 /**/;
添加行号和文件标识,如# 1 “main.c”,以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时能够显示行号信息;
保留所有的#pragma编译器指令,因为编译器须要使用它们;
经过预编译后的.i文件不包含任何宏定义,因为所有的宏都已经被展开,并且包含的文件也已经被插入到.i文件中。所以当无法判断宏定义是否正确或头文件包含是否正确使,可以查看预编译后的文件来确定问题。
好的代码风格3:
代码示例:
"···
typedef struct {
#if !defined(LOSCFG_ARCH_FPU_DISABLE)
UINT64 D[FP_REGS_NUM]; /* D0-D31 */
UINT32 regFPSCR; /* FPSCR */
UINT32 regFPEXC; /* FPEXC */
#endif
UINT32 resved; /* It's stack 8 aligned */
UINT32 regPSR;
UINT32 R[GEN_REGS_NUM]; /* R0-R12 */
UINT32 SP; /* R13 */
UINT32 LR; /* R14 */
UINT32 PC; /* R15 */
} TaskContext;
结构很简单,目的更简单,就是用来保存寄存器现场的值的. 鸿蒙内核源码分析(总目录) 系列寄存器篇中已经说过了,到了汇编层就是寄存器在玩,当CPU工作在用户和系统模式下时寄存器是复用的,玩的是17个寄存器和内存地址,访问内存地址也是通过寄存器来玩.
哪17个? R0~R15和CPSR. 当调度(主动式)或者中断(被动式)发生时.将这17个寄存器压入任务的内核栈的过程叫保护案发现场.从任务栈中弹出依次填入寄存器的过程叫恢复案发现场.
从栈空间的具体哪个位置开始恢复呢? 答案是:stackPointer,任务控制块(LosTaskCB)的首个变量.对应到汇编层的就是SP寄存器.
而TaskContext(任务上下文)就是一定的顺序来保存和恢复这17个寄存器的.任务上下文在任务还没有开始执行的时候就已经保存在内核栈中了,只不过是一些默认的值,OsTaskStackInit干的就是这个默认的事. 而OsUserTaskStackInit是对用户栈的初始化,改变的是(CPSR)工作模式和SP寄存器.