반응형

Android.mk를 사용하는 vendor 파티션의 모듈이 system 파티션의 AIDL을 사용하는 예제를 소개합니다.
 

주어진 상황

- System 파티션: AIDL 인터페이스 제공 (ISystemService.aidl)
- Vendor 파티션: external/aaa 모듈이 AIDL 사용
- 빌드 시스템: Android.mk 사용

1. System 파티션 - AIDL 인터페이스 정의
frameworks/base/core/java/android/os/ISystemService.aidl

package android.os;

interface ISystemService {
    int getValue();
    void setValue(int value);
    String getStatus();
}


System의 Android.bp (AIDL 빌드)

// frameworks/base/Android.bp 일부
aidl_interface {
    name: "system-service-aidl",
    vendor_available: true,  // ← 중요! vendor에서 사용 가능
    srcs: [
        "core/java/android/os/ISystemService.aidl",
    ],
    stability: "vintf",  // vendor/system 간 안정적인 인터페이스
    backend: {
        java: {
            enabled: true,
        },
        cpp: {
            enabled: true,
        },
        ndk: {
            enabled: true,  // ← vendor는 보통 NDK 백엔드 사용
        },
    },
}


2. Vendor 파티션 - aaa 모듈 구현
external/aaa/Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := aaa
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true  # vendor 파티션에 설치

# C++ 소스 파일
LOCAL_SRC_FILES := \
    aaa_main.cpp \
    SystemServiceClient.cpp

# AIDL 생성 코드 포함 (중요!)
LOCAL_SHARED_LIBRARIES := \
    liblog \
    libutils \
    libbinder_ndk \
    system-service-aidl-V1-ndk  # ← AIDL 라이브러리 (NDK 백엔드)

# 또는 CPP 백엔드 사용 시:
# LOCAL_SHARED_LIBRARIES += system-service-aidl-V1-cpp

# AIDL 헤더 경로 (자동으로 포함되지만 명시적으로 추가 가능)
LOCAL_HEADER_LIBRARIES := \
    system-service-aidl-ndk_headers

# C++ 표준
LOCAL_CPPFLAGS := -std=c++17 -Wall -Werror

# Vendor Treble 호환성
LOCAL_VENDOR_MODULE := true

include $(BUILD_EXECUTABLE)
# 또는 라이브러리인 경우:
# include $(BUILD_SHARED_LIBRARY)


external/aaa/SystemServiceClient.h

#pragma once

#include <aidl/android/os/ISystemService.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>

using aidl::android::os::ISystemService;

class SystemServiceClient {
public:
    SystemServiceClient();
    ~SystemServiceClient();
    
    bool connect();
    int getValue();
    void setValue(int value);
    std::string getStatus();
    
private:
    std::shared_ptr<ISystemService> mService;
};


external/aaa/SystemServiceClient.cpp

#include "SystemServiceClient.h"
#include <android-base/logging.h>

SystemServiceClient::SystemServiceClient() : mService(nullptr) {
}

SystemServiceClient::~SystemServiceClient() {
}

bool SystemServiceClient::connect() {
    // System 서비스에 연결
    const std::string serviceName =
        std::string() + ISystemService::descriptor + "/default";
    
    ndk::SpAIBinder binder(
        AServiceManager_checkService(serviceName.c_str())
    );
    
    if (binder.get() == nullptr) {
        LOG(ERROR) << "Failed to get system service: " << serviceName;
        return false;
    }
    
    mService = ISystemService::fromBinder(binder);
    if (mService == nullptr) {
        LOG(ERROR) << "Failed to create service interface";
        return false;
    }
    
    LOG(INFO) << "Connected to system service successfully";
    return true;
}

int SystemServiceClient::getValue() {
    if (mService == nullptr) {
        LOG(ERROR) << "Service not connected";
        return -1;
    }
    
    int32_t value = 0;
    ndk::ScopedAStatus status = mService->getValue(&value);
    
    if (!status.isOk()) {
        LOG(ERROR) << "getValue failed: " << status.getMessage();
        return -1;
    }
    
    return value;
}

void SystemServiceClient::setValue(int value) {
    if (mService == nullptr) {
        LOG(ERROR) << "Service not connected";
        return;
    }
    
    ndk::ScopedAStatus status = mService->setValue(value);
    
    if (!status.isOk()) {
        LOG(ERROR) << "setValue failed: " << status.getMessage();
    }
}

std::string SystemServiceClient::getStatus() {
    if (mService == nullptr) {
        LOG(ERROR) << "Service not connected";
        return "";
    }
    
    std::string statusStr;
    ndk::ScopedAStatus status = mService->getStatus(&statusStr);
    
    if (!status.isOk()) {
        LOG(ERROR) << "getStatus failed: " << status.getMessage();
        return "";
    }
    
    return statusStr;
}


external/aaa/aaa_main.cpp

#include <android-base/logging.h>
#include <android/binder_process.h>
#include "SystemServiceClient.h"

int main(int argc, char** argv) {
    // Binder 스레드 풀 시작
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    ABinderProcess_startThreadPool();
    
    LOG(INFO) << "AAA module starting...";
    
    // System 서비스 클라이언트 생성
    SystemServiceClient client;
    
    if (!client.connect()) {
        LOG(ERROR) << "Failed to connect to system service";
        return 1;
    }
    
    // AIDL 메서드 호출
    LOG(INFO) << "Current value: " << client.getValue();
    
    client.setValue(42);
    LOG(INFO) << "Value set to 42";
    
    std::string status = client.getStatus();
    LOG(INFO) << "Status: " << status;
    
    // 계속 실행 (데몬인 경우)
    ABinderProcess_joinThreadPool();
    
    return 0;
}


3. SELinux 정책 (중요!)
external/aaa/sepolicy/aaa.te

type aaa, domain;
type aaa_exec, exec_type, vendor_file_type, file_type;

init_daemon_domain(aaa)

# Binder 사용
binder_use(aaa)

# System 서비스와 통신
binder_call(aaa, system_server)

# ServiceManager 접근
allow aaa servicemanager:binder call;
allow aaa system_service:service_manager find;

# 필요한 경우 추가 권한
allow aaa self:capability { net_admin };
vendor/your_vendor/sepolicy/file_contexts
/vendor/bin/aaa    u:object_r:aaa_exec:s0

 

4. 주의사항 및 체크리스트
■ AIDL 설정관련 확인해야할 부분
1. vendor_available: true
- System의 AIDL이 반드시 vendor_available: true 설정 필요
2. stability: "vintf"
- Vendor/System 간 안정적인 인터페이스 보장
3. NDK 백엔드 사용
- Vendor 모듈은 보통 NDK 백엔드 사용 (-ndk 접미사)
- CPP 백엔드도 가능하지만 NDK가 권장됨
4. 버전 관리
- AIDL 라이브러리 이름에 버전 포함: system-service-aidl-V1-ndk
- 최신 버전 사용: system-service-aidl-ndk (버전 생략 시)

■ Android.mk 설정관련 확인해야할 부분

# 필수 설정
LOCAL_PROPRIETARY_MODULE := true  # vendor 파티션
LOCAL_VENDOR_MODULE := true       # Treble 호환

# AIDL 라이브러리
LOCAL_SHARED_LIBRARIES += system-service-aidl-V1-ndk

# Binder NDK 라이브러리
LOCAL_SHARED_LIBRARIES += libbinder_ndk


■ 빌드 확인

# aaa 모듈만 빌드
m aaa

