Android/Framework

Android HAL 레이어에서 Native Library 및 커널 드라이버 연동

임베디드 친구 2025. 3. 27. 10:00
728x90
반응형

Android HAL 레이어에서 Native Library 및 커널 드라이버 연동

1. 개요

Android 하드웨어 추상화 계층(HAL, Hardware Abstraction Layer)은 애플리케이션과 하드웨어 간의 인터페이스 역할을 수행합니다. HAL을 통해 Android 프레임워크는 하드웨어에 직접 접근하는 것이 아니라 표준화된 API를 사용하여 장치를 제어할 수 있습니다.

이번 글에서는 HAL 레이어에서 Native Library 및 커널 드라이버와의 연동 방법을 설명합니다. 또한, AOSP(Android Open Source Project) 코드 예제를 통해 실제 구현 방식도 살펴보겠습니다.


2. HAL과 Native Library, 커널 드라이버의 관계

Android의 하드웨어 접근 구조는 일반적으로 다음과 같은 계층으로 나뉩니다:

[ 애플리케이션 ]
     ↓
[ Android Framework (Java/Kotlin)]
     ↓
[ JNI (Java Native Interface)]
     ↓
[ Native Library (C/C++) ]
     ↓
[ HAL (C/C++) ]
     ↓
[ 커널 드라이버 (Linux Kernel)]

각 계층의 역할은 다음과 같습니다:

  • 애플리케이션: Android SDK를 이용하여 하드웨어 기능을 호출합니다.
  • Framework: 하드웨어와의 직접적인 연동 없이 Java API를 통해 HAL을 호출합니다.
  • JNI: Java 코드에서 C/C++ 코드(Native Library)를 호출하는 인터페이스 역할을 합니다.
  • Native Library: HAL을 보조하며, 공통 기능을 제공하는 C/C++ 라이브러리입니다.
  • HAL: 하드웨어의 제어를 담당하는 C/C++ 코드로 구성된 계층입니다.
  • 커널 드라이버: 실제 하드웨어와 통신하는 Linux 커널 모듈입니다.

3. HAL에서 Native Library 연동

HAL에서 Native Library를 사용하는 이유는 공통적으로 사용되는 기능을 별도의 라이브러리로 분리하여 코드의 재사용성과 유지보수성을 높이기 위함입니다.

3.1 Native Library 연동 방식

Native Library는 일반적으로 Android.bp 또는 Android.mk 파일에서 정의됩니다. HAL에서 이를 참조하여 빌드할 수 있습니다.

1) Native Library 정의 (Android.bp)

cc_library_shared {
    name: "libexample",
    srcs: ["example.c"],
    shared_libs: ["liblog"],
    cflags: ["-Wall"],
}

2) HAL에서 Native Library 사용 (Android.bp)

cc_library_shared {
    name: "android.hardware.example@1.0-impl",
    srcs: ["example_hal.cpp"],
    shared_libs: ["libexample"],
    cflags: ["-Wall"],
}

3) HAL 코드에서 Native Library 호출 (C++)

#include <example.h>

void example_function() {
    example_lib_function();
}

이렇게 하면 HAL이 libexample.so를 동적으로 로드하여 사용할 수 있습니다.


4. HAL과 커널 드라이버 연동

HAL은 직접 하드웨어를 제어할 수 없기 때문에 Linux 커널 드라이버를 통해 접근합니다. 일반적으로 ioctl, sysfs, devfs 등을 이용하여 드라이버와 통신합니다.

4.1 커널 드라이버 인터페이스

커널 드라이버는 /dev 디렉터리에 디바이스 파일을 생성하거나 sysfs 인터페이스를 통해 데이터에 접근할 수 있도록 합니다.

1) 커널 드라이버 코드 예제 (C)

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>

#define DEVICE_NAME "example_device"

static int example_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Example device opened\n");
    return 0;
}

static struct file_operations fops = {
    .open = example_open,
};

static int __init example_init(void) {
    int major = register_chrdev(0, DEVICE_NAME, &fops);
    printk(KERN_INFO "Example device registered with major number %d\n", major);
    return 0;
}

static void __exit example_exit(void) {
    printk(KERN_INFO "Example device unregistered\n");
}

module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE("GPL");

4.2 HAL에서 커널 드라이버 접근

HAL에서 커널 드라이버를 접근하는 방법은 파일 인터페이스(/dev/example_device)를 열고 ioctl이나 read/write를 호출하는 방식이 일반적입니다.

1) HAL에서 드라이버 파일 접근 (C++)

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

#define DEVICE_PATH "/dev/example_device"

void access_kernel_driver() {
    int fd = open(DEVICE_PATH, O_RDWR);
    if (fd < 0) {
        printf("Failed to open device file\n");
        return;
    }

    char buffer[128];
    read(fd, buffer, sizeof(buffer));
    printf("Data from driver: %s\n", buffer);

    close(fd);
}

위 코드를 통해 /dev/example_device에 접근할 수 있으며, 커널 드라이버에서 제공하는 기능을 HAL에서 활용할 수 있습니다.


5. 결론

Android의 HAL은 Native Library 및 커널 드라이버와 밀접한 연관이 있습니다.

  • Native Library는 코드의 재사용성과 유지보수성을 위해 HAL에서 동적으로 로드하여 사용됩니다.
  • HAL은 커널 드라이버를 통해 하드웨어를 제어하며, 파일 인터페이스(/dev), ioctl, sysfs 등을 활용하여 데이터를 주고받습니다.

AOSP에서는 HAL과 Native Library, 커널 드라이버 간의 연동이 체계적으로 구성되어 있으므로, 프로젝트 개발 시 AOSP 코드를 참고하여 구조를 이해하는 것이 중요합니다.

앞으로도 HAL 개발을 진행할 때, Native Library와 커널 드라이버와의 인터페이스를 명확하게 정의하고 관리하는 것이 핵심적인 부분이 될 것입니다.

728x90
반응형