본문 바로가기
AndroidOverLinux

AoL IOT rootfs 빌드 스크립트

by ㅋㅋ잠자 2020. 11. 15.
반응형

안녕하세요?


IOT 서비스들만 테스트 목적으로 돌려 볼 수 있도록 제작한 buildroot 입니다.


스크립트는 수정에 수정을 가한 부분으로 약간 일관성이 매우 떨어지는 부분도 있습니다.



이전에, AoL U5PVR 에 탑재하면서 초기에 이미지를 debootstrap 으로 한번 만들고 그 이후에는 패치만 진행하였기 때문에 ... 실제로 그때 어떤 패치들이 들어갔는지 메모를 해두었어야 했는데 메모가 없다보니.. 기억을 복구하는데에 시간이 많이 걸렸네요.


근 3~4일 동안 이것만 매달린것 같습니다.


@eddylab-aol


(로고는 매우 대충 만들어서 죄송합니다.)


1. 기본 개념 및 잡설


이 개념은 linux deploy 나 termux 와 동일한 개념을 사용하고 있습니다.


그런데 termux 의 경우 proot 을 사용하여 root 권한 (시스템 권한)을 가지지 못하는 단점이 있습니다. 제일 크게 다가오는 부분이 포트를 1024 이하로 열 수 없다는 점입니다.


안드로이드에서는 SELINUX 가 있어서 root 권한을 획득하기가 매우 어렵고, 특히 Android TV 인증을 받으려면 SELINUX 부분을 빡세게 적용해주어야합니다.


이상한 SELINUX 설정이 들어가 있을 경우 CTS 인증을 통과하지 못하기 때문에 AndroidTV 에서는 작업하기가 어렵습니다.


쉴드야 리커버리를 통해 루팅이 가능하고 복구도 가능하기 때문에 좋은 플랫폼이라고 볼 수 있죠.



그렇다 보니 일단 U5의 경우 ROOT 기능이 열려있고, 현재 ATV8의 경우에도 일부분 열려있기 때문에 동작이 가능해진 부분이 있습니다. 이걸 만약에 인증을 받았다면 절대로 AoL 은 성공하지 못했을 것입니다.


그럼 기본 개념에 대해서 알아보겠습니다.


저희 리눅스 커널은 부팅할 때 작은 램디스크를 가지고 있습니다. 구조는 하기와 같습니다.

(안드로이드와 구조가 조금 다릅니다.)


/

/dev

/proc

/sys

/switch_root

/sbin

/init


램디스크는 커널 이미지에 압축되어 들어가며, 아무리 커도 armhf / arm64 커널 이미지는 대부분 16MB 를 넘지 않습니다.


여기서 아마도 /sbin/busybox 가 필요한 애플릿만을 이용하여 들어있을 것이고, /switch_root 에는 /init 에 작성된 스크립트를 통해 switch_root 에 EMMC 의 특정 파티션을 마운트 할 것 입니다. 이게 저희가 리눅스 부팅 후, 보는 rootfs 와 같습니다.


init 스크립트는 일단 mount -t dev dev /dev 등의 명령으로 /dev /proc /sys 를 마운트 하고 /switch_root 에 EMMC 의 rootfs 를 마운트 합니다. (ex: /dev/mmcblk0p1)


그리고 마운트가 끝나면 /dev /proc /sys 를 언마운트 하고 switch_root 애플릿을 통해 chroot 와 비슷하게 EMMC의 rootfs 로 들어가서 EMMC 내부의 /init 을 실행합니다.


이 init 파일은 systemd 와 연관이 되어 있음으로 이 systemd 는 다시 switch_root 내부의 /dev /sys /proc 등 필요한 파일 시스템을 마운트 하고 systemd 에 정의된 타겟을 타면서 서비스들을 로딩합니다.


그리고 chroot 는 경로를 독립하여 운용하는 것으로 실제 리눅스에서 개발 운영체제 버전이 호스트 운영체제와 다를 때 많이 사용하는 부분이 있습니다.


