本文基于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 获取图片数据 然后传递出来 

最后上两张完成的图

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