Finally, I successfully compiled AOSP in WSL (Windows Subsystem for Linux) 終於讓WSL成功運作AOSP

多年以來,要開發Android裝置,基本上你只能使用Linux環境來完成這個工作。過去,我基於 OS X 下的 Vagrent 來編譯 AOSP,但是效能與效果非常地不理想。最終,我只好放棄這開發方式。老實的安裝了一套Linux來做做為開發平台。使用 Ubuntu 來開發 AOSP 說真的非常的方便,但是這跟我常用的Windows 與 macOS 開發平台產生了很大的不方便。

Microsoft Love Linux

Microsoft Love Linux

大概誰也沒想到Windows會在2016年迎來一個重大的改變,WSL (Windows Subsystem for Linux)。這很不 Microsoft。Windows 中竟然開始支援 Linux Subsystem。這個改變時在嚇壞了大家,也完全顛覆了人們對於Microsoft的刻板印象。 至於甚麼 Linux Subsystem 呢?簡單的說,他不是VirtualMachine,還是採用一種Fusion的方式,把多個不同的Subsystems連結到 Windows 的 Kernel 之中。 換言之,就是這個方式實現了 ABI 的相容。一個 Linux 程式可以不經過編譯,便能在 Windows上執行。不同於VirtualMachine (比方 HyperV 與 VirtualBox) 採用虛擬化的技術讓不同的OS在 HOST 與 GUEST 中切換運行,ABI 可以算是一個更輕量與快速的方式,讓Linux 程式運行在 Windows上。

echo “hello!!!” > /mnt/c/temp/log.txt

安裝 WSL 與 Ubuntu

請參考Microsoft關於如何安裝WSL與Ubuntun的方式

首先你一定得有套Windows 10。之後,選擇一個適合的Ubuntun版本。這邊我推薦 16.04,原因我們之後再說。但是我自己則是花了不少時間才在18.04成功編譯出 AOSP 的。所以以下的內容都是基於 18.04開發過程所寫成的。

再來我們要講述如何建立環境與編譯AOSP。所以我們假設你已經了解如何在一般的傳統的 Linux 編譯 AOSP Android Project。我們就不贅述這些基礎知識。

WSL 的限制與不同

在講述這一切之前,我們先理解 WSL 在編譯環境中與真實的 Linux 有甚麼不同,有哪些限制。

  1. 只能只行64位元的程式。也就是常見的 ELF32 是不能夠在 WSL 上執行的。
  2. WSL 下,能夠用行 Win32 EXE 程式。但是注意,對執行的Windows程式來說,本質上還是運行於 Windows 上的程式,所有的檔案結構依然是Windows 那套。也就是說,/mnt/c/ 這樣的檔案名稱是無法被這樣的Windows 程式存取的。(這點很重要,也成為我們解套AOSP編譯的一個重要契機)
  3. WSL 預設是用 lxfs 檔案系統來當成 rootfs。而且這個檔案系統是分大小寫的。
  4. 你可以存取 NTFS,但是 NTFS 預設是不分大小寫。但請注意 AOSP 只能在區分大小寫的檔案系統上編譯。所幸,在新版的 Windows 10 中,NTFS 已經能夠開啟大小寫區分了。我們可以動態的開啟這些功能。
  5. WSL 藉由 DrvFs 來存取Windows 的檔案系統。
    C:\ on /mnt/c type drvfs (rw,noatime,uid=1000,gid=1000,metadata,case=off)
  6. 接續 5. 你的外接裝置比方 USB DISK,並不會自動的加入 WSL 的系統。最簡單的方式就是重新啟動 WSL。
    wsl — shutdown or wsl -t Ubuntu or Restart-Service LxssManager
  7. WSL的安裝位置。預設來說安裝於:這個位置是能夠被改變的,只是相對來說有些難處。
    %userprofile%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc
  8. Symbolic Link 的問題:
    如果你在 rootfs 上建立 symbolic link,這點跟一般 Linux 下沒甚麼不同。但是如果你在 DrvFs 下的 NTFS 編譯 AOSP,那麼你記住你的檔案系統是與 Windows 共用的。 Windows 下有兩種連結方式,"SYMBOLIC" 與 "JUNCTION" 其中 "S" 類的需要有較高的權限才能使用。另外,我測試的結果是想對目錄時,SYMLINK 是可以的,但是 /mnt/xxx 這類是完全無法在 Windows上正常工作的。