# vendor 이미지 빌드
m vendorimage

# 설치 확인
adb shell ls -l /vendor/bin/aaa

 
 
■  런타임 확인

# 실행
adb shell /vendor/bin/aaa

# 로그 확인
adb logcat | grep aaa

# SELinux denial 확인
adb logcat | grep avc | grep aaa

 

5. CPP 백엔드 사용 시 (대안)
NDK 대신 CPP 백엔드를 사용하려면:
# Android.mk

LOCAL_SHARED_LIBRARIES := \
    liblog \
    libutils \
    libbinder \
    system-service-aidl-V1-cpp  # ← CPP 백엔드


// 헤더 include

#include <android/os/ISystemService.h>
#include <binder/IServiceManager.h>

using android::os::ISystemService;
using android::sp;
using android::IBinder;

// 서비스 연결
sp<ISystemService> getService() {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("system_service"));
    return interface_cast<ISystemService>(binder);
}


6. 트러블슈팅
문제: "undefined reference to AIDL symbols"
해결: LOCAL_SHARED_LIBRARIES에 AIDL 라이브러리 추가 확인

문제: "service not found"
해결: System 서비스가 실제로 실행 중인지 확인
ServiceManager에 등록되었는지 확인: adb shell service list

문제: "permission denied (SELinux)"
해결: SELinux 정책에 binder_call 규칙 추가
 

AVC denial 로그 확인 후 필요한 권한 추가




 

 

Q. aaa모듈이 원래 C로 구성된 모듈이라면? CPP를 추가할 수 있나요?  -> YES
AIDL은 C++로 작성하고, 기존 C 코드는 그대로 유지하면서 C/C++를 혼용하면 C 모듈에 C++ 코드를 추가할 수 있습니다. 

1. Android.mk 수정 (C/C++ 혼용)
external/aaa/Android.mk

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := aaa
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true
LOCAL_VENDOR_MODULE := true

# C 소스 파일 (기존 코드)
LOCAL_SRC_FILES := \
    aaa_main.c \
    aaa_core.c \
    aaa_utils.c

# C++ 소스 파일 (AIDL 관련 신규 코드)
LOCAL_SRC_FILES += \
    SystemServiceClient.cpp \
    aidl_wrapper.cpp

# C와 C++ 모두 사용
LOCAL_CPP_EXTENSION := .cpp

# C++ 표준 설정
LOCAL_CPPFLAGS := -std=c++17 -Wall -Werror

# C 컴파일 플래그 (필요시)
LOCAL_CFLAGS := -Wall -Werror

# AIDL 및 Binder 라이브러리 (C++용)
LOCAL_SHARED_LIBRARIES := \
    liblog \
    libcutils \
    libutils \
    libbinder_ndk \
    system-service-aidl-V1-ndk

# C++STL 라이브러리 (필수!)
LOCAL_SHARED_LIBRARIES += libc++

# 헤더 경로
LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)/include

include $(BUILD_EXECUTABLE)




2. C/C++ 인터페이스 래퍼 작성
C 코드에서 C++ AIDL 코드를 호출하려면 C 인터페이스 래퍼가 필요합니다.
external/aaa/include/aidl_wrapper.h (C 헤더)

#ifndef AIDL_WRAPPER_H
#define AIDL_WRAPPER_H

#ifdef __cplusplus
extern "C" {
#endif

// C에서 사용할 불투명 핸들
typedef struct SystemServiceHandle SystemServiceHandle;

// C 인터페이스 함수들
SystemServiceHandle* system_service_connect(void);
void system_service_disconnect(SystemServiceHandle* handle);

int system_service_get_value(SystemServiceHandle* handle);
int system_service_set_value(SystemServiceHandle* handle, int value);
char* system_service_get_status(SystemServiceHandle* handle);
void system_service_free_string(char* str);

#ifdef __cplusplus
}
#endif

#endif // AIDL_WRAPPER_H


external/aaa/aidl_wrapper.cpp (C++ 구현)

#include "aidl_wrapper.h"
#include "SystemServiceClient.h"
#include <android-base/logging.h>
#include <cstring>
#include <cstdlib>

// C++에서만 보이는 구조체 정의
struct SystemServiceHandle {
    SystemServiceClient* client;
};

extern "C" {

SystemServiceHandle* system_service_connect(void) {
    SystemServiceHandle* handle =
        (SystemServiceHandle*)malloc(sizeof(SystemServiceHandle));
    
    if (handle == nullptr) {
        LOG(ERROR) << "Failed to allocate handle";
        return nullptr;
    }
    
    handle->client = new SystemServiceClient();
    
    if (!handle->client->connect()) {
        LOG(ERROR) << "Failed to connect to service";
        delete handle->client;
        free(handle);
        return nullptr;
    }
    
    return handle;
}

void system_service_disconnect(SystemServiceHandle* handle) {
    if (handle == nullptr) {
        return;
    }
    
    if (handle->client != nullptr) {
        delete handle->client;
    }
    
    free(handle);
}

int system_service_get_value(SystemServiceHandle* handle) {
    if (handle == nullptr || handle->client == nullptr) {
        LOG(ERROR) << "Invalid handle";
        return -1;
    }
    
    return handle->client->getValue();
}

int system_service_set_value(SystemServiceHandle* handle, int value) {
    if (handle == nullptr || handle->client == nullptr) {
        LOG(ERROR) << "Invalid handle";
        return -1;
    }
    
    handle->client->setValue(value);
    return 0;
}

char* system_service_get_status(SystemServiceHandle* handle) {
    if (handle == nullptr || handle->client == nullptr) {
        LOG(ERROR) << "Invalid handle";
        return nullptr;
    }
    
    std::string status = handle->client->getStatus();
    
    // C 문자열로 복사 (호출자가 해제 필요)
    char* result = (char*)malloc(status.length() + 1);
    if (result != nullptr) {
        strcpy(result, status.c_str());
    }
    
    return result;
}

void system_service_free_string(char* str) {
    if (str != nullptr) {
        free(str);
    }
}

} // extern "C"


external/aaa/SystemServiceClient.h (C++ 전용)

#ifndef SYSTEM_SERVICE_CLIENT_H
#define SYSTEM_SERVICE_CLIENT_H

#include <aidl/android/os/ISystemService.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <string>
#include <memory>

using aidl::android::os::ISystemService;

class SystemServiceClient {
public:
    SystemServiceClient();
    ~SystemServiceClient();
    
    bool connect();
    int getValue();
    void setValue(int value);
    std::string getStatus();
    
private:
    std::shared_ptr<ISystemService> mService;
};

#endif // SYSTEM_SERVICE_CLIENT_H


external/aaa/SystemServiceClient.cpp

#include "SystemServiceClient.h"
#include <android-base/logging.h>

SystemServiceClient::SystemServiceClient() : mService(nullptr) {
}

SystemServiceClient::~SystemServiceClient() {
}

bool SystemServiceClient::connect() {
    const std::string serviceName =
        std::string() + ISystemService::descriptor + "/default";
    
    ndk::SpAIBinder binder(
        AServiceManager_checkService(serviceName.c_str())
    );
    
    if (binder.get() == nullptr) {
        LOG(ERROR) << "Failed to get system service: " << serviceName;
        return false;
    }
    
    mService = ISystemService::fromBinder(binder);
    if (mService == nullptr) {
        LOG(ERROR) << "Failed to create service interface";
        return false;
    }
    
    LOG(INFO) << "Connected to system service successfully";
    return true;
}

