MTK手機軟件系統工程和配置簡介

MTK是現在市場上所有國內手機設計、製造商使用的最多的一個完整的手機產品解決方案,大部分做手機的技術人員都對此有接觸和了解。不過,MTK的整套軟件系統十分龐大且複雜,很多剛接觸這套系統的軟件工程師一時不知如何進行配置和客戶化定製。本文在此對整個MTK軟件系統的工程結構和配置進行了簡單介紹,希望通過此文和大家相互交流MTK軟件系統的維護和修改、定製方面的心得。

MTK使用了nucleus實時操作系統,在其上做了個內核抽象層的封裝,以適應多種實時操作系統,如oscar、ThreadX、nucleus。整個軟件系統包括nucleus操作系統、平臺設備驅動、協議棧、文件系統、WGUI、MMI、J2ME等。在這裏MMI部分幾乎包括了操作系統內核、協議棧、文件系統之上的所有部分,其中WGUI也在其中。
MTK的PC模擬版使用VC的編譯器和鏈接器生成,ARM版使用ADS1.2的編譯器和鏈接器生成。因爲MTK的整個軟件系統是一個很龐大而且複雜的工程,並且要支持多個MTK的產品系列和多家客戶的客戶化支持,使用集成開發環境(IDE)已經無法勝任,而且很難做到整個工程的自動構建和資源、代碼的生成。所以MTK的軟件系統使用了windows下的GNU開發工具鏈(MinGW)來進行工程的管理、配置和構建,MTK將MinGW放到了第三方工具中。另外還使用了perl腳本來解析用戶輸入的命令行參數,因此第三方工具中還包含了ActivePerl(windows下的perl解釋器)。不過,整個軟件系統並沒有使用MinGW的全部工具,好象只使用了make這個工具,由幾個Makefile控制了構建的過程,在編譯和鏈接時根據最終生成PC模擬版還是ARM版而分別調用VC的編譯器和鏈接器或ADS1.2的編譯器和鏈接器。
接下來我們從具體的工程實踐來看MTK的手機軟件系統。
一. MTK手機軟件系統的目錄結構簡介
  MTK手機軟件系統的主要目錄如下所示,因整個工程的目錄樹非常龐大,爲簡單起見和減小篇幅,去除了在工程結構中相對不重要的目錄。
 |-- Fast_DL
 |-- ROM
 |-- adaptation
 |-- applib
 |-- bootloader
 |-- config
 |-- custom
 |   |-- app
 |   |   -- TOP_6227_BB
 |   |-- common
 |   |-- drv
 |   |   |-- LCD
 |   |   |   -- TOP_6227_LCM
 |   |   |-- image_sensor
 |   |       |-- MT9D011
 |-- drv
 |-- fs
 |-- inc
 |-- init
 |-- interface
 |-- j2me
 |-- kal
 |-- make
 |   |-- applib
 |   |   |-- applib.def
 |   |   |-- applib.inc
 |   |   |-- applib.lis
 |   |   |-- applib.pth
 |   |-- bootloader
 |   |-- config
 |   |-- custom
 |-- media
 |-- mmi
 |-- modis
 |-- mtk_lib
 |  | -- MT6227
 |      | -- S01
 |          | -- gprs
 |               |-- abm.lib
 |               |-- adaptation.lib
 |               |-- applib_inet.lib
 |-- nucleus
 |-- nvram
 |-- plutommi
 |-- tools
 
   Fast_DL是開發時下載二進制映像和資源等的相關文件的目錄。ROM是固化在ROM(可能是Flash的只讀區)中的相關代碼和頭文件的目錄,在給客戶的發佈版中大都只有一些導出函數的頭文件,其中似乎還有一個跳轉表的東西ROMSA_FuncTable。