開始編譯AOSP

工作目錄設定:
由於我的 C:\ 容量並不大,而且我想要增加 Winodws 與 WSL 共用性,所以我選擇了 D:\aosp 作為我的工作目錄。以 WSL 來說就是 /mnt/d/aosp。

設定目錄為大小寫:
如同前面所述的,NTFS預設來說並不分大小寫。請開啟cmd,並執行:

fsutil.exe file setCaseSensitiveInfo D:\aosp enable

下載你的AOSP或是你自己的Android Project到這個目錄中:

repo init …
repo sync …

下載開發工具:

sudo apt update && sudo apt full-upgrade -y && sudo apt install -y bc build-essential ccache curl g++-multilib gcc-multilib git gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5-dev libsdl1.2-dev libssl-dev libwxgtk3.0-dev libxml2 libxml2-utils lzop m4 openjdk-8-jdk pngcrush repo rsync schedtool squashfs-tools xsltproc zip zlib1g-dev

sudo apt-get install libxml-simple-perl && sudo apt-get install python-pip && pip install pycrypto && sudo apt-get install ccache && sudo apt-get install bison

安裝adb: (Android Debug Bridge)

由於 adb 是採用 client & server 的方式運作。為了不用碰觸 usb 支援的問題,我們將在windows 上運行 adb server,這樣一來無論在哪個 WSL 用行 adb client 就都沒有問題了。還有一點必須注意,你必須安裝相同版本的adb才能正常工作。為了保持相同版本我們採用個別安裝:(當然你可以用你自己SDK或是Anndroid Studio的版本)

mkdir ~/android && cd ~/androidwget https://dl.google.com/android/repository/platform-tools-latest-linux.zip && unzip platform-tools-latest-linux.zipecho “alias adb=’~/android/platform-tools/adb’” >> ~/.bash_aliases
echo “alias fastboot=’~/android/platform-tools/fastboot’” >> ~/.bash_aliases
source ~/.bash_aliases

Windows的版本請自行下載:
https://dl.google.com/android/repository/platform-tools-latest-windows.zip

安裝舊版OpenSSL:

如果你用的是16.04那麼你應該不需要這個安裝。因為這個版本的Ubuntu自帶的OpenSSL並不會有甚麼問題。如果你用的是18.04那麼你可能會遇上版本太新的問題。

mkdir ~/openssl && cd ~/opensslwget https://www.openssl.org/source/old/1.0.1/openssl-1.0.1u.tar.gz
tar -zxvf openssl-1.0.1u.tar.gz
cd openssl-1.0.1usudo ./config && sudo make && sudo make install# (backup current openssl tool)
sudo cp `which openssl` `which openssl`_new
# (create link to the new openssl)
sudo ln -sf /usr/local/ssl/bin/openssl `which openssl`

克服各種ELF32不相容問題:

我們前面說過,WSL 是不能運行 ELF32 程式的。但是 AOSP 中,有許多prebuilts 是採用 32 bits 的方式。我們必須要這些工具置換成64 bits 版本。

