王 千,麥秀青,陸 平
(中國(guó)電子科技集團(tuán)公司第三十二研究所基礎(chǔ)軟件部,上海 201808)
近年來,我國(guó)與歐美一些國(guó)家之間以操作系統(tǒng)為核心的技術(shù)生態(tài)體系競(jìng)爭(zhēng)日益顯現(xiàn)[1-2]。Android 從移動(dòng)設(shè)備、穿戴設(shè)備、智能家居全方位打造的生態(tài)圈已經(jīng)相當(dāng)成熟[3],在我國(guó)的移動(dòng)終端市場(chǎng)占有極大的比例,甚至一些安全要求高的專用領(lǐng)域也在使用Android系統(tǒng),如北斗導(dǎo)航、警用搜救、軍用作戰(zhàn)等[4-5],這無疑在安全性、知識(shí)產(chǎn)權(quán)等多方面都存在巨大風(fēng)險(xiǎn)[6]。在此背景下,銀河銳華終端操作系統(tǒng)(YROS)就成為了很好的國(guó)產(chǎn)化替代方案。
銀河銳華終端操作系統(tǒng)是國(guó)防科技大學(xué)與中國(guó)電子科技集團(tuán)第三十二研究所自主研發(fā)的智能移動(dòng)終端操作系統(tǒng),使用Linux+HTML5 的實(shí)現(xiàn)方案,適用于智能手持、平板、可穿戴等移動(dòng)終端設(shè)備[7]。
銀河銳華終端操作系統(tǒng)應(yīng)用是使用HTML5+JavaScript+CSS 的模式開發(fā)的,這種開發(fā)模式具有界面適配靈活、可移植性強(qiáng)的特點(diǎn)[8-10],但是用于開發(fā)移動(dòng)終端應(yīng)用也存在較多問題,諸如運(yùn)行效率較低、可調(diào)試性差、對(duì)底層的操控性差等[11]。此外,由于一些專用領(lǐng)域已在使用基于Android開發(fā)的軟件,這些Android應(yīng)用多為Java+Native 模式開發(fā),即有很多對(duì)性能要求較高的核心功能是通過JNI 的方式在Native 層實(shí)現(xiàn)的[12-13],而將這部分代碼通過JavaScript 的方式移植到銀河銳華終端操作系統(tǒng)上往往是不現(xiàn)實(shí)的。若能夠提供一種切實(shí)可行的移植方案,則能加快國(guó)產(chǎn)化移動(dòng)操作系統(tǒng)的普及以及生態(tài)的建立。
綜上所述,在銀河銳華終端操作系統(tǒng)上實(shí)現(xiàn)應(yīng)用的C++/JavaScrip 混合開發(fā)是非常有必要的?;诖?,本文進(jìn)行基于銀河銳華終端操作系統(tǒng)的C++適配層研究,通過對(duì)系統(tǒng)框架層與系統(tǒng)接口進(jìn)行擴(kuò)展,實(shí)現(xiàn)C++與JavaScript的交互調(diào)用。
基于銀河銳華終端操作系統(tǒng)的C++適配層通過插件的方式,動(dòng)態(tài)加載按照特定方式實(shí)現(xiàn)的功能性C++插件庫(kù)文件,并以系統(tǒng)接口的形式實(shí)現(xiàn)JavaScript 與C++插件庫(kù)之間的交互調(diào)用。
在銀河銳華終端操作系統(tǒng)的框架層拓展插件庫(kù)模塊管理器與插件庫(kù)對(duì)象管理器。其中插件庫(kù)模塊管理器對(duì)所有的C++插件庫(kù)以模塊的形式進(jìn)行動(dòng)態(tài)管理;而插件庫(kù)對(duì)象管理器則隸屬于每一個(gè)應(yīng)用進(jìn)程,用于JavaScript對(duì)C++插件庫(kù)的具體調(diào)用。
C++適配層的架構(gòu)圖如圖1所示。
圖1 C++適配層架構(gòu)圖
C++插件庫(kù)需要按照特定的方式進(jìn)行開發(fā)。
C++適配層提供了一個(gè)插件庫(kù)的基類,C++插件庫(kù)應(yīng)繼承該基類根據(jù)具體功能需求實(shí)現(xiàn)一個(gè)橋接類,該橋接類將作為C++插件庫(kù)接收J(rèn)avaScrip 調(diào)用指令的入口。橋接類的主要功能包括插件的初始化與插件的方法調(diào)用。繼承插件庫(kù)基類實(shí)現(xiàn)橋接類的關(guān)鍵在于調(diào)用方法的重載實(shí)現(xiàn),調(diào)用方法接收J(rèn)avaScrip 傳遞的操作指令以及指令參數(shù),根據(jù)指令進(jìn)行相應(yīng)操作決策,并將執(zhí)行的最終結(jié)果返回到JavaScrip。由于指令參數(shù)在數(shù)量以及類型上均存在不確定性,因此在C++插件庫(kù)基類聲明了一個(gè)字符串作為指令參數(shù),應(yīng)用開發(fā)時(shí),可以根據(jù)實(shí)際情況在傳入時(shí)對(duì)參數(shù)列表進(jìn)行編碼,并在C++適配層中進(jìn)行相應(yīng)的解碼工作,以保證參數(shù)的正確傳遞。
C++插件庫(kù)需要按照約定聲明一個(gè)全局插件實(shí)例,該實(shí)例將在C++插件庫(kù)加載時(shí)被初始化,該實(shí)例的指針將向外提供,用于對(duì)插件庫(kù)中的方法進(jìn)行調(diào)用。
此外,C++適配層還為C++插件庫(kù)提供一個(gè)接口用于其對(duì)JavaScript的回調(diào)。在該回調(diào)方法中,將通過回調(diào)ID惟一標(biāo)示每一次回調(diào)過程。
插件庫(kù)模塊管理器將每個(gè)C++插件庫(kù)作為一個(gè)模塊進(jìn)行動(dòng)態(tài)管理,插件模塊中保存有系統(tǒng)調(diào)用該C++插件庫(kù)時(shí)所需的信息,具體如下:
插件庫(kù)句柄:用于保存C++插件庫(kù)的句柄。
插件庫(kù)橋接類實(shí)例指針:用于保存橋接類的實(shí)例。
回調(diào)方法指針:用于保存C++插件庫(kù)發(fā)起對(duì)JavaScript調(diào)用的入口方法。
注冊(cè)回調(diào)指針方法:用于系統(tǒng)向插件庫(kù)中進(jìn)行回調(diào)方法的注冊(cè)。
刪除回調(diào)指針方法:用于系統(tǒng)移出插件庫(kù)中的回調(diào)方法。
調(diào)用方法:用于系統(tǒng)發(fā)起對(duì)C++插件庫(kù)的調(diào)用。
每當(dāng)應(yīng)用使用JavaScript 發(fā)起加載一個(gè)C++插件庫(kù)的請(qǐng)求時(shí),系統(tǒng)為該插件庫(kù)動(dòng)態(tài)生成插件模塊進(jìn)行保存;當(dāng)JavaScript 進(jìn)行C++插件庫(kù)功能調(diào)用時(shí),插件庫(kù)模塊管理器將通過C++插件庫(kù)的句柄進(jìn)行方法調(diào)用;若C++插件庫(kù)需要進(jìn)行回調(diào),需要JavaScript 首先向插件庫(kù)中注冊(cè)回調(diào)方法指針進(jìn)行保存,插件庫(kù)通過插件模塊中保存的回調(diào)方法指針進(jìn)行回調(diào)。
每個(gè)應(yīng)用將獨(dú)立擁有一個(gè)專屬于自己的插件庫(kù)對(duì)象管理器,插件庫(kù)對(duì)象管理器向應(yīng)用提供用于與C++插件庫(kù)進(jìn)行交互的系統(tǒng)接口,這些接口主要包括:
C++插件庫(kù)初始化接口(init):用于動(dòng)態(tài)加載指定C++插件庫(kù),創(chuàng)建該庫(kù)的模塊實(shí)例;
C++插件庫(kù)調(diào)用接口(exec):用于調(diào)用C++插件庫(kù)中的指定功能;
注冊(cè)回調(diào)方法接口(addListener):用于注冊(cè)接收并處理C++插件庫(kù)回調(diào)事件的方法;
移除回調(diào)方法接口(removeListener):用于停止接收C++插件庫(kù)中的回調(diào)事件;
檢測(cè)庫(kù)是否加載接口(isloadedlibrary):用于檢測(cè)某指定C++插件庫(kù)是否被成功加載;
卸載C++插件庫(kù)接口(unloadlibrary):用于卸載指定的C++插件庫(kù)。
C++適配層通過拓展系統(tǒng)JavaScript 接口向應(yīng)用提供與C++插件庫(kù)的交互調(diào)用功能。
首先應(yīng)用通過初始化接口(init)加載指定路徑的C++插件庫(kù),并為該C++插件庫(kù)指定一個(gè)惟一的標(biāo)示符;再通過調(diào)用接口(exec)指定操作字段,調(diào)用C++插件庫(kù)的指定功能;應(yīng)用注冊(cè)回調(diào)事件處理方法(addListener),用于接收處理C++插件庫(kù)的回調(diào)事件,回調(diào)事件中包括用于標(biāo)示每個(gè)回調(diào)的惟一ID,以及傳遞的參數(shù),回調(diào)事件處理方法通過識(shí)別不同的回調(diào)ID來進(jìn)行不同的處理;當(dāng)應(yīng)用與C++插件庫(kù)的交互調(diào)用結(jié)束時(shí),通過調(diào)用移除回調(diào)方法接口(removeListener)結(jié)束對(duì)C++插件庫(kù)回調(diào)的監(jiān)聽,并最后通過調(diào)用卸載庫(kù)接口卸載指定C++插件庫(kù)。應(yīng)用與C++插件庫(kù)的交互流程圖如圖2所示。
圖2 應(yīng)用與C++插件庫(kù)交互調(diào)用流程圖
在銀河銳華終端操作系統(tǒng)中增加C++適配層框架后,便能夠?qū)︺y河銳華終端操作系統(tǒng)應(yīng)用進(jìn)行C++/JavaScript 開發(fā)。本章節(jié)將使用該模式進(jìn)行一個(gè)簡(jiǎn)單加減法計(jì)算應(yīng)用的開發(fā),其中加減法的運(yùn)算邏輯功能在C++插件庫(kù)中設(shè)置,而應(yīng)用通過JavaScript使用系統(tǒng)接口實(shí)現(xiàn)對(duì)C++插件庫(kù)的功能調(diào)用。
應(yīng)用通過繼承C++適配層提供的基類按照功能需求實(shí)現(xiàn)自己的C++插件庫(kù)。該插件類的實(shí)現(xiàn)關(guān)鍵在于對(duì)方法Execute的重載實(shí)現(xiàn),該方法的核心在于通過對(duì)指令參數(shù)的解析來選擇需要執(zhí)行的處理流程,并解析傳入?yún)?shù)進(jìn)行相應(yīng)的處理。
在該實(shí)現(xiàn)過程中,使用“ADD”、“MIN 作為操作指令,并將參數(shù)列表按照J(rèn)SON 格式進(jìn)行解析;在進(jìn)行相應(yīng)的功能操作后將結(jié)果同樣進(jìn)行JSON封裝后返回。
Calculator.h實(shí)現(xiàn)的偽代碼如“代碼1”所示。
應(yīng)用通過插件庫(kù)對(duì)象管理器加載C++插件庫(kù),并對(duì)C++插件庫(kù)進(jìn)行調(diào)用,添加回調(diào)監(jiān)聽器來監(jiān)聽并處理C++插件庫(kù)中的回調(diào)事件。
一個(gè)簡(jiǎn)單的對(duì)上述加、減運(yùn)算C++插件庫(kù)的交互JavaScript 示例如代碼3 所示。首先應(yīng)用需要實(shí)例化一個(gè)插件庫(kù)對(duì)象管理器,并調(diào)用初始化接口對(duì)C++插件庫(kù)進(jìn)行初始化;然后通過注冊(cè)回調(diào)方法接口注冊(cè)一個(gè)回調(diào)方法;最后將參數(shù)進(jìn)行JSON 格式封裝后通過C++插件庫(kù)調(diào)用接口進(jìn)行具體功能的調(diào)用。
基于銀河銳華終端操作系統(tǒng)的C++適配層通過擴(kuò)展系統(tǒng)框架與系統(tǒng)接口,實(shí)現(xiàn)JavaScript與C++的交互調(diào)用,從而使銀河銳華終端操作系統(tǒng)應(yīng)用的開發(fā)能夠使用C++/JavaScript 混合進(jìn)行。這就使銀河銳華終端操作系統(tǒng)應(yīng)用的開發(fā)更加靈活與便捷;也使更多的Android 應(yīng)用能夠更方便地移植到銀河銳華終端操作系統(tǒng)上。這無疑能大大加快專用領(lǐng)域的移動(dòng)操作系統(tǒng)國(guó)產(chǎn)化進(jìn)程。