리눅스 커널과 안드로이드 커널은 거의 비슷하며, 리눅스 커널 + 안드로이드 전용 드라이버 + 안드로이드 오픈소스 프로젝트의 커널 패치 이게 포함된 것이 안드로이드 커널입니다.


즉, 안드로이드 커널로도 리눅스 부팅을 할 수 있습니다.


chroot 를 할 경우에는 호스트에 mount 애플릿이 있어야 하며 chroot 할 타겟 디렉터리에 호스트의 /dev /sys /proc 등을 바인드하고 chroot $CHROOT_DIR $COMMAND 이런식으로 환경에 진입하게 됩니다.


이 부분을 구현한 것이 Android Over Linux 입니다.


별것 아닌 기술로 만들어 낸 것이며, 이제는 스크립트를 github에 공개함으로 써 누구나 이 프로젝트를 관리할 수 있고 개발할 수 있으며, 관심이 있는 분들이 이 스크립트를 보고 대략적으로 영감을 얻을 수 있으면 좋을 것 같습니다.


https://github.com/eddylab-aol/aol_iot_buildroot


2. docker 가 안되면 chroot 로 비비자


일단 충분히 안드로이드 시스템에서 docker 를 구동할 수 있다는 것은 증명이 된 상태입니다.


그런데 이런 상태에서 ATV 인증은 절대 받지 못하는 부분은 ... 음 어쩔 수 없습니다.


1. 관련된 커널 모듈을 패치하고

2. 따로 rootfs 를 두지 않기 위해서 dockerd containerd docker 등을 NDK로 컴파일하여 system 파티션에 내장합니다.

3. init.rc 를 수정하여 /sys/cgroup 에 파일시스템이 정상적으로 마운트 될 수 있도록 수정합니다.


상기 과정을 거치면 docker 를 충분히 사용할 수 있습니다.


물론 완벽하게 사용은 하지 못할 것이지만, 저희가 사용하는 범위 내에서는 문제 없이 작동이 될 것 입니다.


일단 이전에 AoL 을 17년도에 처음 구상할 때, docker 바이너리만 /system 에 내장하고

사용자가 AoL 설치를 누르면 docker pull 을 통해서 AoL 컨테이너를 받아서 실행하는 수준의 정도로 생각을 했었지만, 이런 저런 문제로 성공하지는 못하였습니다.


그래서 일단 homeassistant 나 z2m 그리고 z2m-assistant 의 경우에는 docker rootfs 이미지를 다운받아서 /opt 에 배치하고 chroot 를 통해 docker 비슷한 효과를 내려고 스크립트를 작성하였습니다.


그렇다면, docker 컨테이너 실행 시 내부구조 파악을 통해 알아낸 부분은 아래와 같습니다.

docker file 에는 entry point 라는 것이 있기 때문에 그것만 정확히 봐도 컨테이너가 실행 시, 어떤 명령을 수행하며 실행되는지 체크는 쉽게 하실 수 있습니다.


homeassistant / z2m / z2m-assistant 로 /opt 에 풀어 두었다면 하기와 같습니다.


root@AOL-Debian:/opt# tree -L 2

.

├── hass

│   ├── bin

│   ├── config

│   ├── dev

│   ├── etc

│   ├── home

│   ├── init

│   ├── lib

│   ├── libexec

│   ├── media

│   ├── mnt

│   ├── opt

│   ├── proc

│   ├── root

│   ├── run

│   ├── sbin

│   ├── srv

│   ├── sys

│   ├── tmp

│   ├── usr

│   └── var

├── z2m

│   ├── app

│   ├── bin

│   ├── dev

│   ├── etc

│   ├── home

│   ├── lib

│   ├── media

│   ├── mnt

│   ├── opt

│   ├── proc

│   ├── root

│   ├── run

│   ├── sbin

│   ├── srv

│   ├── sys

│   ├── tmp

│   ├── usr

│   └── var