Bison
aosp_android_9.0.0/source/prebuilts/misc/linux-x86/bison/bison ==> /aosp_9/prebuilts/build-tools/linux-x86/bin
Using soft-link bison -> ../../../../../aosp_9/prebuilts/build-tools/linux-x86/bin/bison
ln -s ../../../../../aosp_9/prebuilts/build-tools/linux-x86/bin/bison bison
Error: prebuilts/misc/linux-x86/bison/bison: prebuilts/build-tools/common/bison/m4sugar/m4sugar.m4: cannot open: No such file or directorycp ../aosp_9/prebuilts/build-tools/common/ ./prebuilts/build-tools/ -rfOrmake bison
export BISON_EXEC=$ANDROID_BUILD_TOP/out/host/linux-x86/bin/bison
ijar’s problem
wsl: https://github.com/Microsoft/WSL/issues/3157
possible patch: https://review.lineageos.org/c/LineageOS/android_build/+/208102/5/tools/ijar/zip.cccd build/make/tools/ijara18c1d9.diff
a18c1d9.diff
git apply a18c1d9.diff
make ijar
export IJAR_EXEC=$ANDROID_BUILD_TOP/out/host/linux-x86/bin/ijar
Orreplace prebuilts/build-tools/linux-x86/bin/ijar with $ANDROID_BUILD_TOP/out/host/linux-x86/bin/ijarmv ijar ijar_back && cp -f $ANDROID_BUILD_TOP/out/host/linux-x86/bin/ijar .Ormake ijar
export IJAR_EXEC=$ANDROID_BUILD_TOP/out/host/linux-x86/bin/ijar

以上是我的置換過程。實際情況還得根據自己遇上的問題。

關於那些預先安裝沒有代碼的執行檔案:

用Win32 EXE替換ELF32:

如我們先前提到,你無法使用執行 ELF32。很多都是因為這個問題造成 AOSP 無法在 WSL 中編譯的。雖然 ELF32 不能被執行,但是 Win32 的 EXE 卻是能直接被WSL執行的。這點也成了我們克服這個問題的重要契機。

舉例來說,我遇上的Qualcomm Sign Tool 的問題:

Qualcomm’s image sign tool bin is 32bits. We must use 64bits.Fortunately, WSL could run win32 .exe directly. We use WIN version to replace LIN.qcom/proprietary/common/scripts/SecImage/bin/LIN
mv crypto_ccm crypto_ccm_32bit_not_work
cp ../WIN/crypto_ccm.exe ./crypto_ccm
cp ../WIN/openssl.* .
Although, we can run .exe from WSL direcrtly. The file input and path are not accessible from .exe. 🙁Using mklink junction to connect wsl/ubuntu/tmp with root tmpmklink /j tmp %userprofile%\AppData\Local\Packages\CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs\tmp

我們用 Win32 EXE 替換了 ELF32,然後再利用mklink 來做符號連結,把NTFS 檔案連到 WSL 的Linux 檔案系統之中。如此一來就能直接在WSL中使用,並且路徑都是正確的。

增快執行效能:

由於 WSL 是採用 ABI 相容的方式執行 ELF64 的程式,在 Windows 子系統中再轉譯這些指令到 Kernel 代碼,所以他的運行上是有一定的耗能。同樣的機器下,絕對是比原生Linux更慢。另外,磁碟效能也是一個問題。WSL 模擬了Linux VFS 然後提供各種對應的 File System。建議,在編譯 AOSP 的期間,可以嘗試把防毒軟體關閉,這樣可以增進檔案系統的效能。

結論:

經過一番努力終於讓 AOSP 能夠在 WSL 上成功的編譯。相對於 HyperV 或是 Virtual Box 上安裝 Linux 的方式,效能與方便性是高上許多。你可以透夠Visual Studio Code 與 Visual Studio 2017/2019 直接編譯,然後也可以透過WSL 介面或 透過 CLI 直接把命令下到 AOSP上。這點可說十分方便。

最後,WSL 上編譯 AOSP 整個難度還是太過困難。我們期待 WSL2 的到來讓一切問題都能被一次性解決!

延伸閱讀:
Windows Subsystem for Linux Overview
Windows Subsystem for Linux (WSL) 原理介紹
LineageOS Android Distribution