← Docs hub

Task 소유권: 누가 이 작업을 조회하거나 취소할 수 있는가

이번 구현은 실제 Task 기록에 소유자를 함께 저장하고, 조회·취소할 때 그 소유권을 검사하는 내부 연결이다. 공개 Binder나 제품 명령 경로 전체를 완성한 것은 아니다. 전체 구조는 구조 Atlas, 누적 진행은 리팩터링 현황에서 확인한다.

1. 전체 구조에서의 위치

구간 책임 이번 상태
앱 SDK Manager → Android Binder 통신 값 변환, 서버에서 호출자 신원 확인 typed Stub·SDK 구현; 공개 등록·실제 왕복은 미완
TaskManagerEndpoint 호출마다 신뢰·권한·서비스 준비 상태·런타임 세대 검사 내부 조회·취소 연결 구현
TaskManagerService 소유자와 입력의 동시 접수, 본인 작업 조회·취소 구현 및 JVM 검증
AMR·Cleaning 등 실행 서비스 자기 도메인의 실행·상태 관측·실제 중단 기존 개별 이관과 별도 연결 필요
SkixTaskManager → ITaskManager → TaskManagerBinderService
                     ↓ [코드 구현; 호스트 공개·실제 IPC 검증은 미완]
                  매 호출 신원 확인
TaskManagerEndpoint → 매 호출 권한·준비 상태·세대 검사
                     ↓
TaskManagerService → Task 기록의 UID / 사용자 / 패키지와 비교
                     ├─ 본인 기록: 조회 또는 취소 의도 등록
                     └─ 타인·무소유·없는 기록: 같은 결과로 숨김

실행 도메인 → 실제 중단 확인 → 완료 처리
             (취소 요청 수락과 별개의 책임)

TaskOwner는 UID·Android 사용자 ID·패키지명의 불변 값이다. PID는 앱 재시작마다 바뀔 수 있으므로 소유권에 포함하지 않는다. 앱 payload의 source나 requestId는 인증 근거가 아니다. TaskOwner 객체를 생성할 수 있다는 것 자체가 권한을 의미하지 않는다.

2. 폴더와 파일별 책임

아래 경로는 skix-framework/base/services/core/java/com/sk/airbot/frameworkservice/server/ 기준이다.

폴더 / 파일 역할
entrypoint/binder/TaskManagerEndpoint.java getTask/listTasks/cancelTask를 기존 admission 검사 뒤 실제 Task 서비스로 전달
execution/task/TaskOwner.java 호출자 소유권의 값 비교; 인증 토큰이 아님
execution/task/TaskRecord.java 입력·소유자를 작업 기록과 같은 수명으로 보관
execution/task/TaskManagerService.java 접수·소유권 검사·취소 상태 변경을 동일 잠금 아래 수행
entrypoint/validation/ 및 control/lifecycle/ 기존 호출 권한 검사와 서비스 수명·준비 상태 검사; endpoint가 재사용

폴더명 binder는 진입점의 설계 위치다. 이번 클래스는 Android Binder 상속이나 AIDL 구현이 없는 통신 방식과 분리된 내부 객체이며 Android 호스트에서 자동 공개하지 않는다.

3. 실제 동작 규칙

상황 처리
내부 도메인의 submitOwnedExecution 준비 상태, owner/input 검사 후 입력과 소유자를 함께 기록
서로 다른 소유자의 같은 requestId 별개 요청으로 허용
같은 소유자의 중복 requestId 기존 중복 거부 의미 유지
기존 소유자 없는 내부 Task 기존 내부 API 동작 유지; 외부용 소유자 조회에서는 숨김
getTask: 타인·없는 작업·무소유 작업 모두 empty; 타인의 작업 존재 여부를 구분하지 않음
cancelTask: 타인·없는 작업·무소유 작업 동일 TASK_NOT_FOUND 및 고정 메시지, 상태 변경 없음
listTasks 본인 작업만 최신 접수순, limit은 1..100, 반환 목록 수정 불가
본인 취소 요청 첫 취소 사유 보존, CANCELLING, 기존 실행 권한 철회
완료 기록 정리 해당 소유자의 중복 키도 함께 제거, 다른 소유자 키는 유지

조회는 기존 DISCOVERY_READ, 취소는 MUTATION 권한을 사용한다. 이는 현재의 넓은 작업 권한 구분이며 세부 읽기 권한 체계를 새로 만든 것은 아니다. 모든 요청에 소유자 필터가 추가 적용된다. 권한 회수나 런타임 세대 변경 후의 호출은 기존 admission 검사에서 거부한다.