kal是上面所說的內核抽象層的相關文件的目錄。nvram是存取NV中的內容的相關代碼的目錄。nucleus是nucleus實時操作系統的目錄,在給客戶的發佈版中只有頭文件。drv是驅動相關的代碼的目錄。fs是文件系統相關的目錄,好像只支持fat格式的。tools是工程相關工具的目錄,包括MinGW。interface是系統各層的接口的目錄,還包含重要模塊的接口,如bluetooth、WIFI。config是一些系統和任務(task)相關頭文件的目錄,感覺不像是配置相關的目錄。inc是中斷控制和寄存器地址相關頭文件的目錄。
  modis是PC模擬版的相關目錄,包括了虛擬的GSM網絡、SIM卡等,以及模擬器需要的字符串、圖片等資源,還有PC模擬版的庫、VC的相關工程文件。
mmi是一個缺省的空的MMI應用的目錄,其中只是創建了一個什麼也不幹的MMI任務(線程),處理下層發送上來的消息。plutommi是pluto組織(也可能是原本的mmi應用的代號)所寫的整套MMI應用所在的目錄,而實際上也就是我們需要定製和修改的MMI應用。其中的mmi目錄中是pluto原本寫好的mmi應用,mtkapp中是mtk後來所寫的mmi應用,而Customer中是圖片、字符串等資源的定製目錄,大部分只是修改了字符串和圖片、聲音等的項目只要修改這個目錄下的資源即可。
mtk_lib中是已經編譯鏈接好的ARM版的庫。因整個工程過於龐大,若完整的全新構建一次需要很長的時間。爲了減少構建的時間,將一些已經完全調試穩定且基本不再改動的庫和MTK不開放源代碼的庫放到這個目錄,這樣每次構建時只需要將這些庫和其他編譯好的庫鏈接起來就可以了。這些庫一般是ARM版的,若有thumb版的,則再增加一個和ARM版相對的thumb版的庫,一般叫第二個庫,如media_sec.lib就是thumb版的多媒體庫。
custom是所有客戶化項目的驅動程序及系統和MMI應用定製相關的文件的目錄。如你的手機主板的RAM、FLASH等存儲器的尺寸和地址空間有改動,MMI應用的特性有不同,藍牙、WAP的配置有變化,或是有項目相關的新應用,其相關文件都是放在這個目錄中和特定項目對應的目錄下,如項目CUST1_6227,則放在CUST1_6227_BB下。要注意的是custom也作爲一個模塊存在,這使得其可以通過make目錄中的custom模塊的四個文件進行客戶化的一些定製。
applib、bootloader、init、media、j2me等是這個系統各個層次的相對獨立的模塊各自的目錄,其實drv和fs等目錄也可以看成是相對獨立的模塊,只不過其更重要些而在前面介紹。這些目錄包含了這些模塊的C文件和頭文件。每個目錄(模塊)都在下面的make目錄中有相對應的目錄保存構建時的編譯鏈接配置文件。
make是工程構建過程中最重要的一個目錄了,工程構建用的Makefile和一些中間配置文件將放在這裏,Makefile在講解構建過程時再具體介紹。在每個模塊對應的目錄下,都有四個文件控制了編譯鏈接時的過程和配置。分別是:
<module_name>.def文件中是該模塊構建過程中用的條件定義。
<module_name>.inc文件中是該模塊所有用到的頭文件所在目錄的路徑,是相對整個工程根目錄的路徑。
<module_name>.lis文件中列出了該模塊的所有C文件,其路徑也是相對整個工程根目錄的。
<module_name>.pth文件中是該模塊的所有C文件所在目錄的路徑,是相對整個工程根目錄的路徑。
build目錄中保存了構建過程中產生的目標文件和庫文件,及其他一些中間文件。
二. MTK手機軟件系統的構建過程
如前面一節所述,MTK手機軟件系統的構建使用了GNU的make,使得整個工程的構建可以自動進行,且可以靈活控制。整個構建過程由Make.bat、make2.pl、MoDIS.dsw、Gsm2.mak、Option.mak、<customer>_<project>.mak等文件控制。構建PC模擬版是通過msdev和VC的工程文件MoDIS.dsw來完成的。Gsm2.mak是構建ARM版的核心Makefile文件,整個構建過程由其控制,其他是一些啓動、選項配置、子過程的文件。其關係圖如下所示。
 
