[Android] Android.mk와 AIDL 2 (작성중)
2026. 1. 22. 16:43
아예 코드를 새로 알려주세요. - Android.mk를 가진 aaa라는 모듈 (C 데몬)은 send(), register() (이 둘의 반환값은 모두 "hello world") 이 2개의 API를 제공하는 AIDL 서버 입니다.
네, 처음부터 완전히 새로 작성하겠습니다.
디렉토리 구조
external/aaa/
├── Android.mk
├── aidl/
│ └── com/
│ └── example/
│ └── IAaaService.aidl
├── include/
│ ├── aaa_core.h
│ └── aidl_server.h
├── src/
│ ├── aaa_main.c
│ ├── aaa_core.c
│ └── aidl_server.cpp
└── sepolicy/
└── aaa.te
1. AIDL 인터페이스 정의
external/aaa/aidl/com/example/IAaaService.aidl
package com.example;
interface IAaaService {
String send();
String register();
}
2. Android.mk
external/aaa/Android.mk
LOCAL_PATH := $(call my-dir)
###########################################
# aaa 데몬
###########################################
include $(CLEAR_VARS)
LOCAL_MODULE := aaa
LOCAL_MODULE_TAGS := optional
LOCAL_PROPRIETARY_MODULE := true
LOCAL_VENDOR_MODULE := true
# AIDL 파일
LOCAL_SRC_FILES := \
aidl/com/example/IAaaService.aidl
LOCAL_AIDL_INCLUDES := \
$(LOCAL_PATH)/aidl
# C/C++ 소스 파일
LOCAL_SRC_FILES += \
src/aaa_main.c \
src/aaa_core.c \
src/aidl_server.cpp
LOCAL_CPP_EXTENSION := .cpp
# 헤더 경로
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/include
# 라이브러리
LOCAL_SHARED_LIBRARIES := \
libc++ \
liblog \
libcutils \
libutils \
libbinder_ndk \
libbase
# 헤더 라이브러리
LOCAL_HEADER_LIBRARIES := \
libbinder_ndk_headers
# 컴파일 플래그
LOCAL_CFLAGS := -Wall -Werror
LOCAL_CPPFLAGS := -std=c++17 -Wall -Werror
include $(BUILD_EXECUTABLE)
3. C 헤더
external/aaa/include/aaa_core.h
#ifndef AAA_CORE_H
#define AAA_CORE_H
#ifdef __cplusplus
extern "C" {
#endif
// C 데몬 코어 함수
void aaa_core_init(void);
void aaa_core_cleanup(void);
void aaa_core_process(void);
#ifdef __cplusplus
}
#endif
#endif // AAA_CORE_H
external/aaa/include/aidl_server.h
#ifndef AIDL_SERVER_H
#define AIDL_SERVER_H
#ifdef __cplusplus
extern "C" {
#endif
// AIDL 서버 초기화/정리
int aidl_server_init(void);
void aidl_server_cleanup(void);
#ifdef __cplusplus
}
#endif
#endif // AIDL_SERVER_H
4. C 소스 파일
external/aaa/src/aaa_core.c
#include "aaa_core.h"
#include <stdio.h>
#include <log/log.h>
void aaa_core_init(void) {
ALOGI("aaa core initialized");
printf("aaa core initialized\n");
}
void aaa_core_cleanup(void) {
ALOGI("aaa core cleanup");
printf("aaa core cleanup\n");
}
void aaa_core_process(void) {
ALOGI("aaa core processing...");
// 데몬 로직 처리
}
external/aaa/src/aaa_main.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <log/log.h>
#include "aaa_core.h"
#include "aidl_server.h"
// Binder 스레드 풀 시작 (C++에서 구현)
extern void start_binder_threadpool(void);
static volatile int running = 1;
void signal_handler(int sig) {
ALOGI("Received signal %d, shutting down", sig);
running = 0;
}
int main(int argc, char** argv) {
ALOGI("aaa daemon starting...");
printf("aaa daemon starting...\n");
// 시그널 핸들러 등록
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
// C 코어 초기화
aaa_core_init();
// AIDL 서버 초기화
if (aidl_server_init() < 0) {
ALOGE("Failed to initialize AIDL server");
fprintf(stderr, "Failed to initialize AIDL server\n");
aaa_core_cleanup();
return 1;
}
// Binder 스레드 풀 시작 (백그라운드)
start_binder_threadpool();
ALOGI("aaa daemon ready");
printf("aaa daemon ready\n");
// 메인 루프
while (running) {
aaa_core_process();
sleep(5); // 5초마다 처리
}
// 정리
ALOGI("aaa daemon shutting down");
printf("aaa daemon shutting down\n");
aidl_server_cleanup();
aaa_core_cleanup();
return 0;
}
5. C++ AIDL 서버 구현
external/aaa/src/aidl_server.cpp
#include "aidl_server.h"
#include <aidl/com/example/BnAaaService.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <android-base/logging.h>
#include <memory>
using aidl::com::example::IAaaService;
using aidl::com::example::BnAaaService;
// AIDL 서버 구현
class AaaServiceImpl : public BnAaaService {
public:
AaaServiceImpl() {
LOG(INFO) << "AaaServiceImpl created";
}
~AaaServiceImpl() {
LOG(INFO) << "AaaServiceImpl destroyed";
}
// send() API 구현
ndk::ScopedAStatus send(std::string* _aidl_return) override {
LOG(INFO) << "send() called";
*_aidl_return = "hello world";
return ndk::ScopedAStatus::ok();
}
// register() API 구현
ndk::ScopedAStatus register_(std::string* _aidl_return) override {
LOG(INFO) << "register() called";
*_aidl_return = "hello world";
return ndk::ScopedAStatus::ok();
}
};
// 전역 서비스 인스턴스
static std::shared_ptr<AaaServiceImpl> gService = nullptr;
extern "C" {
int aidl_server_init(void) {
LOG(INFO) << "Initializing AAA AIDL service";
// 서비스 인스턴스 생성
gService = std::make_shared<AaaServiceImpl>();
// 서비스 이름
const std::string instance = std::string() + IAaaService::descriptor + "/default";
// ServiceManager에 등록
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) << "AAA service registered as: " << instance;
return 0;
}
void aidl_server_cleanup(void) {
LOG(INFO) << "Cleaning up AAA AIDL service";
gService = nullptr;
}
// Binder 스레드 풀 시작 (Non-blocking)
void start_binder_threadpool(void) {
LOG(INFO) << "Starting Binder thread pool";
ABinderProcess_setThreadPoolMaxThreadCount(4);
ABinderProcess_startThreadPool();
}
} // extern "C"
6. Init RC 파일
vendor/your_vendor/etc/init/aaa.rc
service aaa /vendor/bin/aaa
class late_start
user root
group root system
seclabel u:r:aaa:s0
disabled
on property:aaa.start=1
start aaa
on property:aaa.start=0
stop aaa
on boot
setprop aaa.start 0
7. SEPolicy
vendor/your_vendor/sepolicy/aaa.te
# aaa 데몬 타입
type aaa, domain;
type aaa_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(aaa)
# Binder 사용
binder_use(aaa)
# ServiceManager 접근
allow aaa servicemanager:binder { call transfer };
allow aaa aaa_service:service_manager add;
# 클라이언트 허용
binder_call(system_server, aaa)
binder_call(platform_app, aaa)
binder_call(priv_app, aaa)
binder_call(untrusted_app, aaa)
# 로그
allow aaa kmsg_device:chr_file write;
# 프로세스 권한
allow aaa self:process signal;
vendor/your_vendor/sepolicy/service.te
type aaa_service, service_manager_type, vendor_service;
vendor/your_vendor/sepolicy/service_contexts
com.example.IAaaService/default u:object_r:aaa_service:s0
vendor/your_vendor/sepolicy/file_contexts
/vendor/bin/aaa u:object_r:aaa_exec:s0
8. 빌드 및 테스트
빌드
# aaa 빌드
m aaa
# 결과 확인
ls out/target/product/*/vendor/bin/aaa
# 디바이스에 푸시
adb push out/target/product/*/vendor/bin/aaa /vendor/bin/
adb shell chmod 755 /vendor/bin/aaa
실행
# 수동 실행
adb shell /vendor/bin/aaa
# Property로 실행
adb shell setprop aaa.start 1
# 프로세스 확인
adb shell ps -A | grep aaa
서비스 확인
# 서비스 등록 확인
adb shell service list | grep IAaaService
# 출력 예:
# 123 com.example.IAaaService/default: [com.example.IAaaService]
AIDL 호출 테스트
# send() 호출 (service call 명령어 사용)
adb shell service call com.example.IAaaService/default 1
# register() 호출
adb shell service call com.example.IAaaService/default 2
9. 클라이언트 예제 (테스트용)
test_client.cpp
#include <aidl/com/example/IAaaService.h>
#include <android/binder_manager.h>
#include <android-base/logging.h>
#include <iostream>
using aidl::com::example::IAaaService;
int main() {
const std::string instance = std::string() + IAaaService::descriptor + "/default";
AIBinder* binder = AServiceManager_checkService(instance.c_str());
if (binder == nullptr) {
std::cerr << "Failed to get service" << std::endl;
return 1;
}
auto service = IAaaService::fromBinder(ndk::SpAIBinder(binder));
if (service == nullptr) {
std::cerr << "Failed to create service interface" << std::endl;
return 1;
}
std::string result;
// send() 호출
auto status = service->send(&result);
if (status.isOk()) {
std::cout << "send() returned: " << result << std::endl;
} else {
std::cerr << "send() failed" << std::endl;
}
// register() 호출
status = service->register_(&result);
if (status.isOk()) {
std::cout << "register() returned: " << result << std::endl;
} else {
std::cerr << "register() failed" << std::endl;
}
return 0;
}
test_client Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := test_aaa_client
LOCAL_PROPRIETARY_MODULE := true
LOCAL_SRC_FILES := test_client.cpp
# aaa의 AIDL 사용
LOCAL_AIDL_INCLUDES := \
external/aaa/aidl
LOCAL_SHARED_LIBRARIES := \
libc++ \
liblog \
libutils \
libbinder_ndk \
libbase
LOCAL_CPPFLAGS := -std=c++17
include $(BUILD_EXECUTABLE)
클라이언트 실행
# 빌드
m test_aaa_client
# 실행
adb shell /vendor/bin/test_aaa_client
# 출력:
# send() returned: hello world
# register() returned: hello world
10. 로그 확인
# aaa 데몬 로그
adb logcat -s aaa:V
# AIDL 호출 로그
adb logcat | grep -E "AaaServiceImpl|send\(\)|register\(\)"
요약
구조
aaa (C 데몬)
├── C 메인 루프 (aaa_main.c)
├── C 코어 로직 (aaa_core.c)
└── C++ AIDL 서버 (aidl_server.cpp)
├── send() → "hello world"
└── register() → "hello world"
핵심 포인트
Android.mk: AIDL 파일을 직접 포함하여 빌드
C/C++ 혼용: C 데몬 + C++ AIDL 서버
Non-blocking: startThreadPool()로 메인 루프와 독립 실행
2개 API: send(), register() 모두 "hello world" 반환
빌드하고 실행해보세요! 추가 질문 있으시면 알려주세요!