접수 API는 인증 및 정책 검사를 끝낸 서버 내부 도메인용이다. 이번 endpoint에 submit/claim/transition API는 없다. 내부 Task 서비스를 직접 호출하는 코드의 신뢰 경계와 Android Binder 호출자 검증을 혼동하면 안 된다.

4. 동시 접근과 실제 정지의 차이

소유권 검사와 Task 변경은 기존 TaskManagerService의 같은 잠금에서 처리한다. 검사 뒤 다른 Task 기록에 적용하는 별도 소유권 맵은 만들지 않았다. 다른 앱의 취소 요청과 실행 claim이 겹치는 경우도 회귀 테스트한다.

그러나 취소 의도 등록은 물리 정지 완료가 아니다. CANCELLING 응답만으로 AMR 정지, 팬 정지, 최종 완료, 자원 반환을 만들어내지 않는다. 도메인 실행기는 관측·실행 식별자·완료 근거를 확인해야 한다. 런타임 전체와 기기 동작을 하나의 전역 잠금으로 원자화한 것도 아니다.

5. 검증과 남은 연결

<a id="typed-transport"></a>

후속 구현: typed Binder와 SDK (dba443e)

최신 진행 현황은 진행 현황 정본에 기록하고, 이 절에서는 계약과 소스 책임을 설명한다.

skix-framework/base/ 기준 경로 역할
core/aidl/.../ITaskManager.aidl getTask·listTasks·cancelTask만 제공; 실행권 획득·상태 강제 전이 API 없음
core/aidl/.../TaskSnapshotParcel.aidl 작업 ID·상태·우선순위·시각·취소 사유를 전달; 소유자 자격 정보는 전달하지 않음
core/aidl/.../TaskSnapshotResultParcel.aidl, TaskListResultParcel.aidl 정상 결과와 업무 거부 코드를 명시적으로 전달
core/java/.../internal/binder/TaskSnapshotCodec.java 변경 가능한 통신 객체와 불변 SDK 상태 값 사이 복사
core/java/.../manager/SkixTaskManager.java 앱 호출 창구, 목록 1..100 제한, 알 수 없는 상태·오류 코드 거부
services/runtime/java/.../entrypoint/binder/TaskManagerBinderService.java 매 호출 신원 해석 후 기존 endpoint에 위임; 신원 실패는 보안 예외

업무 오류는 0=성공, 1=잘못된 요청, 2=중복 요청, 3=작업 없음, 4=허용되지 않는 상태 전이, 5=취소 불가, 6=서비스 미준비로 고정한다. SDK는 거부를 TaskAccessException으로 변환한다. 조회의 정상 null은 작업 없음이지만 취소 결과 null·목록 null·알 수 없는 enum은 잘못된 응답으로 거부한다. Android 숨김 API ServiceSpecificException에 의존하지 않는다.

SkixTaskManager.fromBinder()는 이미 확보한 Binder를 받는 팩토리다. Root 검색·호스트 등록·공개 Binder 권한 설정까지 구현했다는 뜻은 아니다. 현재 시작 서비스의 onBind()는 null이며 비공개 설정을 유지한다. 실제 호출자·Parcel·프로세스 종료는 Android 실행 환경에서 별도 검증해야 한다.

후속 검증은 서버 447개 / SDK 62개 JVM 테스트, typed 전송 정적 계약 2개, release APK 빌드 통과다. SDK 신규 16개는 codec·typed 결과·입력 제한·오류 거부를 검사한다. JVM 전송 대역 검증이지 실제 Binder 왕복이 아니다. RemoteException 발생 시 자동 재시도하지 않는 코드는 있으나 해당 분기의 Android 실행 테스트는 미완이다. 아래 표는 선행 소유권 구현 당시의 검증 이력이다.

코드 기준 dab4e73, 목록 할당 보강 2d35b09. 커밋 대상 서버 소스만 분리해 검증했으며 기존 미완 LLM/TTS 수정은 제외했다. 독립 리뷰에서 발견한 전체 이력 snapshot 생성 문제를 수정해 최대 limit개만 생성한다. 목록 조회는 여전히 이력 전체를 잠금 아래 순회하므로, 대규모 운영을 위한 인덱스·페이지 단위 조회는 후속 과제다.

검증 결과 / 의미
신규 소유권·endpoint 테스트 22개 통과; 실제 내부 Task 서비스와 admission 연결 및 4,000개 활성 이력 검사
전체 서버 / SDK JVM 447개 / 46개 통과, 실패·오류·건너뜀 0
release APK 빌드 성공; private 시작 서비스 manifest 확인
소스 경계 검사 tree/layer/API/Bundle 및 snapshot 할당 정적 검사 통과; 성능 벤치마크는 아님
공개 Binder·앱 SDK 왕복 UNVERIFIED — 아직 연결하지 않음
제품 부팅·기기 실행·물리 취소 UNVERIFIED — 설치 및 실기기 검증 없음