在MTK手機軟件系統的根目錄下有一個批處理文件Make.bat,這個批處理文件啓動了整個工程的構建過程。在windows的命令行下,在該系統的根目錄下輸入命令make和相應的參數即可開始工程的構建,該批處理文件的使用方法如下所示。

Usage:
  make ["customer"|"mt62xx"] "project" "action" ["modules"]

Description:
  customer   = mtk             (Default customer)
             = firefly17_demo  (FIREFLY17_DEMO project)
             = [mt6217|mt6219|mt6226|mt6227|mt6228|mt6229] (EVB only)
             = ...

  project    = l1s             (Layer 1 stand-alone)
             = gsm             (GSM only)
             = gprs            (GPRS only)
             = basic           (Basic Framework)

  action     = new             (codegen, resgen, clean, update) (default)
             = update or u     (scan, compile, link)
             = remake or r     (compile, link)
             = clean or c      (clean)
             = resgen          (resgen)
             = c,u             (clean then update)
             = c,r             (clean then remake)
             = codegen         (codegen)
             = viewlog         (open edit to view build log)
             = emigen          (emigen)
             = emiclean        (emiclean)

  module(s)  = modules' name   (kal, l1, ...)
   => OPTIONAL when action is one of (clean c remake r update u c,r c,u)

Example:
  make gsm new                         (MT6205B EVB new)
  make gprs codegen                    (MT6218B EVB codegen)
  make mt6219 gprs update              (MT6219 EVB update)
  make firefly17_demo gprs new
  make milan_demo gprs c,u init custom
  make mt6219 gprs r init custom drv


其中較常用的action有new、update、remake、new_modis這幾個。
  new是全新開始構建整個工程的ARM版,包括圖片、聲音、字符串等資源都要重做,依賴的其他動作最多,是最徹底也是耗時最長的一個動作,一般得到一個新的MTK發佈版本後要做一次。
    update是重新更新整個工程的ARM版,該動作會掃描工程中文件和庫的依賴關係,若依賴關係有變化會建立新的依賴關係,隨後根據新的依賴關係重新編譯鏈接有改動的部分,一般在增加或刪除一些驅動或應用的情況下需要用update。
    remake是重新編譯整個工程的ARM版,該動作只是簡單的重新編譯鏈接有改動的部分,不檢查依賴關係,是耗時最短的一個動作,也是最常用的動作。
  new_modis是全新構建整個工程的PC模擬版,其調用VC的編譯器和鏈接器得到一個可以在windows上運行的PC模擬版。MMI應用軟件工程師可以在沒有硬件板的情況下在PC上檢查和調試自己寫好的應用。
    Make.bat實際上只起引導作用,其只有一行批處理語句perl make2.pl %*,於是運行該批處理文件後控制權轉給了perl腳本make2.pl。在這個perl腳本中解析了用戶輸入的命令行參數,設置變量,準備make時需要的臨時配置文件,隨後根據生成的可運行映像是PC模擬版還是ARM版而分別調用不同的構建過程。
    Pc模擬版的構建通過調用如下命令實現。