└── z2m-assistant

    ├── app

    ├── bin

    ├── boot

    ├── dev

    ├── etc

    ├── home

    ├── lib

    ├── media

    ├── mnt

    ├── opt

    ├── proc

    ├── root

    ├── run

    ├── sbin

    ├── srv

    ├── sys

    ├── tmp

    ├── usr

    └── var


아.. 실제로 실행하는 데에는 저렇게 많은 폴더구조가 필요없는데... 실제로 설치하는 것보다 편하게 진행되니 이렇게 구성하게 되었습니다.


그럼 docker 에서는 상기 처럼 필요없는 폴더들은 어떻게 용량을 감소시키냐... 이런 부분은 overlayfs 등을 활용하여 공통으로 쓰는 부분은 한개 파일로 같이 쓰고 변동이 있는 부분만 따로 가져가는 방식을 사용하고 있습니다.


일단은 homeassistant 의 경우 하기와 같이 실행이 가능합니다.


mount -o bind /dev /opt/hass/dev

mount -o bind /proc /opt/hass/proc

mount -o bind /sys /opt/hass/sys

mount -o bind /data/media/0/hass /opt/config


chroot /opt/hass /bin/sh /etc/services.d/home-assistant/run


이런식으로 실행이 가능합니다.


이런 스크립트의 내용은 하기 URL을 참고하시면 제가 어떻게 실행했는지 확인하실 수 있습니다.


https://github.com/eddylab-aol/aol_iot_buildroot/blob/master/services/homeassistant/files/hass.sh


https://github.com/eddylab-aol/aol_iot_buildroot/blob/master/services/zigbee2mqtt-assistant/files/z2m-assistant.sh


https://github.com/eddylab-aol/aol_iot_buildroot/blob/master/services/zigbee2mqtt/files/z2m.sh


3. cdc-acm 드라이버


일단 직비를 사용하기 위해서는 커널 defconfig 에서 cdc-acm 을 enable 해줘야 사용이 가능합니다.



경우에 다라서는 ueventd.rc 파일을 수정해서 mknod 로 /sys 의 장치를 /dev 에 올려줄 수 있도록 설정을 변경해야합니다.



(사진은 어디서 퍼왔습니다. 제가 커널 컴파일 할 환경을 집에 만들어 두지 않았습니다.)


U5 에 커널 모듈이 로드되어 정상적으로 보이는 부분은 아래와 같습니다.


[    5.918853] cdc_acm 2-1:1.0: ttyACM0: USB ACM device                                                


root@AOL-Debian:/opt# ls /dev | grep ttyACM

ttyACM0


4. buildroot.sh


이 게시글에 적혀있는 github 주소를 git clone 해 보시면 하기와 같습니다. 우분투나 데비안 시스템에서 이미지 생성이 가능합니다.


https://github.com/eddylab-aol/aol_iot_buildroot


buildroot.sh 를 실행시키면 마지막에 linux.tar- 파일이 생성됩니다.


root@debian10:~/aol_iot_buildroot# ./buildroot.sh

[BUILDROOT] ### Android Over Linux buildroot script

[BUILDROOT] ### You should run this script debian/ubuntu based OS

[BUILDROOT] ### cleanup buildroot...

[BUILDROOT] ### install dependent packages...

Hit:1 http://deb.debian.org/debian buster InRelease

Hit:2 http://deb.debian.org/debian buster-updates InRelease

Hit:3 http://security.debian.org/debian-security buster/updates InRelease

Reading package lists... Done

Building dependency tree

Reading state information... Done

14 packages can be upgraded. Run 'apt list --upgradable' to see them.

Reading package lists... Done

Building dependency tree

Reading state information... Done

binfmt-support is already the newest version (2.2.0-2).

binutils is already the newest version (2.31.1-16).

debootstrap is already the newest version (1.0.114).

qemu-user-static is already the newest version (1:3.1+dfsg-8+deb10u8).

The following packages were automatically installed and are no longer required:

  libev4 libuv1 libwebsockets8

Use 'apt autoremove' to remove them.

0 upgraded, 0 newly installed, 0 to remove and 14 not upgraded.