int SystemServiceClient::getValue() {
    if (mService == nullptr) {
        LOG(ERROR) << "Service not connected";
        return -1;
    }
    
    int32_t value = 0;
    ndk::ScopedAStatus status = mService->getValue(&value);
    
    if (!status.isOk()) {
        LOG(ERROR) << "getValue failed: " << status.getMessage();
        return -1;
    }
    
    return value;
}

void SystemServiceClient::setValue(int value) {
    if (mService == nullptr) {
        LOG(ERROR) << "Service not connected";
        return;
    }
    
    ndk::ScopedAStatus status = mService->setValue(value);
    
    if (!status.isOk()) {
        LOG(ERROR) << "setValue failed: " << status.getMessage();
    }
}

std::string SystemServiceClient::getStatus() {
    if (mService == nullptr) {
        LOG(ERROR) << "Service not connected";
        return "";
    }
    
    std::string statusStr;
    ndk::ScopedAStatus status = mService->getStatus(&statusStr);
    
    if (!status.isOk()) {
        LOG(ERROR) << "getStatus failed: " << status.getMessage();
        return "";
    }
    
    return statusStr;
}


3. C 메인 코드에서 사용
external/aaa/aaa_main.c (기존 C 코드)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "aidl_wrapper.h"
#include "aaa_core.h"  // 기존 C 헤더

int main(int argc, char** argv) {
    printf("AAA module starting (C version)...\n");
    
    // 기존 C 코드 초기화
    aaa_core_init();
    
    // AIDL 서비스 연결 (C++ 래퍼 사용)
    SystemServiceHandle* service = system_service_connect();
    if (service == NULL) {
        fprintf(stderr, "Failed to connect to system service\n");
        return 1;
    }
    
    // AIDL 메서드 호출
    int current_value = system_service_get_value(service);
    printf("Current value: %d\n", current_value);
    
    system_service_set_value(service, 42);
    printf("Value set to 42\n");
    
    char* status = system_service_get_status(service);
    if (status != NULL) {
        printf("Status: %s\n", status);
        system_service_free_string(status);
    }
    
    // 기존 C 코드 로직
    while (1) {
        aaa_core_process();
        
        // 주기적으로 AIDL 호출
        current_value = system_service_get_value(service);
        printf("Updated value: %d\n", current_value);
        
        sleep(5);
    }
    
    // 정리
    system_service_disconnect(service);
    aaa_core_cleanup();
    
    return 0;
}


external/aaa/aaa_core.c (기존 C 코드 예제)

#include "aaa_core.h"
#include <stdio.h>

void aaa_core_init(void) {
    printf("AAA core initialized\n");
}

void aaa_core_process(void) {
    printf("AAA core processing...\n");
    // 기존 로직
}

void aaa_core_cleanup(void) {
    printf("AAA core cleanup\n");
}


external/aaa/include/aaa_core.h

#ifndef AAA_CORE_H
#define AAA_CORE_H

#ifdef __cplusplus
extern "C" {
#endif

void aaa_core_init(void);
void aaa_core_process(void);
void aaa_core_cleanup(void);

#ifdef __cplusplus
}
#endif

#endif // AAA_CORE_H

 

4. 디렉토리 구조

external/aaa/
├── Android.mk
├── aaa_main.c           (C - 메인 엔트리)
├── aaa_core.c           (C - 기존 로직)
├── aaa_utils.c          (C - 기존 유틸리티)
├── aidl_wrapper.cpp     (C++ - C/C++ 브릿지)
├── SystemServiceClient.cpp  (C++ - AIDL 클라이언트)
├── include/
│   ├── aaa_core.h       (C 헤더)
│   ├── aaa_utils.h      (C 헤더)
│   ├── aidl_wrapper.h   (C 헤더, C++ 래퍼)
│   └── SystemServiceClient.h  (C++ 헤더)
└── sepolicy/
    └── aaa.te


5. 주의사항
■ 필수 설정
C++ STL 라이브러리
- LOCAL_SHARED_LIBRARIES += libc++
 
extern "C" 블록
- C 헤더에서 C++와 호환되도록 extern "C" 사용

메모리 관리
- C++에서 할당한 객체는 C++에서 해제
- C에서 할당한 메모리는 C에서 해제
- 문자열 전달 시 복사본 생성 및 명시적 해제 함수 제공
 
■ 링킹 순서
# C++ 라이브러리를 먼저 링크
LOCAL_SHARED_LIBRARIES := \
    libc++ \
    liblog \
    libutils \
    libbinder_ndk \
    system-service-aidl-V1-ndk \
    libcutils
 
■ 컴파일러 호환성

# C++ 확장자 명시
LOCAL_CPP_EXTENSION := .cpp

# C++17 사용
LOCAL_CPPFLAGS := -std=c++17

# C99 또는 C11 사용 (필요시)
LOCAL_CFLAGS := -std=c11


6. 빌드 및 테스트

# 빌드
m aaa

# 설치 확인
adb shell ls -l /vendor/bin/aaa

# 실행
adb shell /vendor/bin/aaa

# 로그 확인
adb logcat | grep -E "aaa|AAA"

 

7. 트러블슈팅
문제 1) "undefined reference to __cxa_*"
 
해결: C++ STL 라이브러리 추가
LOCAL_SHARED_LIBRARIES += libc++
 
문제 2) "symbol not found" (C/C++ 링킹 에러)

 
해결: extern "C" 확인

#ifdef __cplusplus
extern "C" {
#endif
// C 함수 선언
#ifdef __cplusplus
}
#endif


문제 3) "multiple definition"
해결: C 헤더가 C++에서 포함될 때 extern "C" 누락 확인






Q. startThreadPool을 사용하면 그러면 blocking 되지 않고 알아서 바인드 스레드가 생성되는 건가? -> YES

ABinderProcess_startThreadPool()을 호출하면:
즉시 리턴됨 (Non-blocking)
내부적으로 Binder 스레드가 자동 생성됨
메인 스레드는 계속 진행
동작 방식

int main() {
    printf("Step 1: Main thread starting\n");
    
    // AIDL 서버 등록
    aidl_server_init();
    
    // Binder 스레드 풀 시작 (Non-blocking!)
    ABinderProcess_setThreadPoolMaxThreadCount(4);
    ABinderProcess_startThreadPool();
    
    printf("Step 2: startThreadPool returned immediately!\n");
    // ↑ 여기까지 즉시 도달!
    // 백그라운드에서 Binder 스레드들이 이미 생성되어 돌아가는 중
    
    // 메인 스레드는 계속 실행
    int fd = open("/dev/device", O_RDWR);
    
    while (1) {
        // 여기서 블로킹해도 문제없음
        read(fd, buffer, size);  // ← 메인 스레드 블로킹
        
        // 동시에 Binder 스레드는 독립적으로 클라이언트 요청 처리 중!
    }
    
    return 0;
}


프로세스 내부 모습
aaa 프로세스
├── Main Thread
│   ├── main() 함수 실행
│   ├── read(fd) ← 블로킹
│   ├── aaa_core_process()
│   └── while(1) 루프

├── Binder Thread 1  ← startThreadPool()이 자동 생성
│   └── 클라이언트 요청 대기 및 처리

├── Binder Thread 2  ← startThreadPool()이 자동 생성
│   └── 클라이언트 요청 대기 및 처리

└── Binder Thread 3  ← startThreadPool()이 자동 생성
    └── 클라이언트 요청 대기 및 처리
 
 