다음 통합 지점은 인증된 도메인 요청 → 소유자 포함 접수 → 실행 세션 → 관측에 근거한 완료/취소다. SDK 통신 계약, Android 신원 검증, 서비스 조립 및 제품 어댑터 연결을 각각 확인해야 한다. 이번 결과를 MR6 TaskManager 전체 이식 완료나 전체 프레임워크 완성률로 환산하지 않는다.

<a id="amr-admission"></a>

6. AMR 요청을 소유자 있는 Task로 접수하기

2026-09-10 후속 구현 (8e2d7c6): 이동·스테이션 복귀 입력을 검증된 호출자의 Task로 저장하는 내부 접수 경계를 추가했다. 기존 실행 세션과 별개로 남아 있던 도메인 요청 → Task 기록을 연결한 것이다. 정책 구현이나 실제 주행 연결까지 완료한 것은 아니다.

신뢰된 Android 경계에서 확인한 CallerIdentity
  → AmrTaskEndpoint: AMR 변경 권한·연결 세대 검사, TaskOwner 생성
  → MovementTaskAdmission: AMR / Task / Runtime 준비 상태 확인
      → 필수 도메인 정책 검사
      → 권한·연결 세대 재검사 + 서비스 상태 세대 재검사
  → TaskManagerService.submitOwnedExecution
      → MovementTaskInput + 소유자 + QUEUED 작업 기록
      ├─ 기존 Task endpoint: 본인 작업 조회·취소
      └─ 실행 claim에서 typed 입력 획득 가능

후속 내부 구현: 발급된 claim → MovementTaskDispatcher → 자원 확보 → MovementTaskSession
아직 연결하지 않음: 스케줄러 실행 배정·제품 구동부·관측 기반 Task 완료·실제 정지
서버 정본 폴더·파일 책임
entrypoint/binder/AmrTaskEndpoint.java 호출자 신원에서 owner와 요청 출처 생성; 요청 payload를 신원으로 믿지 않음
domain/amr/execution/MovementTaskAdmission.java 도메인 입력을 Task로 변환; 필수 정책 포트와 AMR·Task·Runtime 수명 검사
domain/amr/execution/MovementTaskInput.java 기존 불변 이동·복귀 입력; 접수부터 실행 claim까지 같은 typed 값 유지
execution/task/TaskManagerService.java 기존 소유자별 중복·조회·취소 규칙과 같은 기록 저장소 사용

작업 큐는 movement, 내부 method는 amr.move / amr.return_to_station이다. ASYNC, CONTROL, APP, 입력의 timeout, 자동 재시도 0회, 취소 가능으로 고정한다. 새로운 기존 제품 통신 문자열 계약이 아니며, 현재 endpoint는 앱 신원 기반 요청용이다. 예약·클라우드의 별도 접수 계약을 대신하지 않는다.

MovementTaskAdmission.Policy는 반드시 주입해야 한다. 기본 허용 정책은 없지만, 실제 제품 사양을 판정하는 정책 구현을 연결한 것도 아니다. 현재 기본 Runtime은 이 접수 객체를 자동 조립하거나 공개하지 않는다. 틸팅·청소 상태·주행 금지 조건 등은 이후 기존 사양과 관측을 연결해 구현해야 한다.

검사와 Task 저장은 하나의 원자적 서비스 간 트랜잭션이 아니다. 정책 검사 중 발생한 권한 회수·연결 세대 변경·서비스 수명 변경은 재검사로 거부하지만, 이후 실행 시점에는 실행기가 정책·서비스 상태·자원을 다시 검사해야 한다. 접수 성공은 구동 허가나 이동 시작, 실제 정지 보장이 아니다.

검증 결과 / 한계
신규 AMR 접수 테스트 14개 통과: 이동·복귀 typed 입력, 소유권·중복, 권한·미준비·세대 변경·정책 거부
커밋 서버 기준 분리 검증 서버 461개 / SDK 62개 JVM 테스트; 기존 미완 LLM/TTS 변경 제외
release APK·소스 경계 빌드 및 tree/layer/API 검사 통과
독립 코드 검토 접수 범위에서 중대 권한·수명 우회 없음; 문서 누락 보완
제품 정책·실행 배정·공개 Binder·기기 미연결 또는 미검증; 실기기 설치하지 않음

후속으로 실행권→자원 확보→세션 연결을 구현했다. 실행 시점의 정책 재검사와 중복 준비 방지는 내부 테스트로 검증했으며, 스케줄러·제품 관측·실제 완료 연결은 남아 있다. 접수 테스트 통과만으로 MR6 실행기 전체 이식을 완료 처리하지 않는다.

Connections

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date