信UOS上編譯內(nèi)核跑Anbox:從binder配置到APK安裝完整指南)
我最近在一臺統(tǒng)信UOS系統(tǒng)的機器上完整走了一遍Anbox路線從內(nèi)核編譯到安卓APP裝進系統(tǒng)中間踩了不少Linux發(fā)行版特有的坑。老實說UOS雖然和Debian系沾親帶故但它在內(nèi)核、安全中心、軟件源這幾個環(huán)節(jié)都有自己的脾氣網(wǎng)上大量Ubuntu教程直接照搬過來大概率會卡在“模塊加載”或“服務起不來”這種地方。這篇就把整個過程記錄下來把容易踩坑的關鍵點都指出來給想在UOS上跑安卓APP的朋友一條能直接照著做的路。說一下適用范圍如果你需要的是偶爾運行辦公、工具類、輕娛樂的安卓APP那Anbox性價比很高如果你指望它變成第二個安卓手機那我建議降低預期。文章按“選型思路 → 內(nèi)核準備 → 內(nèi)核編譯 → 模塊驗證 → Anbox安裝 → APK安裝”的順序?qū)懨恳徊阶隽耸裁?、為什么這么做、出問題怎么查都會說清楚。1. UOS跑安卓應用的方案對比為什么我最后選了Anbox1.1 模擬器、容器、原生方案的本質(zhì)差異在UOS上跑安卓APP大致有三條路虛擬機模擬器、容器方案、閉源的商業(yè)兼容層。后面這類在UOS上不夠通用我身邊用的人不多這里主要說前兩者。模擬器方案以VirtualBox或QEMU為代表在宿主機里虛擬出一整套硬件再在虛擬硬件上跑完整的Android系統(tǒng)。優(yōu)點是兼容性最好幾乎什么APK都能裝缺點是性能損耗明顯內(nèi)存和CPU開銷都大UOS又是出了名的吃內(nèi)存日常體驗容易卡頓適合測試不適合常駐使用。容器方案以Anbox和Waydroid為代表它們不虛擬硬件而是直接復用宿主機的Linux內(nèi)核把Android的用戶態(tài)裝進隔離環(huán)境里運行。因為沒有硬件模擬層啟動速度快、性能接近原生但對“宿主機內(nèi)核能提供什么能力”有硬性要求最典型的就是內(nèi)核必須提供Android所需的binder和ashmem這兩類IPC/內(nèi)存設備。我的最終選擇是Anbox原因有兩點一是它對內(nèi)核的要求在UOS 5.10內(nèi)核上可以通過自行編譯實現(xiàn)路徑清晰二是它的社區(qū)資料相對穩(wěn)定官方deb包在Debian系上安裝也流暢。Waydroid雖然更新、Android版本也新但它的binderfs依賴在UOS上更容易出問題后文會展開說。1.2 Anbox的邊界哪些APP裝得起哪些裝了也白搭選型之前先聊清楚邊界問題否則后面裝完再后悔就晚了。Anbox官方鏡像基于Android 7這個版本本身不算高再加上鏡像里沒有Google Mobile ServicesGMS所以會遇到這些情況依賴Google服務框架的APP比如大量國外社交、地圖、支付類APP裝了大概率閃退或卡在啟動頁。比較新的國產(chǎn)APP如果最低支持版本高于Android 7會直接提示“無法安裝”或“解析包錯誤”。純ARM架構(gòu)的APK在Anbox默認的x86_64鏡像里沒法直接跑需要找x86/x86_64版本。硬件GPS、NFC這類設備功能基本指望不上因為Anbox只提供基礎的虛擬傳感器和網(wǎng)絡。換句話說Anbox最適合的場景是在辦公電腦上跑一個需要安卓環(huán)境才能用的輕量工具APP比如某個設備管理工具、某個內(nèi)部OA、某個常用的文件處理工具。如果你要玩王者榮耀、原神這種3D大作就不要折騰Anbox了。1.3 我為什么沒選WaydroidWaydroid這幾年風頭很足支持較新的Android容器圖形性能也更好按理說比Anbox有前途。但我在UOS上實測下來的感覺是它的官方腳本對Debian系的支持比較粗糙而且Waydroid依賴binderfs而UOS自帶內(nèi)核默認沒有開啟binderfs這意味著很可能需要自己編譯內(nèi)核或加載額外模塊。既然怎么都要碰內(nèi)核那選配置路徑更成熟、社區(qū)資料更明確的Anbox反而省心。我這不是說Waydroid不行而是“在UOS上從零跑通”這個前提下Anbox的坑更少、更可控。后面所有內(nèi)容都圍繞Anbox展開。2. 編譯內(nèi)核前的準備工作版本確認、工具鏈和源碼獲取2.1 先搞清楚你手上這臺UOS的底細不要憑感覺開始第一步永遠是確認系統(tǒng)情況。我會按下面幾條命令過一遍cat /etc/os-release uname -r uname -m我手頭這臺是UOS 20系列內(nèi)核版本5.10.xx86_64架構(gòu)。如果你的內(nèi)核版本是4.19或者更新的5.15后面配置項的寫法會略有差異但整體流程一致。這里特別強調(diào)一點編譯內(nèi)核最好選擇和當前系統(tǒng)版本接近的內(nèi)核源碼不要一上來就拉Linux主線最新版。主線內(nèi)核和UOS深度定制的內(nèi)核差異太大就算Anbox跑起來了顯卡驅(qū)動、指紋驅(qū)動、電源管理等很可能翻車得不償失。2.2 編譯工具鏈和依賴庫的坑UOS默認桌面版不會裝全套編譯工具需要手動補上sudo apt update sudo apt install build-essential bc bison flex libssl-dev libelf-dev dwarves這幾個包的作用分別是build-essential提供gcc和make基礎環(huán)境bc是內(nèi)核配置腳本用的計算器工具bison和flex用來處理內(nèi)核源碼里的語法解析器libssl-dev負責內(nèi)核模塊簽名和加密相關功能libelf-dev和dwarves主要是新版內(nèi)核生成BTF信息時需要用的不裝的話編譯到最后可能報錯。有個UOS特有的小坑dwarves這個包在部分UOS源里叫pahole如果你執(zhí)行上面命令時報“無法定位軟件包”先搜一下apt search pahole把包名替換一下即可。2.3 內(nèi)核源碼從哪里來用什么版本最穩(wěn)獲取UOS內(nèi)核源碼我個人推薦三種方式按優(yōu)先級排列如果軟件源里開了deb-src直接apt-get source拉取當前版本源碼和系統(tǒng)默認配置最貼近。從統(tǒng)信/Deepin的開源倉庫下載與當前內(nèi)核版本一致的源碼包這種方式最穩(wěn)我最后也是走的這條路。實在找不到匹配版本再去kernel.org下載相同大版本號的官方內(nèi)核但需要手動把UOS的編譯配置遷移過去過程繁瑣不推薦新手嘗試。源碼準備好之后把當前系統(tǒng)內(nèi)核的配置文件拷貝出來作為基礎配置cp /boot/config-$(uname -r) .config這一步能讓你在后續(xù)編譯時沿用UOS默認的硬件支持、文件系統(tǒng)、驅(qū)動選項只針對Anbox需要的功能做增量修改大幅降低“編譯完新內(nèi)核導致無線網(wǎng)卡失效、顯卡出問題”的風險。3. 內(nèi)核配置與編譯實操把binder和ashmem放進來3.1 binder和ashmem到底在Anbox里扮演什么角色Anbox復用宿主機內(nèi)核但Android的用戶態(tài)代碼并不認識普通Linux內(nèi)核它只認Android內(nèi)核提供的幾個專屬設備。其中最關鍵的是兩個binderAndroid系統(tǒng)的進程間通信中樞。Android里APP和系統(tǒng)服務之間幾乎所有的跨進程調(diào)用都要經(jīng)過binder相當于一個“系統(tǒng)級服務臺”。沒有它Android的各個進程之間沒法通信系統(tǒng)服務起不來整個環(huán)境自然就崩了。ashmem匿名共享內(nèi)存機制用來在進程之間高效傳遞大塊數(shù)據(jù)。圖形緩沖、進程間大數(shù)據(jù)交換都依賴它你可以理解成“進程們共用的倉庫”。Anbox啟動時容器里的Android系統(tǒng)會直接去打開/dev/binder和/dev/ashmem這兩個設備節(jié)點。設備不存在、權限不夠、模塊版本不匹配任何一個環(huán)節(jié)出問題都會導致啟動失敗或中途崩潰。3.2 打開配置項從基礎config到olddefconfig拿到基礎的.config文件后用內(nèi)核源碼自帶的配置腳本直接修改配置項比打開menuconfig一個個找要快得多也更容易寫到教程里復現(xiàn)cd /path/to/kernel-source # 打開Android相關支持和兩個關鍵設備驅(qū)動 scripts/config --enable CONFIG_ANDROID scripts/config --enable CONFIG_ANDROID_BINDER_IPC scripts/config --enable CONFIG_ASHMEM # 生成最終的完整配置文件 make olddefconfig這三個是Anbox跑起來的最低要求。CONFIG_ANDROID是Android內(nèi)核支持的總開關CONFIG_ANDROID_BINDER_IPC對應binder驅(qū)動CONFIG_ASHMEM對應ashmem驅(qū)動。用--enable選項會把選項編譯進內(nèi)核而不是編譯成外部模塊這樣重啟之后設備節(jié)點就會自動出現(xiàn)省去手動modprobe的麻煩我強烈建議用這種方式。至于CONFIG_ANDROID_BINDERFS這是新版內(nèi)核引入的binder文件系統(tǒng)機制Anbox社區(qū)對它的支持并不統(tǒng)一默認可以不開啟。如果你以后要用Waydroid可以再回頭編譯一個帶binderfs的新內(nèi)核當前階段不要給自己增加變量。配置改完之后用以下命令確認關鍵選項確實打開了grep -E CONFIG_ANDROID|CONFIG_ASHMEM|CONFIG_BINDER .config只要看到對應選項后面跟著y而不是# CONFIG_XX is not set就說明配置生效了。3.3 編譯與打包用deb包方式安裝內(nèi)核編譯內(nèi)核有兩種常見姿勢一種是在源碼目錄里直接make install和make modules_install另一種是用make deb-pkg打成deb包再安裝。我強烈建議用deb包方式make -j $(nproc) deb-pkg-j參數(shù)后面接CPU核心數(shù)如果你的機器內(nèi)存足夠可以稍微加大一點并行度。編譯過程根據(jù)CPU性能不同通常要等20分鐘到1小時不等。正常情況下編譯完成后會在源碼目錄的上一級目錄生成類似linux-image-5.10.x_*.deb、linux-headers-5.10.x_*.deb、linux-libc-dev_*.deb的安裝包。然后用dpkg -i逐個安裝sudo dpkg -i ../linux-image-*.deb ../linux-headers-*.deb ../linux-libc-dev_*.deb sudo update-grub2完成后重啟機器。用deb包方式有幾個好處一是安裝路徑和UOS默認內(nèi)核一致grub能自動識別二是哪天新內(nèi)核出問題了還能在grub啟動菜單里選擇老內(nèi)核回滾三是不用擔心手動make install把/lib/modules目錄搞亂。4. 模塊加載與驗證編譯完不等于能用4.1 重啟后先驗證設備節(jié)點重啟后第一件事確認當前確實進入了新內(nèi)核uname -r如果版本號對上了接下來直接看設備節(jié)點ls -l /dev/binder /dev/ashmem因為我前面用的是--enable編譯進內(nèi)核正常情況這里應該能看到binder和ashmem兩個設備文件。如果看不到也不要急著繼續(xù)裝Anbox先排查清楚否則后面每一步都會出奇怪的報錯。4.2 設備或模塊不對時的完整排查順序如果你看到設備節(jié)點缺失按照下面的順序排查不要跳過任何一步確認內(nèi)核配置確實編譯進去了。執(zhí)行zcat /proc/config.gz | grep -E BINDER|ASHMEM如果系統(tǒng)沒有開啟/proc/config.gz那就回到源碼目錄用grep查.config文件。檢查模塊文件是否存在。有些情況下雖然配置開了但被編成了外部模塊m那就需要手動加載find /lib/modules/$(uname -r) -name *binder* -o -name *ashmem*找到對應的.ko文件后modprobe加載。模塊名在不同內(nèi)核里不完全一樣5.10上常見的是binder_linux和ashmem_linux4.19上則更可能是binder和ashmem一切以實際文件名稱為準。查看內(nèi)核是否注冊了misc設備。binder和ashmem驅(qū)動在misc設備框架下注冊加載成功后會出現(xiàn)在/proc/misc里cat /proc/misc | grep -E binder|ashmem如果模塊在、設備節(jié)點卻沒有手動創(chuàng)建設備文件也只是臨時方案。先用cat /proc/misc | grep binder查到binder對應的次設備號假設查到的是57再執(zhí)行sudo mknod /dev/binder c 10 57 sudo chmod 0666 /dev/binder要注意的是misc設備的主設備號通常是10但次設備號是內(nèi)核運行時動態(tài)分配的不同機器可能不一樣不要照抄網(wǎng)上的“57”。這也是為什么強烈建議把驅(qū)動編譯進內(nèi)核而不是加載模塊前者能觸發(fā)自動創(chuàng)建節(jié)點后者則可能遇到udev沒有自動生成節(jié)點的尷尬。4.3 用模塊加載配置和udev規(guī)則把權限一次做對設備節(jié)點創(chuàng)建出來只是第一步還要確保每次開機都自動生效、并且當前用戶有權限訪問。創(chuàng)建/etc/modules-load.d/anbox.conf文件內(nèi)容寫上模塊名binder_linux ashmem_linux如果你的模塊被編譯成binder和ashmem的舊命名文件名對應改成這兩個名字就行。這一步只對“模塊方式”有意義編譯進內(nèi)核的系統(tǒng)理論上不需要但寫上也無妨不會影響啟動。接下來是udev規(guī)則把設備權限放開。創(chuàng)建/etc/udev/rules.d/99-anbox.rulesKERNELbinder, NAMEbinder, MODE0666 KERNELashmem, NAMEashmem, MODE0666然后重新加載規(guī)則sudo udevadm control --reload-rules sudo udevadm trigger這一步特別容易被忽略。Anbox的容器服務是root啟動的沒問題但圖形界面的session-manager通常以普通用戶身份運行如果設備權限是root:root 0644普通用戶打開/dev/binder就會報Permission denied而且報錯信息不會直接說“沒權限”而是“無法啟動Android系統(tǒng)”誤導性很強。5. Anbox本機安裝deb包、源碼構(gòu)建和依賴排錯5.1 安裝Anbox先走官方deb包這條路內(nèi)核就緒后開始裝Anbox本體。建議直接從Anbox官方GitHub倉庫的Release頁面下載x86_64版本的deb包然后執(zhí)行sudo dpkg -i anbox*.deb sudo apt -f install第一次dpkg -i大概率會報依賴缺失這是預期內(nèi)的。apt -f install會自動把缺的依賴包拉齊比如libwayland相關庫、dbus相關工具等。UOS軟件源里的包版本如果偏老個別依賴可能提示“無法滿足依賴關系”這時候可以關注一下缺的具體包名手動疊加倉庫或用更高版本替換。這里還要提一個UOS特有的前置條件**UOS有比較嚴格的安全中心未在應用商店上架的deb包在安裝時可能被攔截或提示不受信來源)。建議在控制中心的“通用—開發(fā)者模式”里按統(tǒng)信官方流程開啟開發(fā)者模式。這不是可有可無的操作我見過不少人在這一步卡住dpkg安裝了但文件被安全策略擋在外面Anbox服務怎么起都失敗。5.2 開啟容器管理服務并檢查journalctldeb包安裝完成之后系統(tǒng)里會多出一個anbox-container-manager服務這個服務負責真正把Android的rootfs跑起來。先把它設為開機自啟sudo systemctl enable --now anbox-container-manager systemctl status anbox-container-manager看到狀態(tài)不是active (running)先不要急著配置畫面用journalctl看日志journalctl -u anbox-container-manager -e我實測中最高頻的報錯就幾種找不到/dev/binder、權限不夠、/var/lib/anbox下的rootfs沒有生成。前面內(nèi)核部分處理好了第一種基本不會出現(xiàn)第二種大概率是udev規(guī)則沒生效第三種則在重裝一次deb包后可以解決。容器服務正常后再啟動圖形會話anbox session-manager 如果這一步安靜地待在后臺沒有報錯說明Anbox已經(jīng)成功連接上了Android系統(tǒng)。如果報錯繼續(xù)看終端的輸出日志通常信息比systemd日志更直接。5.3 UOS安全策略對anbox的額外限制UOS的安全基線做得比普通Debian嚴格不少具體到Anbox身上我踩過的一個坑是systemd服務執(zhí)行時被設備訪問策略擋住。日志里可能會出現(xiàn)關于DevicePolicy或類似的關鍵字這表明systemd的沙箱配置限制了容器服務訪問設備節(jié)點。遇到這種情況不要急著去關UOS的安全保護可以用systemd的drop-in來針對性放行sudo systemctl edit anbox-container-manager在打開的編輯器里根據(jù)journalctl提示的策略類型填入對應的放開配置保存后重啟服務。如果日志里提到了AppArmor那就單獨對anbox相關的profile使用aa-complain切換為警告模式觀察效果。其實大多數(shù)情況下根本不需要改這些安全策略問題還是出在前面說的設備節(jié)點和權限上。所以我一直強調(diào)先確保/dev/binder和/dev/ashmem對普通用戶都可用再去看安全策略這個順序不要顛倒。6. 把APK裝進Anbox并真正跑起來ADB、圖形與共享目錄6.1 通過adb把APK推進容器Anbox跑起來后最直接的安裝APK方式是ADB。UOS如果不帶adb先裝sudo apt install adb然后連接Anbox暴露出來的本地ADB端口adb connect localhost:5555 adb devices如果連接成功adb devices會顯示一臺設備。如果連接后過一會又lost大概率是sandbox和session-manager之間斷了回看第5章的日志排查。連接穩(wěn)定后安裝APK就一行命令adb install 你的應用.apk安裝大體積APK時偶爾會遇到timeout可以把安裝方式拆開先推送再在設備內(nèi)安裝adb push 你的應用.apk /data/local/tmp/ adb shell pm install /data/local/tmp/你的應用.apk這種方法比單純的adb install穩(wěn)定不少尤其是幾十MB以上的安裝包。6.2 APK架構(gòu)和Android版本帶來的兼容性限制APK裝進去了不代表能打開兼容性問題是Anbox用戶最需要心理準備的部分。Anbox官方鏡像是x86_64架構(gòu)的Android 7所以優(yōu)先下載x86或x86_64版本APK?,F(xiàn)在很多應用商店默認下發(fā)arm64包裝進去之后啟動時“直接閃退”或報“無法執(zhí)行二進制文件”多半就是這個原因。依賴Google Play服務的APP基本沒戲。Anbox鏡像不帶GMS應用只要調(diào)用了Google服務接口簡單點的還能報個錯復雜點的直接卡開機動畫。Android 7以下的舊應用反而更容易兼容因為它們當時就是照著Android 6/7的API寫的。如果你確實需要跑一個arm64-only的應用也可以搜索社區(qū)里針對Anbox修改的arm轉(zhuǎn)譯方案但這套方案在Android 7上的可用性一般屬于進階玩法文章里不展開介紹。6.3 窗口尺寸、文件傳輸和性能優(yōu)化Anbox默認啟動后是一個豎屏手機窗口在辦公顯示器上顯得很小。分辨率可以通過session-manager的支持參數(shù)調(diào)整不同版本參數(shù)大同小異先用anbox session-manager --help看看當前版本支持哪些選項再按需設置。我自己的習慣是把它調(diào)成接近手機的中等窗口而不是強行拉滿全屏因為Anbox的圖形性能上限不高拉滿只會讓畫面更卡。文件傳輸方面Anbox沒有模擬器那種“共享宿主目錄”的便利功能日常文件交換基本靠ADBadb push ./files/ /sdcard/ adb pull /sdcard/文件 ./桌面/性能優(yōu)化我提三個可行的方向。一是如果宿主機GPU驅(qū)動較弱部分應用會白屏或渲染異常設置環(huán)境變量LIBGL_ALWAYS_SOFTWARE1能有效避開GPU驅(qū)動坑代價是圖形性能進一步下降二是在Anbox系統(tǒng)里關閉窗口動畫安裝完應用后執(zhí)行adb shell settings put global window_animation_scale 0 adb shell settings put global transition_animation_scale 0 adb shell settings put global animator_duration_scale 0三是如果發(fā)現(xiàn)Anbox進程吃內(nèi)存太多可以在systemd服務的drop-in文件里加上MemoryMax限制避免它把宿主機內(nèi)存占光導致整個桌面露餡。性能調(diào)整沒有銀彈具體壓到什么值需要邊觀察任務管理器邊調(diào)。整套流程走完我最想強調(diào)的還是開頭那句話Anbox最麻煩的從來不是Anbox本身而是它依賴的內(nèi)核能力和UOS默認配置之間的差異。只要binder和ashmem兩個設備能在系統(tǒng)里穩(wěn)定存在、權限正確后面的container-manager、session-manager、adb install基本都會一路順利。反過來說如果內(nèi)核這一步?jīng)]做扎實裝再多次deb包也是白搭。我在UOS上跑通這套流程之后目前最常用的場景是把一個老舊的設備管理工具APP放進Anbox里日常打卡用占用很小開機自啟后幾乎無感。如果你也用UOS當主力桌面系統(tǒng)手上恰好有一兩個“只能在安卓上跑”的剛需應用Anbox值得抽一個下午認真折騰一次。內(nèi)核編譯等待的那段時間雖然枯燥但換來的是干凈、輕量、可控的安卓子環(huán)境這筆賬在辦公場景下是劃算的。