startThreadPool() vs joinThreadPool()
startThreadPool() - Non-blocking

printf("Before startThreadPool\n");

ABinderProcess_startThreadPool();
// ↑ 여기서 즉시 리턴!

printf("After startThreadPool - I can see this!\n");
// ↑ 이 줄이 즉시 실행됨!

while (1) {
    read(fd, ...);  // 메인 스레드는 자유롭게 동작
}


내부 동작:

// startThreadPool() 내부 (단순화)
void ABinderProcess_startThreadPool() {
    for (int i = 0; i < maxThreadCount; i++) {
        pthread_create(&thread, NULL, binderThreadLoop, NULL);
        pthread_detach(thread);
    }
    // 즉시 리턴!
    return;
}
joinThreadPool() - Blocking
printf("Before joinThreadPool\n");

ABinderProcess_joinThreadPool();
// ↑ 여기서 블로킹! 프로세스 종료 전까지 리턴 안됨!

printf("After joinThreadPool - NEVER executed!\n");
// ↑ 이 줄은 절대 실행되지 않음!


내부 동작:

// joinThreadPool() 내부 (단순화)
void ABinderProcess_joinThreadPool() {
    while (true) {
        // 무한루프로 Binder 명령 처리
        processBinderCommands();
        // 절대 리턴 안함!
    }
}


실제 확인 방법
external/aaa/aaa_main.c (테스트 코드)

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include "aidl_server.h"

int main() {
    printf("[Main] Step 1: Starting\n");
    
    printf("[Main] Step 2: Initializing AIDL server\n");
    aidl_server_init();
    
    printf("[Main] Step 3: Calling startThreadPool\n");
    ABinderProcess_setThreadPoolMaxThreadCount(4);
    ABinderProcess_startThreadPool();
    
    printf("[Main] Step 4: startThreadPool returned! (Non-blocking confirmed!)\n");
    
    // 스레드 확인
    printf("[Main] Step 5: Sleeping 2 seconds to let threads start...\n");
    sleep(2);
    
    printf("[Main] Step 6: Entering main loop\n");
    
    int counter = 0;
    while (1) {
        printf("[Main] Main thread loop iteration %d\n", counter);
        
        // AIDL 서버 상태 업데이트 (백그라운드 스레드가 처리)
        aidl_server_update_value(counter);
        
        sleep(3);
        counter++;
        
        if (counter > 10) break;  // 테스트용
    }
    
    printf("[Main] Main loop finished normally!\n");
    
    return 0;
}


출력 예상:
[Main] Step 1: Starting
[Main] Step 2: Initializing AIDL server
[Main] Step 3: Calling startThreadPool
[Main] Step 4: startThreadPool returned! (Non-blocking confirmed!)
[Main] Step 5: Sleeping 2 seconds to let threads start...
[Main] Step 6: Entering main loop
[Main] Main thread loop iteration 0
[Main] Main thread loop iteration 1
[Main] Main thread loop iteration 2
...
[Main] Main loop finished normally!
 
프로세스/스레드 확인
# aaa 실행
adb shell /vendor/bin/aaa &

# 프로세스 확인
adb shell ps -T | grep aaa
출력 예:
USER      PID   PPID  VSIZE  RSS   WCHAN    PC        NAME
vendor    1234  1     12345  2048  binder_... 00000000 S aaa          ← Main thread
vendor    1234  1     12345  2048  binder_... 00000000 S Binder:1234_1 ← Binder thread 1
vendor    1234  1     12345  2048  binder_... 00000000 S Binder:1234_2 ← Binder thread 2
vendor    1234  1     12345  2048  binder_... 00000000 S Binder:1234_3 ← Binder thread 3
보시다시피 메인 스레드 외에 Binder 스레드들이 자동으로 생성되어 있습니다!
최종 정리
 

✅ startThreadPool() 사용 시
// 간단한 서버 초기화
aidl_server_init();
ABinderProcess_setThreadPoolMaxThreadCount(4);  // 최대 4개 스레드
ABinderProcess_startThreadPool();               // Non-blocking!

// 메인 로직은 그대로
while (1) {
    read(fd, ...);      // 메인 스레드 - 블로킹 OK
    process(...);
    aidl_server_update_value(...);  // 데이터 업데이트
}
// Binder 스레드는 백그라운드에서 독립적으로 클라이언트 요청 처리
❌ joinThreadPool() 사용 시
aidl_server_init();
ABinderProcess_startThreadPool();
ABinderProcess_joinThreadPool();  // ← 여기서 영원히 블로킹!

// 아래 코드는 절대 실행 안됨!
while (1) {
    read(fd, ...);  // NEVER REACHED!
}
따라서 기존 데몬에 AIDL 서버를 추가할 때는 startThreadPool()만 사용하면 됩니다. 별도로 pthread를 만들 필요도 없습니다!
// 이게 정답!
int main() {
    aidl_server_init();
    ABinderProcess_startThreadPool();  // ← 이것만!
    
    // 기존 코드 그대로
    while (1) {
        read(fd, buffer, size);
        // ...
    }
}







해당 aaa모듈에 대한 sepolicy를 작성해주세요. 이 모듈은 aaa.start 라는 property가 1이 될 때 실행됩니다. 이 모듈이 실행될때 adil 서비스도 구동하게 해주세요




aaa 모듈의 SELinux 정책을 작성해드리겠습니다. property 기반 실행과 AIDL 서비스 구동을 모두 포함합니다.
1. SELinux Policy 파일들
vendor/your_vendor/sepolicy/aaa.te

# aaa 데몬 타입 정의
type aaa, domain;
type aaa_exec, exec_type, vendor_file_type, file_type;

# init에서 실행되는 데몬
init_daemon_domain(aaa)

# Binder 사용 (AIDL 서버/클라이언트)
binder_use(aaa)

# ServiceManager 접근 (AIDL 서비스 등록)
allow aaa servicemanager:binder { call transfer };
allow aaa service_manager_type:service_manager { add find list };

# 자체 AIDL 서비스 등록
add_service(aaa, aaa_service)

# System 서비스와 통신 (AIDL 클라이언트)
binder_call(aaa, system_server)
allow aaa system_service:service_manager find;

# Property 읽기 (aaa.start property 확인)
get_prop(aaa, vendor_aaa_prop)
get_prop(aaa, system_prop)

# 로그 작성
allow aaa kmsg_device:chr_file write;
allow aaa vendor_shell_exec:file { execute execute_no_trans };

# 디바이스 파일 접근 (/dev/aaa_device)
type aaa_device, dev_type;
allow aaa aaa_device:chr_file rw_file_perms;

# 데이터 파일 접근 (/data/vendor/aaa)
type aaa_data_file, file_type, data_file_type;
allow aaa aaa_data_file:dir create_dir_perms;
allow aaa aaa_data_file:file create_file_perms;

# /sys 파일 시스템 접근 (필요한 경우)
allow aaa sysfs:dir r_dir_perms;
allow aaa sysfs:file rw_file_perms;

# /proc 파일 시스템 접근
allow aaa proc:file r_file_perms;

# 자기 자신에 대한 권한
allow aaa self:capability { net_admin sys_admin };
allow aaa self:process { sigkill signal };
allow aaa self:netlink_kobject_uevent_socket create_socket_perms;

# Unix 도메인 소켓
allow aaa aaa:unix_stream_socket { create_stream_socket_perms };

