기기 정책: 판단 순서·예외·실제 반환값
기준:
a1-packages-mr6,quber/mr7,7695c9a85fedf6d756490e51c07f6e09f568a4bd. 추적 소스의 정적 분석이다. 미추적 TaskManagerClient 및 작업 산출물은 포함하지 않는다. APK·AOSP 빌드나 기기 동작 검증은 이번 분석 범위가 아니다.
모든 축약 경로 DA/는 apps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/다. 이 표는 제품 요구사항을 새로 제안하는 문서가 아니라 지정 커밋의 실제 분기를 설명한다.
정책을 수정할 때
정책별 적용 범위표에서 일반 명령·예약·WSS의 차이를 먼저 비교한다. 아래 조건표의 조기 반환·주석·마스킹·재허용까지 현재 동작에 포함된다. 정책 소유 파일만 수정해도 공유 소비자가 영향을 받을 수 있으므로 변경 영향 지도와 함께 검토한다.
정책은 여러 단계에 분산되어 있다
MainApi → StateManager → 해당 API 분기 → CmdPolicyManager 또는 기능별 Policy → Manager/Controller가 대표 경로다. 예약 Receiver, WSS 전용 Binder, 설정 setter에는 별도 판단과 side effect가 있다. 모든 API가 하나의 직렬 정책 파이프라인을 통과한다고 해석하면 안 된다.
1. MainApi와 제품 상태
| 판단 지점 | 활성 코드의 동작 | 근거 |
|---|---|---|
| 재부팅 명령 | UPGRADE이면 거절. 일반 메서드 차단과 별도 분기 | DA/main/api/MainApi.java:159–174, DA/event/StateManager.java:110 |
| FACTORY | FactoryState로 위임하고 결과에 따라 반환 | DA/main/api/MainApi.java:179–183 |
| ICT | getFirmwareVersion/setA1Version 예외 외에는 ICTState로 위임 후 반환 | DA/main/api/MainApi.java:184–191 |
| SELFTEST | SelfTestState로 위임 후 반환 | DA/main/api/MainApi.java:193–195 |
| UPGRADE / VITALSIGN | setAMROperation, scheduleiot, setAirCleanerOperation, airSensorDetected, setstation, setMoveTo, setConfig, getConfig, gpsLocNearBy, control 차단 | DA/event/StateManager.java:149–169 |
| STREAMING_ALPHA | setAMROperation, scheduleiot, setAirCleanerOperation, airSensorDetected, setMoveTo, gpsLocNearBy 차단 | DA/event/StateManager.java:170–178 |
setMainState/getMainState에는 별도 stateMethod 예외가 있다. isProductOperationState()와 checkBlockedStatus()는 같은 검사도, 같은 차단 목록도 아니다. 전자는 FACTORY/ICT/UPGRADE/SELFTEST를 일반 운영에서 제외하고, 후자는 특정 상태에서 특정 메서드 이름을 막는다.
2. CmdPolicyManager의 공통 판단 순서
입력은 청정 파라미터, 수행 모드 mMode, checkOption이다. 판단 전 CleaningTransaction, InterScheduleManager, RobotMovementController, MovingController, AMRService, ErrorHandler, LlmManager를 읽는다. 아래 순서에서 조기 반환하면 뒷부분은 실행되지 않는다.
| 순서 | 조건 | 결과·예외 | 근거 |
|---|---|---|---|
| 1 | 일반 제품 운영 상태가 아님 | 거절 | DA/policy/CmdPolicyManager.java:265–275 |
| 1b | 특정 모드 상태 | 저전력 복귀 예외가 아닐 때 VITALSIGN·MULTI_AP 설정·예약 편집·WIZARD 상태를 거절. 저전력 복귀이면 이 switch를 건너뜀 | DA/policy/CmdPolicyManager.java:282–296 |
| 2 | LLM 처리 중 | 기본 거절. IGNORE_LLM 옵션 또는 AIR_SENSOR 새 청정은 예외 | DA/policy/CmdPolicyManager.java:302–313 |
| 3 | 오류 분류 | MAJOR는 청정·이동·인터랙션 모두, MOVING_EX_S02는 이동 관련, CLEANING은 청정 관련 block 필드 설정. 일부 저전력 복귀 예외 | DA/policy/CmdPolicyManager.java:172–192, :318–366 |
| 4 | station 위 BASIC 새 청정 | 여기서 허용 반환. 뒤의 배터리·준비·편집 조건까지 통과했다는 뜻은 아님 | DA/policy/CmdPolicyManager.java:371–380 |
| 5 | S03 임계 저전력 | 거절 | DA/policy/CmdPolicyManager.java:385–388 |
| 6 | AMR 연결/도킹 상태 준비 안 됨 | 이동 성격의 모드 차단. 시뮬레이션 예외 | DA/policy/CmdPolicyManager.java:393–400 |
| 7 | S02 저전력 | 새 청정·일반 이동·예약 차단 | DA/policy/CmdPolicyManager.java:405–415 |
| 8 | 긴급 복귀 진행 중 | 일반 복귀·이동·예약 차단 | DA/policy/CmdPolicyManager.java:420–427 |
| 9 | 프라이버시 | 이동 성격 명령 차단. 저전력 복귀 예외 | DA/policy/CmdPolicyManager.java:432–440 |
| 10 | A1 초기화 미완료 | 거절. TempSettings의 무시 옵션 존재 | DA/policy/CmdPolicyManager.java:445–450 |
| 11 | 지도 편집 중 | 거절 | DA/policy/CmdPolicyManager.java:456–459 |
| 12 | WSS 진행 중 | 로그는 남기지만 거절 return이 주석 처리됨 | DA/policy/CmdPolicyManager.java:461–468 |
오류 분류는 if/else-if 우선순위이므로 모든 오류의 block 집합을 단순 합산하는 형태가 아니다. 실제 동시 오류 조합은 이 순서로 읽어야 한다.
기능별 후속 판단과 실행
newClean: 공통 검사 후 기존 청정·이동·인터랙션이 있으면 기본 거절. air-sensor 요청은 복귀 중 pause 또는 station BASIC 청정에서 PARTIALLY_ALLOWED 예외.DA/policy/CmdPolicyManager.java:471–510.setMoveTo: 목적지 areaId가 MapManager 목록에 없으면 거절. 허용 시RobotMovementController.move()를 직접 호출한다. “검사만 하는 함수”가 아니다.DA/policy/CmdPolicyManager.java:530–556.returnToStation: 공통 검사 후 LiveView이면 AMR 직접 복귀 분기. 이미 station/복귀 상태일 때도 stop/resume side effect가 있을 수 있다. 새 복귀는 stopAllAction 뒤 moveToStation으로 연결된다.DA/policy/CmdPolicyManager.java:716–783.schedule: follow-me/STREAMING_ALPHA 차단. station BASIC 청정은 선행 stop 후 허용할 수 있고 다른 청정·이동·인터랙션은 거절한다.DA/policy/CmdPolicyManager.java:786–827.
저전력 예외는 주석보다 실행값을 우선한다
allowedLowBatteryReturnToStation_ignoreOtherCond = true다. S02 + 일반 복귀 모드이면 일부 오류·프라이버시 차단을 우회한다. 그 위의 과거 주석은 다른 조건을 체크한다고 설명하지만 현재 flag와 활성 분기는 다르다. 그렇다고 모든 차단이 무시되는 것은 아니다. 제품 상태, S03 등 별도 선행·후행 검사는 남아 있다.
근거: DA/policy/CmdPolicyManager.java:118–132, :231–239, :318, :350, :432.
3. AirCleaningPolicy: 계산값과 반환값의 차이
BaseCleaningManager.set()은 새 START일 때 getPolicy()를 호출한다. 홈 잠금이면 POLICY_BLOCKED를 조기 반환하고, capacity가 0 이하라 AMR 미연결로 취급되면 즉시 허용을 반환한다. 그 이후 station/배터리/청정 범위 분기는 mPolicy를 계산하지만 함수 마지막 반환값은 POLICY_NOT_DEFINED(-1) 이다.
호출자는 BLOCKED / STOP_AND_START / WAIT_AND_START만 구분하고 나머지 값은 즉시 시작 허용으로 처리한다. 따라서 이 함수 내부의 15% 이하 계산만 보고 “배터리 차단이 실제 적용된다”고 주장할 수 없다. 새 청정의 MainApi 경로에는 별도로 CmdPolicyManager가 있으므로 전체 시스템에 배터리 차단이 없다는 뜻도 아니다.
근거: DA/cleaning/AirCleaningPolicy.java:60–113, :120, :127–201; DA/cleaning/BaseCleaningManager.java:223–257; DA/main/api/MainApi.java:636–665.
또한 self-test 검사는 TODO이고, 청정 진행 여부는 false로 강제한다. 이전 개요의 “self/line test 검사”, “계산한 정책에 따른 stop 후 재시작” 설명은 활성 구현을 과도하게 일반화했다. 이 상세 분석이 그 부분을 정정한다.
4. 예약 정책: 일반 조건과 Security 예외
| 단계 | 판단/연결 | 근거 |
|---|---|---|
| 알람 수신 | DB의 존재·활성 확인, 요일/휴일/시간 검사. GPS는 시간 조건 예외 | DA/schedule/ScheduleAlarmReceiver.java:71–100 |
| 중복 억제 | 마지막 실행 시각을 메모리에 기록. 시뮬레이션 우회 | DA/schedule/ScheduleAlarmReceiver.java:91–108 |
| 최우선 OTA | triggerScheduleAction의 UPGRADE 검사에서 즉시 반환 | DA/schedule/ScheduleAlarmReceiver.java:291–298 |
| 일반 허용 조건 | mapping, privacy, station BASIC 조건, night, home lock, area 유효성, 보안 실행 여부 검사 | DA/schedule/ScheduleAlarmReceiver.java:134–229 |
| Streaming | 실행 중이라고 로그를 남기지만 이 if에는 return false가 없음 | DA/schedule/ScheduleAlarmReceiver.java:231–233 |
| 복귀 중 예외 | 복귀/도킹 중이면 CmdPolicy.schedule와 주행 priority 검사를 건너뜀 | DA/schedule/ScheduleAlarmReceiver.java:235–251 |
| Security 재판정 | 일반 검사가 실패해도 canExecuteSafeCareSchedule가 true면 진행 | DA/schedule/ScheduleAlarmReceiver.java:256–312 |
| 전달 | setSchedule Bundle을 Main callback으로 송신 | DA/schedule/ScheduleAlarmReceiver.java:334–349 |
Security 재판정은 실패 원인을 전달받지 않는다. 따라서 “특정 일반 조건만 예외”라고 축소해서 설명하면 부정확하다. S02+station, 편집 모드, 일부 동작 진행 상태 등의 허용 분기에 들어가면 일반 검사 실패 뒤에도 Launcher 전달 단계로 진행할 수 있다. 이후 WSS 자체 정책과 실제 시작은 별도로 확인해야 한다.
5. WSS 정책과 호출자 권한
일반 명령 정책과 별도로, WSS Binder는 SYSTEM_UID와 FRONT/REMOTE 역할을 API마다 확인한다. 이것은 “누가 호출 가능한가”의 정책이고 WssPolicyChecker는 “현재 기기가 실행 가능한가”의 정책이다.
WssPolicyChecker는 camera/tilting error, privacy, home lock, PIN, 로컬 네트워크와 AWS 상태, 구독 상태, 배터리 오류를 reason bit에 누적한다. 이동형은 map/주행 오류를 추가하고 follow-me/vital/LLM/upgrade/self-test 상태도 검사한다.
근거: DA/ipc/WssControlStub.java:90–114; DA/wss/policy/WssPackageValidator.java:58–109; DA/wss/policy/WssPolicyChecker.java:48–167.
반환 해석: basic과 patrol 모두 허용 여부 계산에서 배터리 reason 두 개를 마스킹한다. reasonCodes에는 비트가 남아 있으므로 allowed=true와 battery reason이 공존할 수 있다. LLM trigger는 WssManager에서 추가 reason을 제외하고 허용 여부를 다시 계산하며 station 상태에 따른 예외도 있다. 단계별 boolean/reasonCodes를 함께 봐야 한다.
근거: DA/wss/policy/WssPolicyChecker.java:171–187; DA/wss/WssManager.java:520–558.
6. 설정 정책은 저장과 부수 동작으로 연결된다
| 설정 | setter의 동작 | 소비 정책 |
|---|---|---|
| Privacy | Vision stop/start, tilt 조건 reset, system property·Preferences 저장, SoundFlow mode, LLM 통지 | CmdPolicy 이동 검사, 예약, WSS |
| Home lock | Preferences 저장, SoundFlow LOCK mode, LLM 통지 | AirCleaningPolicy, 예약, WSS |
| Night | 활성 값 저장, LCD/LED, 청정 ghost mode, volume refresh, IoT/PUI 갱신. 해제 시 calibration 호출 | 예약 차단 및 표시·청정 동작 |
근거: DA/settings/Settings.java:329–358, :433–447, :913–923.
설정 API 반환은 카메라/마이크/장치의 실제 정지 확인과 같은 의미가 아니다. 각 서비스 반영 callback·기기 로그가 있어야 완료를 판단할 수 있다.
7. OTA 입장 조건: IotAgent의 요청 유형별 차이
IotAgent.onDownloadUpdateAgent(downloadurl, jobid)는 jobid가 비어 있지 않은 요청에만 다음 조건을 검사한다. station에 없거나 배터리가 30% 미만이면 실패하고, vital sign·STREAMING·PATROL_SECURITY/FIXED_SECURITY 중에도 FAILED 사유를 반환한다. 빈 jobid는 주석상 Samba/local 요청이며 이 검사 블록을 건너뛴다. 따라서 “OTA는 항상 station과 배터리 조건을 검사한다”는 설명은 이 함수의 실제 분기와 다르다.
통과 후 mRobotStatus_update=true와 상태 송신을 수행하고 com.sk.airbot.updateagent/.ui.MainActivity를 명시적으로 실행한다. Intent에는 PATH, MODE=local, jobid, downloadurl을 전달한다. 다운로드·UpdateEngine 완료는 이 입장 판정과 별도다.
근거: apps/IotAgent/app/src/main/java/com/sk/airbot/iotagent/IotAgent.java:1748–1795.
Connections
상세 분석 목차 · 기존 전체 SVG 지도 · 정책 조건표 · 실행 시나리오