android linux 雙系統實現(android+buster)同時運行

本文基於lxc 容器在安卓系統中運行linux 兩個同時運行不需要重啓切換 

android 運行linux 有很多方案

1.chroot  需要root 

2.proot 不需要root

3.lxc 需要改造內核 需要並且需要root

三種方案網上都很多,像我之前在手機上編譯deepin 就是用到了 linux deploy ,編譯deepin armhf的時候也用了華爲內測的鯤鵬917 那速度爽到爆,可惜真正銷售的時候華爲發佈了鯤鵬920 ,920支持硬件浮點不支持軟浮點,我沒辦法使用chroot來構建一個armhf環境,所以直接用手機安裝了linux deploy來實現,手機現在的配置都是6G 8g 內存 這個配置買個服務器要很多錢,主要還是錢的問題有錢直接讓華爲單獨給你開個917 服務器,迴歸正題,大部分方案要顯示界面都是通過 vnc遠程或者xdsl方式,比較簡單安裝個apk就能解決。

本文使用lxc方案 natvice直接繪製到java層 使用的案例安卓版本爲7.1.2 linux版本debian buster  其他版本大同小異

閱讀這篇文章的前提 你必須有android 源碼 內核源碼 能自己編譯安卓系統,熟悉構建chroot linux

構建lxc linux debian 在ubuntu上 

安裝也很簡單 apt  install lxc 

lxc-create -t download -n debian10 -- --dist debian  --release "buster"

讓你選擇版本我使用的是rk3288 32位安卓 所以選擇了armhf

然後就通過chroot 大法 安裝x11 桌面環境

3288 是一個非常強悍的cpu 我直接安裝了deepin 桌面 雖然他很大 我已經努力精簡到了1.5G,如何將deepin移植到armhf 請看我其他博客我還爲他寫了一個專欄,需要的是耐心,deepin使用的kde 體積縮小很難,誰讓他漂亮呢,也支持一下國產桌面,精簡的完全可以使用xfce 或者lxde lxqt 等桌面 也是非常的穩定。

也有在linux上運行android 的anbox 方案,也是採用lxc 技術實現lxc 運行android我也嘗試過但是沒有成功運行在armhf 上,我在其他文章也寫過,在ubuntu amd64上能運行起來但是bug 成噸的傷害讓你無從下手讓其有希望成爲商用產品

項目的起因是因爲linux上資源的匱乏,很多軟件沒辦法使用要麼使用winne 但是這個我沒發現怎麼在arm32 位或者arm64位系統上使用,沒想到deepin竟然採用這種方案來運行windows程序

在安卓上運行lxc 我們可以通過mmap 將x11 的界面輸出到安卓,雖然代碼很簡單,但是我爲他閱讀了大量的知識來了解安卓圖形界面顯示的整個原理,及閱讀android surface surfacecontrol  surfaceflinger 關係的源碼,網上資料很多但是大部分都是寫android 4一下的,只能通過介紹對比源碼查看改變

我們創建一個安卓surfaceview程序

        SurfaceView surfaceview = (SurfaceView) findViewById(R.id.surfaceView);
        SurfaceHolder holder = surfaceview.getHolder();
        holder.addCallback(new SurfaceHolder.Callback(){
            @Override
            public void surfaceCreated(SurfaceHolder holder) {

                  linuxinit(holder.getSurface());

linuxinit 是將上層surfaceview創建的surface 通過so傳遞到 底層 

上層與natvice 層交互通過binder

我們傳遞surface 的時候 通過binder實質是傳遞一個IGraphicBufferProducer 下面是 so中的bidner客戶端 將收到的 surface 繼續往下傳遞

   Parcel data, reply;
 
        int transCode = 0;
        int writeInt = 0;
        int replyInt = 0;
         data.writeStrongBinder(IInterface::asBinder(surface->getIGraphicBufferProducer()));
        
        binder->transact(transCode, data, &reply);

 

編寫一個 binder服務器

用於接收

status_t onTransact(uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
    {
            //從parcel讀出一個binder對象
            sp<IBinder> binder(data.readStrongBinder());
            //Binder對象就是IGraphicBufferProducer類型的
            sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
            //new了一個Surface,構造函數的參數會帶上這個binder對象
            zwsurface = new Surface(gbp, true);
}

 爲了驗證效果我直接在natvice 層直接操作 surface 

                 ANativeWindow_Buffer outBuffer;
     zwsurface->lock(&outBuffer, NULL);
     ssize_t bpr = outBuffer.stride * 2;
     android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);
     zwsurface->unlockAndPost();

這是時候 安卓層apk 中的surface view 就顯示一個純色的顏色

類似於java上層用canvas 畫


                Canvas canvas = holder.lockCanvas();
                canvas.drawColor(Color.BLUE);  //隨便設置背景顏色
                holder.unlockCanvasAndPost(canvas);
            

現在natvice 層已經拿到了 surface 那我們就通過mmap將x11 界面 截圖傳遞或者直接socket  傳遞

我們在回顧一下剛纔的natvice 操作 

 ANativeWindow_Buffer outBuffer;申請內存空間

zwsurface->lock(&outBuffer, NULL); 鎖定內存空間

android_memset16((uint16_t*)outBuffer.bits, 0xF800, bpr*outBuffer.height);內存複製

zwsurface->unlockAndPost(); 釋放進行顯示

那我們就需要將x11 的圖形信息傳遞到ANativeWindow_Buffer 中即可

具體的可以取查閱maruos 實現

那麼我們就可以很方便的  將x11 界面數據傳遞過來

關於如何獲取x11 下的圖形數據我們又要熟悉xorg 框架

這裏國內的知識極少 對這一塊我也是學習各大國外源碼的操作一知半解,要學習xlib

主要是 XOpenDisplay 連接連接x server

XShmGetImage 獲取圖片數據 然後傳遞出來 

最後上兩張完成的圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章