# 네트워크 사용 (필요한 경우)
# allow aaa self:tcp_socket create_stream_socket_perms;
# allow aaa self:udp_socket create_socket_perms;
# allow aaa node:tcp_socket node_bind;
# allow aaa port:tcp_socket name_bind;

# Tmpfs 접근 (필요한 경우)
allow aaa tmpfs:dir r_dir_perms;
allow aaa tmpfs:file rw_file_perms;

# Vendor 파일 읽기
allow aaa vendor_file:file { read open getattr execute };
allow aaa vendor_configs_file:file r_file_perms;

# 다른 vendor 서비스와 통신 (필요한 경우)
# binder_call(aaa, hal_vendor_service)
vendor/your_vendor/sepolicy/file_contexts
# aaa 실행 파일
/vendor/bin/aaa                         u:object_r:aaa_exec:s0

# aaa 디바이스 파일
/dev/aaa_device                         u:object_r:aaa_device:s0

# aaa 데이터 디렉토리
/data/vendor/aaa(/.*)?                  u:object_r:aaa_data_file:s0

# aaa 설정 파일 (있는 경우)
/vendor/etc/aaa(/.*)?                   u:object_r:vendor_configs_file:s0
vendor/your_vendor/sepolicy/service_contexts
# aaa AIDL 서비스
com.example.IAaaService/default         u:object_r:aaa_service:s0
vendor/your_vendor/sepolicy/service.te
# aaa 서비스 타입 정의
type aaa_service, service_manager_type, vendor_service;
vendor/your_vendor/sepolicy/property.te
# aaa property 타입 정의
type vendor_aaa_prop, property_type;
vendor/your_vendor/sepolicy/property_contexts
# aaa property 컨텍스트
aaa.                    u:object_r:vendor_aaa_prop:s0
persist.aaa.            u:object_r:vendor_aaa_prop:s0


2. Init RC 파일
vendor/your_vendor/etc/init/aaa.rc
# aaa 서비스 정의
service aaa /vendor/bin/aaa
    class late_start
    user vendor_aaa
    group vendor_aaa system
    seclabel u:r:aaa:s0
    disabled
    oneshot

# property 트리거
on property:aaa.start=1
    start aaa

on property:aaa.start=0
    stop aaa

# 부팅 시 초기화
on boot
    # aaa 디바이스 노드 생성 (필요한 경우)
    # mknod /dev/aaa_device c 10 50
    chown vendor_aaa vendor_aaa /dev/aaa_device
    chmod 0660 /dev/aaa_device
    
    # 데이터 디렉토리 생성
    mkdir /data/vendor/aaa 0770 vendor_aaa vendor_aaa
    restorecon_recursive /data/vendor/aaa

# 종료 시 정리
on shutdown
    stop aaa
3. 사용자/그룹 정의
system/core/libcutils/include/private/android_filesystem_config.h 수정
또는 vendor에서:
vendor/your_vendor/config/ueventd.rc
# aaa 디바이스 권한
/dev/aaa_device           0660   vendor_aaa   vendor_aaa
vendor overlay 방식 (권장)
device/your_vendor/your_device/config.fs 또는 시스템 설정에 추가:
[vendor/bin/aaa]
mode: 0755
user: AID_VENDOR_AAA
group: AID_VENDOR_AAA
caps: 0
4. system/sepolicy 연동 (필요시)
system 서비스와 통신이 필요한 경우:
system/sepolicy/public/aaa.te
# Public 타입 정의 (다른 도메인이 참조 가능)
type aaa, domain;
system/sepolicy/private/system_server.te
# system_server가 aaa와 통신 허용
binder_call(system_server, aaa)
5. 빌드 설정
vendor/your_vendor/sepolicy/Android.bp
soong_namespace {
}

prebuilt_etc {
    name: "aaa.rc",
    src: "aaa.rc",
    sub_dir: "init",
    vendor: true,
}
device/your_vendor/your_device/device.mk
# SEPolicy 추가
BOARD_VENDOR_SEPOLICY_DIRS += \
    vendor/your_vendor/sepolicy

# Init RC 추가
PRODUCT_PACKAGES += \
    aaa.rc

# aaa 바이너리 추가
PRODUCT_PACKAGES += \
    aaa
6. 테스트 및 디버깅
Property 설정 테스트
# aaa 서비스 시작
adb shell setprop aaa.start 1

# aaa 서비스 중지
adb shell setprop aaa.start 0

# 서비스 상태 확인
adb shell ps -A | grep aaa

# SELinux 컨텍스트 확인
adb shell ps -Z | grep aaa

# 서비스 등록 확인
adb shell service list | grep aaa
SELinux Denial 확인
# AVC denial 로그
adb logcat -b all | grep avc | grep aaa

# 또는
adb shell dmesg | grep avc | grep aaa
Denial 해결 방법
# audit2allow 사용
adb logcat -b events -d | audit2allow -p <policy_file>

# 예시 출력:
# allow aaa system_server:binder call;
# allow aaa aaa_service:service_manager add;
7. AIDL 서비스 확인
서비스 등록 확인
# 서비스 목록에서 aaa 확인
adb shell service list | grep IAaaService

# 출력 예:
# 123    com.example.IAaaService/default: [com.example.IAaaService]

# dumpsys로 상세 정보
adb shell dumpsys -l | grep aaa
서비스 호출 테스트
간단한 테스트 클라이언트:
# servicemanager를 통한 테스트
adb shell service call com.example.IAaaService/default 1  # getValue 호출
adb shell service call com.example.IAaaService/default 2 i32 42  # setValue(42) 호출
8. 트러블슈팅
문제 1: Permission denied (서비스 등록 실패)
# Denial 확인
adb logcat | grep "avc.*aaa.*service_manager"

# 해결: service.te와 service_contexts 확인
문제 2: Property 트리거 안됨
# Property 컨텍스트 확인
adb shell getprop -Z | grep aaa

# 출력이 vendor_aaa_prop이어야 함
# 아니면 property_contexts 재확인
문제 3: Binder 통신 실패
# Binder 권한 확인
adb logcat | grep "avc.*aaa.*binder"

# 해결: binder_use(aaa) 및 binder_call 규칙 추가
9. 완전한 예제 정리
최소 필수 파일 구조
vendor/your_vendor/sepolicy/
├── aaa.te                    # 주요 정책
├── file_contexts             # 파일 레이블
├── service_contexts          # 서비스 레이블
├── service.te                # 서비스 타입
├── property.te               # Property 타입
└── property_contexts         # Property 레이블

vendor/your_vendor/etc/init/
└── aaa.rc                    # Init 스크립트

external/aaa/
├── Android.mk                # 빌드 설정
├── aaa_main.c
├── aidl_server.cpp
└── sepolicy/                 # 로컬 sepolicy (optional)
    └── aaa.te
이제 setprop aaa.start 1을 실행하면 aaa 데몬이 시작되고 AIDL 서비스가 자동으로 등록됩니다!
추가 질문이나 특정 denial 에러가 있으면 알려주세요!








aaa모듈이 aidl서버 역할인 경우 sepolicy를 알려주세요. 위와 같습니까?


네, 기본적으로 위와 같지만, AIDL 서버 역할에 더 특화된 정책으로 조정하겠습니다. 클라이언트들이 aaa 서비스에 접근할 수 있도록 추가 설정이 필요합니다.
1. SELinux Policy (AIDL 서버 특화)
vendor/your_vendor/sepolicy/aaa.te
# aaa 데몬 타입 정의 (AIDL 서버)
type aaa, domain;
type aaa_exec, exec_type, vendor_file_type, file_type;