update-binfmts: warning: qemu-arm already enabled in kernel.

[BUILDROOT] ### make debian10 buster /root/aol_iot_buildroot/rootfs...

[BUILDROOT] ### rootfs directory /root/aol_iot_buildroot/rootfs...

I: Retrieving InRelease

I: Retrieving Packages

I: Validating Packages

..................................................................................

### install zigbee2mqtt...

perl: warning: Setting locale failed.

perl: warning: Please check that your locale settings:

        LANGUAGE = (unset),

        LC_ALL = (unset),

        LANG = "en_US.UTF-8"

    are supported and installed on your system.

perl: warning: Falling back to the standard locale ("C").

### install zigbee2mqtt-assistant...

perl: warning: Setting locale failed.

perl: warning: Please check that your locale settings:

        LANGUAGE = (unset),

        LC_ALL = (unset),

        LANG = "en_US.UTF-8"

    are supported and installed on your system.

perl: warning: Falling back to the standard locale ("C").

### install homeassistant...

perl: warning: Setting locale failed.

perl: warning: Please check that your locale settings:

        LANGUAGE = (unset),

        LC_ALL = (unset),

        LANG = "en_US.UTF-8"

    are supported and installed on your system.

perl: warning: Falling back to the standard locale ("C").

[BUILDROOT] ### install services finished...

[BUILDROOT] ### clean apt cache...

Reading package lists... Done

Building dependency tree

Reading state information... Done

[BUILDROOT] ### prepare to make images...

[BUILDROOT] ### make rootfs.tar.gz ...

tar: Removing leading `/' from member names

tar: Removing leading `/' from hard link targets

[BUILDROOT] ### make linux.tar...

tar: Removing leading `/' from member names

[BUILDROOT] ### buildroot routine finished...


root@debian10:~/aol_iot_buildroot# ls -1

buildroot

buildroot.sh

connect.sh

linux.tar-20201115-054128

README.md

rootfs

rootfs.tar.gz

services

upload.sh


update.zip 을 만드는 부분은 공개가 불가능한 부분이 있어서 공개하지 않습니다.


일단 U5 에서는 차후에 이 이미지가 반영이 된다면, 시스템적으로 /sdcard/linux.tar 파일이 있으면 업데이트가 되도록 구성할 예정입니다.


(용량을 위해 bz 압축이나 gz 압축이 들어갈 가능성 큽니다.)


그리고 U5 자체적으로 AoL 을 INIT 할 때 하기의 스크립트를 사용해서 환경을 초기화 하고 AoL 을 부팅시킵니다.


https://github.com/eddylab-aol/aol_iot_buildroot/blob/master/buildroot/init.ghost.linux


5. 서비스 스크린샷


Z2M 의 경우 USB 장치가 붙어있지 않으면 계속 죽어버리는 문제가 있습니다.


U5 의 경우 재부팅 시 USB 장치가 RESET 이 제대로 안되는지 인식이 안되는 경우가 있습니다.


(이전에 DAC 을 재부팅 후 인식할 수 없는 것과 비슷합니다.)



일단 정상적으로 부팅이 된다면 mqtt 서버가 먼저 실행되고 그 다음 z2m 이 실행되는 순서로 실행되며, 문제 없이 HomeAssistant 와 Zigbee2Mqtt 그리고 Zigbee2Mqtt Assistant 가 사용이 가능합니다.


HomeAssistant : 8123

Zigbee2Mqtt Assistant : 8124







6. HASS IO


실제로 상기처럼 HASS CORE 버전보다 HASS IO 가 좋겠지만.. 이게 docker 가 만약에 U5에서 잘 돌더라도

몇가지 필요 사항을 HASS IO 에 맞추려면 쉽지가 않을 것으로 보입니다.


일단은 HomeAssistant Core + Zigbee2Mqtt 로만으로도 많은 것들을 할 수 있고..


제가 그렇게 사용하면서 크게 문제가 없이 사용중입니다.









간단하게 중간 리포트 마칩니다.


감사합니다.



반응형

댓글