1. 程式人生 > >Unity的二進位制熱更新 (二)unity的執行原理

Unity的二進位制熱更新 (二)unity的執行原理

今天講一下Unity引擎的執行原理。為什麼我們寫繼承了Monobehaviour的c#程式碼會在固定的時候執行Update,FixedUpdate等回撥呢?是什麼在背後驅動著引擎去找到你寫的指令碼並執行的呢?

回答這些問題自然是能看到Unity的程式碼就一目瞭然了,但是unity並不是開源軟體。還好iOS編譯不是直接輸出ipa,而是給你提供了一個xcode工程,讓你自己去編譯。我們開啟這個工程的目錄可以看到Classes目錄下面有一大堆.mm檔案,Classes目錄還有一個一個Native資料夾,跟Classes目錄平行的還有一個Library目錄下面放著libiPhone-lib.a和一個il2cpp的目錄下面放著一大堆標頭檔案。有iOS程式設計的基礎的同學大概能猜到這些.mm檔案是unity引擎跟iOS系統對接的程式碼,負責呼叫iOS的系統函式,以及初始化引擎定時回撥等等操作。

事情一步一步看,從初始化開始看起,在UnityAppController.mm這個檔案裡面我們可以找到didFinishLaunchingWithOptions函式也就是程式初始化的入口。我們可以看到這個函式一進去就呼叫了UnityInitApplicationNoGraphics這個名字十分讓人在意的函式,基本上可以斷定這個函式就是unity初始化的邏輯了。可是這個函式我們沒有原始碼,怎麼辦,只好祭出ida。而且我們看到工程裡面提供了libiPhone-lib.a,這個unity的所有程式碼的庫,有了.a所有的符號就都有了,所以說unity幹嘛不給開原始碼。。。。想知道怎麼搞的自己好好看看不就完了麼。。。

直接看.a裡面有一大堆.o不太直觀,乾脆編譯出來一個沒有strip符號的ipa直接看可執行檔案。我們可以通過符號找到UnityInitApplicationNoGraphics這個函式的入口,有興趣的同學可以自己去用ida去看,經過大致的觀看可以看到這就是unity的初始化邏輯,並在這裡面初始化了il2cpp虛擬機器並載入了我們自己寫的c#指令碼,入口是InitializeIl2CppFromMain。再深入觀察,unity裡面執行迴圈的函式叫做

PlayerLoop(bool, bool, IHookEvent*),這個函式會遍歷場景中所有的GameObject,而GameObject上面掛載了哪些元件unity是知道的並儲存了這些元件的控制代碼,那麼剩下的就是去根據時間順序去讓UpdateManager,FixedUpdateManager等等Manager去依次根據這些GameObject名字和控制代碼依次呼叫Update,FixedUpdate等函式,呼叫函式的入口是_il2cpp_runtime_invoke

。其實說到這兒如果有其他想法的同學可以把這個lib做成特徵值給ida,然後去匹配已經上線的專案,找到這個入口,掛上偵錯程式,那麼我們就能看到這些遊戲有哪些指令碼,傳了什麼引數等等等。。。。

我們知道了執行指令碼的入口,那麼我們的c#指令碼經過編譯之後變成了什麼?什麼是il2cpp虛擬機器?unity怎麼通過名字找到我們的指令碼入口地址?怎麼傳入正確的引數?今天又不想寫了明天繼續寫,下面就是重點了