# init에서 실행되는 데몬
init_daemon_domain(aaa)

#####################################
# AIDL 서버 관련 권한
#####################################

# Binder 사용 (AIDL 서버 필수)
binder_use(aaa)

# ServiceManager 접근 (서비스 등록을 위해 필수!)
allow aaa servicemanager:binder { call transfer };

# 자체 서비스를 ServiceManager에 등록
allow aaa aaa_service:service_manager { add find };

# 다른 도메인들이 aaa 서비스를 찾을 수 있도록 허용
# (이 부분이 서버에서 중요!)
allow aaa service_manager_type:service_manager list;

# Binder 통신 - 클라이언트의 호출 수신
# (서버는 클라이언트로부터 call을 받음)
# 각 클라이언트 도메인별로 추가 필요
binder_call(system_server, aaa)      # system_server가 aaa 호출
binder_call(platform_app, aaa)       # platform_app이 aaa 호출
binder_call(priv_app, aaa)           # priv_app이 aaa 호출
binder_call(untrusted_app, aaa)      # 일반 앱이 aaa 호출 (필요시)

# vendor 앱들이 호출 가능하도록 (필요시)
binder_call(vendor_app, aaa)

#####################################
# 일반 데몬 권한
#####################################

# Property 읽기
get_prop(aaa, vendor_aaa_prop)
get_prop(aaa, system_prop)

# Property 쓰기 (상태 업데이트 등)
set_prop(aaa, vendor_aaa_prop)

# 로그 작성
allow aaa kmsg_device:chr_file write;

# 디바이스 파일 접근
type aaa_device, dev_type;
allow aaa aaa_device:chr_file rw_file_perms;

# 데이터 파일 접근
type aaa_data_file, file_type, data_file_type;
allow aaa aaa_data_file:dir create_dir_perms;
allow aaa aaa_data_file:file create_file_perms;

# /proc 접근
allow aaa proc:file r_file_perms;
allow aaa proc_net:file r_file_perms;

# /sys 접근 (필요한 경우)
allow aaa sysfs:dir r_dir_perms;
allow aaa sysfs:file rw_file_perms;
allow aaa sysfs_leds:dir r_dir_perms;
allow aaa sysfs_leds:file rw_file_perms;

# 자기 자신에 대한 권한
allow aaa self:capability { net_admin dac_override };
allow aaa self:process { sigkill signal setpgid };
allow aaa self:netlink_kobject_uevent_socket create_socket_perms;

# Unix 소켓
allow aaa aaa:unix_stream_socket create_stream_socket_perms;
allow aaa aaa:unix_dgram_socket create_socket_perms;

# 네트워크 사용 (필요한 경우)
# allow aaa self:tcp_socket create_stream_socket_perms;
# allow aaa self:udp_socket create_socket_perms;

# Vendor 파일 읽기
allow aaa vendor_file:file { read open getattr execute };
allow aaa vendor_configs_file:{ dir file } r_file_perms;

# Tmpfs 접근
allow aaa tmpfs:dir r_dir_perms;

# SELinux 파일 읽기 (서비스 등록 시 필요할 수 있음)
allow aaa selinuxfs:file r_file_perms;

#####################################
# AIDL 서버 특화 - 파일 디스크립터 전달
#####################################

# Binder를 통한 파일 디스크립터 전달 허용 (필요시)
# allow aaa app_data_file:file { read write getattr };
# allow aaa system_server:fd use;
vendor/your_vendor/sepolicy/service.te
# aaa 서비스 타입 정의 (AIDL 서비스)
type aaa_service, service_manager_type, vendor_service;
vendor/your_vendor/sepolicy/service_contexts
# aaa AIDL 서비스 (인터페이스 full path)
com.example.IAaaService/default         u:object_r:aaa_service:s0

# 또는 vendor prefix 사용
# vendor.example.IAaaService/default    u:object_r:aaa_service:s0
2. 클라이언트 측 정책 (중요!)
클라이언트들이 aaa 서비스를 사용할 수 있도록 각 클라이언트 도메인에 권한 추가:
system/sepolicy/private/system_server.te
# system_server가 aaa 서비스 사용
binder_call(system_server, aaa)
allow system_server aaa_service:service_manager find;
system/sepolicy/private/platform_app.te
# platform_app이 aaa 서비스 사용
binder_call(platform_app, aaa)
allow platform_app aaa_service:service_manager find;
system/sepolicy/private/priv_app.te
# priv_app이 aaa 서비스 사용
binder_call(priv_app, aaa)
allow priv_app aaa_service:service_manager find;
system/sepolicy/private/untrusted_app.te (일반 앱 허용 시)
# 일반 앱이 aaa 서비스 사용 (보안상 신중히 결정)
binder_call(untrusted_app, aaa)
allow untrusted_app aaa_service:service_manager find;
vendor/your_vendor/sepolicy/vendor_app.te (vendor 앱용)
# vendor 앱이 aaa 서비스 사용
type vendor_app, domain;
app_domain(vendor_app)

binder_call(vendor_app, aaa)
allow vendor_app aaa_service:service_manager find;
3. 양방향 Binder 통신 허용
vendor/your_vendor/sepolicy/aaa.te 추가
#####################################
# 콜백 처리 (필요한 경우)
#####################################

# aaa가 클라이언트의 콜백을 호출하는 경우
# (역방향 Binder call)
binder_call(aaa, system_server)
binder_call(aaa, platform_app)
binder_call(aaa, priv_app)

# 클라이언트의 서비스 찾기 (콜백용)
allow aaa system_service:service_manager find;
allow aaa app_api_service:service_manager find;
4. Property 정의 (서버 상태 관리)
vendor/your_vendor/sepolicy/property.te
# aaa property 타입
type vendor_aaa_prop, property_type;
vendor/your_vendor/sepolicy/property_contexts
# aaa 관련 property
aaa.start                       u:object_r:vendor_aaa_prop:s0
aaa.status                      u:object_r:vendor_aaa_prop:s0
aaa.ready                       u:object_r:vendor_aaa_prop:s0
persist.aaa.                    u:object_r:vendor_aaa_prop:s0

# 클라이언트가 읽을 수 있도록 설정
# (property.te에서 관리)
클라이언트가 property 읽기 허용
# system/sepolicy/private/system_server.te
get_prop(system_server, vendor_aaa_prop)

# system/sepolicy/private/platform_app.te
get_prop(platform_app, vendor_aaa_prop)
5. File Contexts
vendor/your_vendor/sepolicy/file_contexts
# aaa 실행 파일
/vendor/bin/aaa                         u:object_r:aaa_exec:s0

# aaa 디바이스
/dev/aaa_device                         u:object_r:aaa_device:s0

# aaa 데이터
/data/vendor/aaa(/.*)?                  u:object_r:aaa_data_file:s0

# aaa 설정
/vendor/etc/aaa\.conf                   u:object_r:vendor_configs_file:s0
6. Init RC (AIDL 서버용)
vendor/your_vendor/etc/init/aaa.rc
# aaa AIDL 서버 서비스
service aaa /vendor/bin/aaa
    class late_start
    user vendor_aaa
    group vendor_aaa system
    seclabel u:r:aaa:s0
    disabled
    oneshot
    
    # 서비스 준비 완료 알림
    onrestart setprop aaa.ready 0

# property 기반 시작
on property:aaa.start=1
    start aaa
    
on property:aaa.start=0
    stop aaa