system("$msdev MoDIS.dsw /MAKE /"$argu - Win32 $modisDir/"
                    /OUT ${MoDISLogDir}//${argu}.log")
ARM版的構建通過調用如下命令實現。
  system("${makeCmd} -f${makeFolder}${myMF} -r -R
                    CUSTOMER=$custom PROJECT=$project $action")
在這裏${makeCmd}是tools/make.exe,即GNU的make,${makeFolder}${myMF}是make/Gsm2.mak,$action是new、update、remake等。變量CUSTOMER和PROJECT分別是客戶名和項目名,在構建過程中將根據此兩個變量的值選定項目相關的配置文件,從而實現客戶化的定製。通過給make指定ARM版的核心Makefile文件Gsm2.mak,開始了ARM版的構建過程。
    Gsm2.mak文件中包含了Option.mak這個配置用的Makefile文件,另外還包含了一些以.tmp和.bld爲後綴的由perl腳本make2.pl生成的臨時配置文件。這些臨時配置文件主要是一些action如clean、remake等所需的變量設置,及客戶化和版本號等的一些信息。Gsm2.mak控制了new、update、remake等動作的過程。具體分別如下所示。
new : cleanall cmmgen mmi_feature_check asngen codegen asnregen /
            operator_check_lite update

 update : cleanlog cleanbin mcddll_update codegen resgen cksysdrv remake

 remake : cleanlog cleanbin genverno libs $(BIN_FILE) done
 

上面的構建過程的幾個步驟中,最重要的兩個步驟是libs、$(BIN_FILE) 。libs調用ARM版的編譯器和連接器將各個模塊目錄下的C文件編譯鏈接爲獨立的庫。$(BIN_FILE)這個步驟將各個模塊編譯鏈接得到的庫和mtk_lib目錄下的庫一起鏈接起來得到一個映像文件,然後使用ADS的工具fromelf將映像文件生成以變量BIN_FILE命名的二進制文件,該文件可以下載到硬件板上運行。
   libs這個步驟如下所示。
 libs: cleanlib startbuildlibs $(COMPLIBLIST)

  libs中真正進行編譯鏈接的步驟是$(COMPLIBLIST),要生成的庫由變量COMPLIBLIST列出,在ARM版中,變量COMPLIBLIST從變量COMPLIST得到。變量COMPLIST是在Option.mak及其包含的Makefile文件中賦值的。因有很多庫需要編譯鏈接,變量COMPLIBLIST展開後包含多個步驟,而這些步驟都是重複不變的,因此在定義步驟$(COMPLIBLIST)的構建過程時使用%.lib代替。%.lib這個步驟先清除了之前的一些依賴關係文件,將一些變量的設置寫入~compbld.tmp這個臨時文件中,然後給make指定Makefile文件comp.mak,完成庫的編譯和鏈接,如下所示。

%.lib:
    …
    @if /I %OS% EQU WINDOWS_NT /
        (if /I $(BM_NEW) EQU TRUE /
            (tools/make.exe -fmake/comp.mak -k -r -R $(strip $(CMD_ARGU)) COMPONENT=$* > $(strip $(COMPLOGDIR))/$*.log 2>&1)
/
        else /
            (tools/make.exe -fmake/comp.mak -r -R $(strip $(CMD_ARGU)) COMPONENT=$* > $(strip $(COMPLOGDIR))/$*.log 2>&1) /
        ) /
    else /
        (if /I $(BM_NEW) EQU TRUE /
            (tools/make.exe -fmake/comp.mak -k -r -R $(strip $(CMD_ARGU)) COMPONENT=$* > $(strip $(COMPLOGDIR))/$*.log) /
        else /
            (tools/make.exe -fmake/comp.mak -r -R $(strip $(CMD_ARGU)) COMPONENT=$* > $(strip $(COMPLOGDIR))/$*.log) /
        )
 
    上面的命令語句中,參數-k是指有錯誤也要繼續編譯,-r和-R是指沒有GNU make的默認規則和變量。COMPONENT=$*把當前要生成的庫賦給變量COMPONENT。要注意%.lib匹配了所有要生成的庫,但這個步驟一次只生成一個模塊的庫,這個步驟對所有匹配到的庫都會執行一次。
    comp.mak這個Makefile文件控制了模塊的編譯鏈接過程。在這個文件中,首先將當前模塊要生成的庫(由變量COMPONENT傳入)設置給了變量TARGLIB。之後從<module_name>.lis文件中得到SRC_LIST和CPPSRC_LIST兩個源文件列表,設定要編譯的C文件、C++文件、彙編文件等的列表,和要鏈接的中間目標文件的列表。將<module_name>.inc、<module_name>.def、<module_name>.pth文件中的頭文件路徑、C文件路徑、編譯鏈接參數等賦值給相應的變量。將平臺相關(如6223、6225)的編譯參數加上,確定使用ARM編譯器還是thumb編譯器,是否支持ARM指令和thumb指令的interwork模式。最後進入庫的編譯鏈接過程。
    庫的編譯鏈接由update_lib步驟完成,這個步驟直接依賴了$(TARGLIB)。目標$(TARGLIB)是由所有按照.c.obj、.s.obj、%.obj: %.cpp等規則編譯得到的中間目標文件鏈接得到的。其主要過程如下所示。
$(TARGLIB):
    ...
    @if exist $(FIXPATH)/$(CUS_MTK_LIB)/$(COMPONENT).lib                                         /
        (copy /z $(FIXPATH)/$(CUS_MTK_LIB)/$(COMPONENT).lib $(subst /,/,$(TARGLIB))) & /
        ($(LIB) -r $(TARGLIB) $(COMPOBJS_DIR)/*.obj)                                     /
    else                                                                                                 /
        ($(LIB) -create $(TARGLIB) $(COMPOBJS_DIR)/*.obj)
 ...

Option.mak是整個工程構建過程中的總控配置文件,在這個文件中還包含了<customer>_<project>.mak和REL_CR_MMI_<project>.mak這兩個項目相關的配置文件,用戶自定義的配置文件USER_SPECIFIC.mak,另外還包含了一些臨時生成的配置文件。這些配置文件在一起設置了工程構建過程中用到的編譯器、鏈接器,庫和二進制的工具,設置了編譯鏈接時的參數,公共的頭文件路徑,設置了需要包含mtk_lib目錄中的哪些既有的庫,設置了需要生成的庫等一系列相關的設置。這些設置都由一些重要的變量保存,具體在下一節中講解。
三. MTK手機軟件系統的配置
  MTK手機軟件系統的大部分配置都已經確定,基本上不需要再改變,一般是MTK發佈新的版本時會作些改變,客戶不大需要關心。最主要的配置文件是Option.mak,而客戶化定製需要需要修改的主要是<costomer>_<project>.mak、REL_CR_MMI_<project>.mak這兩個文件。
     Option.mak文件中設置了工程構建時用到的編譯器、鏈接器、庫管理、二進制文件生成等工具的路徑和可執行程序名,設置了基本的編譯鏈接參數,指定CPU類型(ARM7EJ-S),確定最終使用的庫列表(COMPLIST)。
     
    一個項目是由工程中的多個基本庫、第三方庫和由源代碼新編譯鏈接的庫組成的,最終這些庫鏈接到一起得到一個完整的可執行映像文件。由哪些新編譯鏈接的庫來組成一個項目是由四個關鍵的變量決定,其中一個是前面提到的COMPLIST,另外三個分別是CUS_REL_SRC_COMP、 CUS_REL_PAR_SRC_COMP、CUS_REL_MTK_COMP。這個幾個變量的關係如下所示。
# *************************************************************************
# Custom Release Component Configuration
# *************************************************************************
# Be sure the following:
# 1. CUS_REL_SRC_COMP + CUS_REL_PAR_SRC_COMP =COMPLIST(CUSTOM_RELEASE = True)
# 2. CUS_REL_SRC_COMP + CUS_REL_PAR_SRC_COMP + CUS_REL_MTK_COMP = COMPLIST(CUSTOM_RELEASE = False)
 
  COMPLIST確定了該項目最終是由哪些庫(組件)組成的。MTK的內部版本構建時,則包括 CUS_REL_SRC_COMP、 CUS_REL_PAR_SRC_COMP、 CUS_REL_MTK_COMP這些庫。客戶版本構建時,則只包括 CUS_REL_SRC_COMP、 CUS_REL_PAR_SRC_COMP這些庫。手機設計公司構建的版本都是客戶版本,因此只要改變 CUS_REL_SRC_COMP、 CUS_REL_PAR_SRC_COMP這兩個變量的值即可以定製自己的項目了。
    MTK_LIBS確定了該項目最終包含了哪些MTK提供的基本庫。
    COMPOBJS確定了該項目最終包含了哪些第三方提供的不帶源代碼的庫。變量CUS_RES_OBJ_LIST用於把這些第三方庫隨項目發佈。
 Option.mak和REL_CR_MMI_<project>.mak這兩個文件都有對這兩個變量CUS_REL_SRC_COMP、 CUS_REL_PAR_SRC_COMP賦值。但Option.mak文件只是設定了整個工程需要的基本庫,如手寫、圖形解碼等,和特定項目沒有關係。因此客戶要定製自己的項目只需要修改REL_CR_MMI_<project>.mak這個文件對這兩個變量的賦值即可。
    <costomer>_<project>.mak文件也有對COMPLIST的賦值,但這只是對MTK的內部版本有用,客戶版本沒有影響。值得注意的是,該項目的絕大部分功能特性(feature)是在這個文件中確定的,如使用的sensor、支持哪些音視頻格式、電話本大小、LCD屏幕大小等。下面是該文件中的部分內容。
J2ME_SUPPORT      = NONE    # J2ME support: NONE, MTK_J2ME, J2ME_LIB, /
                               MTK_J2MEHI, J2MEHI_LIB, MTK_DUMMYVM
 
DRM_SUPPORT = NONE #DRM VENDOR: NONE, MTK, BSCI
 
DRM_VERSION = NONE # DRM VERSION: NONE, V01, V02, ALL
 
AMRWB_DECODE        = TRUE      # TRUE/FALSE
 
AMRWB_ENCODE        = FALSE     # TRUE/FALSE
               # MT6219 DSP cannot support AMRWB_ENCODE when GPRS connection
 
JPG_DECODE          = JPG_HW    # NONE, JPG_HW, JPG_SW
 
JPG_ENCODE          = JPG_HW    # NONE, JPG_HW, JPG_SW
 
GIF_DECODE          = TRUE      # TRUE/FALSE
 
PNG_DECODE          = NONE      # NONE, PNG_HW, PNG_SW
 
DAF_DECODE          = TRUE      # TRUE/FALSE
 
MJPG_SUPPORT        = FALSE     # TRUE/FALSE
 
MP4_CODEC           = TRUE      # TRUE/FALSE
 
AAC_DECODE          = TRUE      # TRUE/FALSE
 
ISP_SUPPORT         = TRUE      # TRUE/FALSE
 
CMOS_SENSOR         = OV7660        # OV9640, PAS105, PAS302, NONE, MT9D011, /
                                       MT9M111, OV9650
四. 增加模塊的配置實例
若我們需要加入zlib這麼一個模塊(zlib包含了很多程序都用到的壓縮和解壓函數),我們可以按如下步驟進行。
    1. 把zlib的源代碼包拷貝到你的MTK軟件系統根目錄下,這樣所有的zlib代碼都在zlib目錄或zlib-1.2.3目錄下(用哪個目錄名由你的喜好來確定),在此爲簡單起見就放在zlib目錄。
    2. 在make目錄下新增一個zlib的目錄(最好和根目錄下的目錄名一樣),增加四個文件,分別是zlib.def、zlib.inc、zlib.lis、zlib.pth。zlib.def文件只要加上APCS_INTWORK就可以了,其他三個文件中加上源文件及其目錄、頭文件目錄即可。
    3. 在REL_CR_MMI_<project>.mak這個文件的合適位置加上如下語句。
CUS_REL_SRC_COMP += zlib
    4. 把這個工程remake一下,若沒有錯誤,zlib模塊就成功加上去了。其他模塊就可以調用zlib提供的壓縮和解壓縮函數了。
若我們需要加入一個沒有源代碼的第三方庫,譬如加入wifi,我們可以按如下步驟進行。
    1. 把wifi的所有第三方庫文件拷貝到一個新建的wifi目錄下。
    2. 在Option.mak這個文件的合適位置加上如下語句。
ifeq ($(strip $(WIFI_SUPPORT)),WIFI_LIB)
    COMPOBJS += wifi/sslplus.lib
    CUS_REL_OBJ_LIST += wifi/sslplus.lib
    COMPOBJS += wifi/sb.lib
    CUS_REL_OBJ_LIST += wifi/sb.lib
endif
     3. 把這個工程remake一下,若沒有錯誤,wifi庫就成功加上去了。其他模塊就可以調用wifi提供的功能了。

發佈了12 篇原創文章 · 獲贊 3 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章