DeviceAgent Task Executor Wiring Wiki
1. 목적
이 문서는 TaskExecutorBootstrap에 등록된 skeleton executor를 실제 DeviceAgent 제어 로직과 연결하는 구현 지침이다.
대상 파일:
apps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/TaskExecutorBootstrap.javaapps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/TaskModuleExecutor.javaapps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/MovementTaskExecutor.javaapps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/CleaningAmpTaskExecutor.javaapps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/LlmTtsTaskExecutor.javaapps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/IotTaskExecutor.javaapps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/task/UpdateTaskExecutor.java
2. 현재 skeleton 등록 상태
TaskExecutorBootstrap.registerSkeletonExecutors(boolean dryRun)는 다음 method를 등록한다.
| Executor | taskMethod |
|---|---|
MovementTaskExecutor |
returnToStation, setMoveTo, setMoving, stopMovement |
CleaningAmpTaskExecutor |
setAirCleanerOperation, setStatusClean, stopCleaning, ampStop |
LlmTtsTaskExecutor |
setChangeLlmStatus, setLlmTts, stopLlm, stopTts |
IotTaskExecutor |
setDeviceStatus, setConfig, getConfig |
UpdateTaskExecutor |
OTAUpdateArmResult, OTAUpdateMcuResult, setFirmwareUpdateStatus |
현재 TaskModuleExecutor.execute(...)는 dryRun이면 응답만 쓰고, 아니면 UnsupportedOperationException을 던진다. 따라서 제품 동작으로 쓰려면 반드시 wiring 구현이 필요하다.
3. Bootstrap 위치
DeviceAgent.onCreate()에서 MainCommon.set(...) 이후 등록한다.
MainCommon.set(...);
TaskExecutorBootstrap.registerSkeletonExecutors(false);
개발 중에는 다음 중 하나로 dry-run 검증이 가능하다.
TaskExecutorBootstrap.registerSkeletonExecutors(true);
또는 호출 Bundle에 다음을 넣는다.
indata.putBoolean("executorDryRun", true);
4. TaskModuleExecutor 변경 방향
권장 구조:
abstract class TaskModuleExecutor implements TaskExecutorRegistry.TaskExecutor {
@Override
public final void execute(Bundle indata, Bundle outdata) {
String method = indata == null ? "" : indata.getString("method", "");
if (dryRun || (indata != null && indata.getBoolean("executorDryRun", false))) {
writeDryRunResult(method, outdata);
return;
}
executeWired(method, indata, outdata);
}
protected abstract void executeWired(String method, Bundle indata, Bundle outdata);
}
공통 응답 필드:
| key | type | 의미 |
|---|---|---|
executorWired |
boolean | 실제 wiring 실행 여부 |
executorDomain |
String | movement, cleaning_amp, llm_tts, iot, update |
taskMethod |
String | 실행한 method |
accepted |
boolean | 기존 제어 로직에 명령 접수 성공 여부 |
reason |
String | 실패/거부 사유 |
errorCode |
String | framework error code 또는 task error code |
5. MovementTaskExecutor 연결
| taskMethod | 연결 대상 | 주의 |
|---|---|---|
returnToStation |
CmdPolicyManager.INSTANCE.returnToStation(...) 또는 FrameworkCommandBridge.tryHandle(...) |
명령 접수와 도착 완료를 분리 |
setMoveTo |
CmdPolicyManager.INSTANCE.setMoveTo(Position, isAirSensor, isAppCall) |
positionId를 MapManager로 resolve 필요 |
setMoving |
CmdPolicyManager.INSTANCE.setDeviceStatus(...) |
기존 function/action 계약 유지 |
stopMovement |
RobotMovementController.getInstance().stopCurrentMove(true) |
cancel task와 연결 |
setMoveTo는 최소 다음 입력 중 하나를 지원해야 한다.
| 입력 | 처리 |
|---|---|
positionId |
MapManager에서 Area 조회 후 Position 생성 |
poiId, poiName, x, y, degree |
직접 Area/Position 생성 |
positionIds |
workflow 또는 순차 이동으로 확장 |
6. CleaningAmpTaskExecutor 연결
| taskMethod | 연결 대상 후보 | 비고 |
|---|---|---|
setAirCleanerOperation |
CleanOperationCommandHandler.handleSetAirCleanerOperation(...) 또는 기존 MainApi 로직 분리 |
신규 handler가 있으면 handler 우선 |
setStatusClean |
CleanStatusCommandHandler.handleSetStatusClean(...) |
청정 상태 변경 |
stopCleaning |
기존 청정 stop/cancel 로직 adapter화 | cancel 계약 필요 |
ampStop |
AMP/청정 관련 stop 로직 | 명령 정의 확인 필요 |
DeviceControlService.sendModuleCommand(...)로 자기 자신에게 다시 Binder 호출하는 방식은 피한다. TaskExecutor 안에서 self-call을 하면 MainApi.executeMethod -> TaskManager -> Executor -> MainApi 재진입이 발생할 수 있다.
7. LlmTtsTaskExecutor 연결
| taskMethod | 연결 대상 | 입력 |
|---|---|---|
setChangeLlmStatus |
LlmManager.INSTANCE.setChangeStatus(newStatus) |
newStatus |
stopLlm |
setChangeStatus(CMD_STOP_TTS) 또는 별도 stop 정의 |
정책 확정 필요 |
stopTts |
setChangeStatus(CMD_STOP_TTS) |
newStatus=3 기본 |
setLlmTts |
LlmManager.INSTANCE.setTts(tts) |
tts |
setLlmTts 완료 기준은 명령 전달 완료인지, TTS playback 완료인지 기획 정의가 필요하다.
8. IotTaskExecutor 연결
| taskMethod | 연결 대상 | 비고 |
|---|---|---|
setDeviceStatus |
CmdPolicyManager.INSTANCE.setDeviceStatus(indata) |
IoT/LLM/app 제어 공통 진입 |
setConfig |
ConfigCommandHandler.handleSetConfig(indata) |
framework command 패키지 사용 가능 |
getConfig |
ConfigCommandHandler.handleGetConfiguration(outdata) |
조회는 direct 가능 |
IoT publish가 필요한 command는 AppCmd.INSTANCE.sendModuleCommand_iot(...) 호출 여부를 command별로 확정해야 한다.
9. UpdateTaskExecutor 연결
| taskMethod | 연결 대상 | 주의 |
|---|---|---|
setFirmwareUpdateStatus |
기존 MainApi의 MCU OTA branch를 adapter로 분리 |
startMcuOta_hidl(...) 접근성 문제 |
OTAUpdateArmResult |
기존 MainApi branch adapter화 |
ARM->MCU->SOC 단계 전이 |
OTAUpdateMcuResult |
기존 MainApi branch adapter화 |
recovery 실패/성공 처리 |
Update는 MainApi private 메서드와 필드에 의존하므로, 단순 executor 직접 호출보다 UpdateCommandAdapter를 별도 생성하는 것이 안전하다.
10. 구현 완료 기준
- dry-run 없이 각 executor가
UnsupportedOperationException을 던지지 않는다. - 성공/실패 응답이
outdata에 표준 필드로 남는다. - 장시간 동작은 task 완료 callback 또는 timeout으로 종료된다.
- legacy 직접 호출과 task 호출 결과가 동일해야 한다.
- 단위 테스트에서
executorDryRun=false경로를 최소 1회 이상 검증한다.