# 서비스 시작됨
on property:init.svc.aaa=running
    setprop aaa.status running
    # 잠시 대기 후 ready 설정 (AIDL 등록 시간)
    exec_background - vendor_aaa vendor_aaa -- /bin/sleep 1
    setprop aaa.ready 1

# 서비스 중지됨
on property:init.svc.aaa=stopped
    setprop aaa.status stopped
    setprop aaa.ready 0

# 부팅 시 초기화
on boot
    # 디바이스 노드 권한
    chown vendor_aaa vendor_aaa /dev/aaa_device
    chmod 0660 /dev/aaa_device
    
    # 데이터 디렉토리
    mkdir /data/vendor/aaa 0770 vendor_aaa vendor_aaa
    restorecon_recursive /data/vendor/aaa
    
    # 초기 property 설정
    setprop aaa.status stopped
    setprop aaa.ready 0

# 부팅 완료 후 자동 시작 (optional)
on property:sys.boot_completed=1
    setprop aaa.start 1
7. 매크로를 사용한 간소화 (Optional)
여러 앱 도메인이 aaa 서비스를 사용하는 경우, 매크로 정의:
vendor/your_vendor/sepolicy/te_macros
#####################################
# AAA 서비스 사용 매크로
#####################################
define(`use_aaa_service', `
    binder_call($1, aaa)
    allow $1 aaa_service:service_manager find;
')
사용 예시
# system/sepolicy/private/system_server.te
use_aaa_service(system_server)

# system/sepolicy/private/platform_app.te
use_aaa_service(platform_app)

# vendor/your_vendor/sepolicy/vendor_app.te
use_aaa_service(vendor_app)
8. 디버깅 및 검증
AIDL 서비스 등록 확인
# 서비스 시작
adb shell setprop aaa.start 1

# 서비스 준비 대기
adb shell getprop aaa.ready
# 출력: 1

# 서비스 목록 확인
adb shell service list | grep IAaaService
# 출력: 123    com.example.IAaaService/default: [com.example.IAaaService]

# SELinux 컨텍스트 확인
adb shell service list -c | grep IAaaService
# 출력: com.example.IAaaService/default: u:object_r:aaa_service:s0
클라이언트 접근 테스트
# system_server에서 호출 테스트
adb shell service call com.example.IAaaService/default 1

# 앱에서 호출 테스트 (간단한 테스트 앱 필요)
adb shell am start -n com.example.testapp/.MainActivity
SELinux Denial 확인
# aaa 관련 denial
adb logcat -b all -d | grep "avc.*denied.*aaa"

# 서비스 등록 denial
adb logcat -b all -d | grep "avc.*denied.*service_manager.*aaa"

# 클라이언트 접근 denial
adb logcat -b all -d | grep "avc.*denied.*aaa_service"
9. 주요 차이점 정리
AIDL 서버 vs 클라이언트
항목
AIDL 서버 (aaa)
AIDL 클라이언트
ServiceManager
add 권한 필요
find 권한만
Binder 방향
클라이언트로부터 call 수신
서버로 call 송신
service.te
필요 (서비스 타입 정의)
불필요
service_contexts
필요 (서비스 레이블)
불필요
클라이언트 정책
각 클라이언트에 binder_call(client, aaa)
불필요
joinThreadPool
필요 (또는 startThreadPool)
불필요
10. 완전한 파일 구조
vendor/your_vendor/sepolicy/
├── aaa.te                    # 서버 정책 (핵심!)
├── service.te                # 서비스 타입 정의
├── service_contexts          # 서비스 레이블
├── property.te               # Property 타입
├── property_contexts         # Property 레이블
├── file_contexts             # 파일 레이블
└── vendor_app.te             # vendor 앱 클라이언트 정책

system/sepolicy/private/
├── system_server.te          # system_server 클라이언트 정책
├── platform_app.te           # platform_app 클라이언트 정책
└── priv_app.te               # priv_app 클라이언트 정책

vendor/your_vendor/etc/init/
└── aaa.rc                    # Init 설정
이제 aaa가 완전한 AIDL 서버로 동작하며, 다양한 클라이언트들이 안전하게 접근할 수 있습니다!
추가 질문이나 특정 denial 에러가 있으면 알려주세요!







네 그러면 system-service-aidl-V1-ndk는 무엇입니까? aidl 관련 라이브러리라면,  이렇게 ndk를 포함하지 않고 .aidl 파일을 직접 로딩할 수는 없습니까? 왜냐하면 aaa는 AIDL 서버이므로 여기에 직접 AIDL을 정의하고 Android.mk에 포함시키고 싶습니다.   가능하다면, 이름은 myserver.aidl로 변경해주세요.

네, 가능합니다! Android.mk에서 .aidl 파일을 직접 빌드할 수 있습니다.
AIDL 라이브러리 vs 직접 빌드
system-service-aidl-V1-ndk란?
다른 모듈에서 이미 빌드된 AIDL 인터페이스를 사용할 때 필요
미리 컴파일된 라이브러리 (.so 파일)
클라이언트가 서버의 인터페이스를 참조할 때 사용
직접 빌드
자체 AIDL 서버를 만들 때 사용
.aidl 파일을 소스에 포함하여 직접 컴파일
aidl-cpp 도구가 자동으로 C++ 코드 생성
aaa 모듈에 AIDL 직접 추가
1. 디렉토리 구조
external/aaa/
├── Android.mk
├── aidl/
│   └── com/
│       └── example/
│           └── myserver.aidl
├── aaa_main.c
├── aaa_core.c
├── aidl_server.cpp
└── include/
    └── aidl_wrapper.h
2. AIDL 인터페이스 정의
external/aaa/aidl/com/example/myserver.aidl
package com.example;

interface IMyServer {
    int getValue();
    void setValue(int value);
    String getStatus();
    void setStatus(String status);
    
    // 추가 메서드
    boolean isReady();
    void reset();
}
3. Android.mk 수정
external/aaa/Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := aaa
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true
LOCAL_VENDOR_MODULE := true

#####################################
# AIDL 설정
#####################################

# AIDL 소스 파일
LOCAL_SRC_FILES := \
    aidl/com/example/myserver.aidl

# AIDL include 경로
LOCAL_AIDL_INCLUDES := \
    $(LOCAL_PATH)/aidl

# C/C++ 소스 파일
LOCAL_SRC_FILES += \
    aaa_main.c \
    aaa_core.c \
    aidl_server.cpp \
    aidl_wrapper.cpp

LOCAL_CPP_EXTENSION := .cpp

#####################################
# 컴파일 플래그
#####################################

LOCAL_CPPFLAGS := -std=c++17 -Wall -Werror
LOCAL_CFLAGS := -Wall -Werror

#####################################
# 라이브러리
#####################################

# Binder NDK 라이브러리 (AIDL 필수)
LOCAL_SHARED_LIBRARIES := \
    libc++ \
    liblog \
    libcutils \
    libutils \
    libbinder_ndk

# 추가 유틸리티
LOCAL_SHARED_LIBRARIES += \
    libbase

#####################################
# 헤더 경로
#####################################

LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)/include

# AIDL 생성 헤더 경로 (자동 추가됨)
# $(intermediates)/aidl-generated/include

#####################################
# 빌드 타입
#####################################

include $(BUILD_EXECUTABLE)
4. AIDL 서버 구현
external/aaa/aidl_server.cpp
#include "aidl_wrapper.h"
#include <aidl/com/example/BnMyServer.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <android-base/logging.h>
#include <mutex>

using aidl::com::example::IMyServer;
using aidl::com::example::BnMyServer;

// AIDL 서버 구현
class MyServerImpl : public BnMyServer {
public:
    MyServerImpl() : mValue(0), mStatus("idle"), mReady(false) {}
    
    ndk::ScopedAStatus getValue(int32_t* _aidl_return) override {
        std::lock_guard<std::mutex> lock(mMutex);
        *_aidl_return = mValue;
        LOG(INFO) << "getValue() -> " << mValue;
        return ndk::ScopedAStatus::ok();
    }
    
    ndk::ScopedAStatus setValue(int32_t value) override {
        std::lock_guard<std::mutex> lock(mMutex);
        mValue = value;
        LOG(INFO) << "setValue(" << value << ")";
        return ndk::ScopedAStatus::ok();
    }
    
    ndk::ScopedAStatus getStatus(std::string* _aidl_return) override {
        std::lock_guard<std::mutex> lock(mMutex);
        *_aidl_return = mStatus;
        LOG(INFO) << "getStatus() -> " << mStatus;
        return ndk::ScopedAStatus::ok();
    }
    
    ndk::ScopedAStatus setStatus(const std::string& status) override {
        std::lock_guard<std::mutex> lock(mMutex);
        mStatus = status;
        LOG(INFO) << "setStatus(" << status << ")";
        return ndk::ScopedAStatus::ok();
    }
    
    ndk::ScopedAStatus isReady(bool* _aidl_return) override {
        std::lock_guard<std::mutex> lock(mMutex);
        *_aidl_return = mReady;
        return ndk::ScopedAStatus::ok();
    }
    
    ndk::ScopedAStatus reset() override {
        std::lock_guard<std::mutex> lock(mMutex);
        mValue = 0;
        mStatus = "idle";
        mReady = false;
        LOG(INFO) << "reset()";
        return ndk::ScopedAStatus::ok();
    }
    
    // C 코드에서 호출할 메서드
    void updateValue(int32_t value) {
        std::lock_guard<std::mutex> lock(mMutex);
        mValue = value;
    }
    
    void updateStatus(const std::string& status) {
        std::lock_guard<std::mutex> lock(mMutex);
        mStatus = status;
    }
    
    void setReady(bool ready) {
        std::lock_guard<std::mutex> lock(mMutex);
        mReady = ready;
    }
    
private:
    std::mutex mMutex;
    int32_t mValue;
    std::string mStatus;
    bool mReady;
};

static std::shared_ptr<MyServerImpl> gService = nullptr;

extern "C" {

int aidl_server_init(void) {
    LOG(INFO) << "Initializing MyServer AIDL service";
    
    gService = ndk::SharedRefBase::make<MyServerImpl>();
    
    const std::string instance = std::string() + IMyServer::descriptor + "/default";
    binder_status_t status = AServiceManager_addService(
        gService->asBinder().get(),
        instance.c_str()
    );
    
    if (status != STATUS_OK) {
        LOG(ERROR) << "Failed to register service: " << status;
        gService = nullptr;
        return -1;
    }
    
    LOG(INFO) << "MyServer registered as: " << instance;
    gService->setReady(true);
    return 0;
}

void aidl_server_cleanup(void) {
    LOG(INFO) << "Cleaning up MyServer";
    gService = nullptr;
}

void aidl_server_update_value(int value) {
    if (gService != nullptr) {
        gService->updateValue(value);
    }
}

void aidl_server_update_status(const char* status) {
    if (gService != nullptr && status != nullptr) {
        gService->updateStatus(std::string(status));
    }
}

} // extern "C"
5. 생성되는 파일 확인
빌드 시 AIDL 컴파일러가 자동 생성:
out/soong/.intermediates/external/aaa/aaa/android_vendor.33_arm64_armv8-a/
└── gen/
    └── aidl/
        └── com/
            └── example/
                ├── IMyServer.cpp
                ├── BnMyServer.cpp
                ├── BpMyServer.cpp
                └── include/
                    └── aidl/
                        └── com/
                            └── example/
                                ├── IMyServer.h
                                ├── BnMyServer.h
                                └── BpMyServer.h
Android.bp 방식 (권장)
Android.mk보다 더 현대적인 방법:
external/aaa/Android.bp
// AIDL 인터페이스 정의
aidl_interface {
    name: "myserver-aidl",
    vendor_available: true,
    srcs: [
        "aidl/com/example/myserver.aidl",
    ],
    stability: "vintf",
    backend: {
        ndk: {
            enabled: true,
        },
        cpp: {
            enabled: false,
        },
    },
}

// aaa 실행 파일
cc_binary {
    name: "aaa",
    vendor: true,
    
    srcs: [
        "aaa_main.c",
        "aaa_core.c",
        "aidl_server.cpp",
        "aidl_wrapper.cpp",
    ],
    
    shared_libs: [
        "libc++",
        "liblog",
        "libcutils",
        "libutils",
        "libbinder_ndk",
        "libbase",
        "myserver-aidl-V1-ndk",  // 자체 AIDL
    ],
    
    cflags: [
        "-Wall",
        "-Werror",
    ],
    
    cppflags: [
        "-std=c++17",
    ],
    
    local_include_dirs: [
        "include",
    ],
}
Android.mk에서 계속 사용하는 경우
Android.mk (AIDL 포함, 개선 버전)
LOCAL_PATH := $(call my-dir)

#####################################
# AIDL 인터페이스만 먼저 빌드
#####################################

include $(CLEAR_VARS)

LOCAL_MODULE := myserver-aidl-ndk
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_PROPRIETARY_MODULE := true

LOCAL_SRC_FILES := \
    aidl/com/example/myserver.aidl

LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/aidl

LOCAL_SHARED_LIBRARIES := \
    libbinder_ndk

include $(BUILD_SHARED_LIBRARY)

#####################################
# aaa 실행 파일
#####################################

include $(CLEAR_VARS)

LOCAL_MODULE := aaa
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true
LOCAL_VENDOR_MODULE := true

# C/C++ 소스만
LOCAL_SRC_FILES := \
    aaa_main.c \
    aaa_core.c \
    aidl_server.cpp \
    aidl_wrapper.cpp

# AIDL 생성 코드 사용
LOCAL_SHARED_LIBRARIES := \
    libc++ \
    liblog \
    libcutils \
    libutils \
    libbinder_ndk \
    libbase \
    myserver-aidl-ndk

LOCAL_CPPFLAGS := -std=c++17 -Wall -Werror
LOCAL_CFLAGS := -Wall -Werror

LOCAL_C_INCLUDES := \
    $(LOCAL_PATH)/include

include $(BUILD_EXECUTABLE)
SEPolicy 업데이트
vendor/your_vendor/sepolicy/service_contexts
# 서비스 이름 변경
com.example.IMyServer/default         u:object_r:aaa_service:s0
빌드 및 테스트
# 빌드
m aaa

# 서비스 확인
adb shell service list | grep IMyServer

# 출력:
# 123    com.example.IMyServer/default: [com.example.IMyServer]
정리
✅ 직접 AIDL 빌드 방식
.aidl 파일 → aidl-cpp 컴파일러 → C++ 코드 생성 → 컴파일 → 실행 파일
✅ 사전 빌드된 라이브러리 방식
다른 모듈의 .so 파일 → 링크 → 실행 파일
aaa가 AIDL 서버이므로 직접 빌드 방식이 맞습니다!
추가 질문 있으시면 말씀해주세요!

반응형