언어/Android_Kotlin

[OS] Android와 iOS의 OS 비교

코코몹 2026. 6. 20. 16:58

[주제]


Android와 iOS의 OS 차이

 

[목차]


1.커널 & 아키텍처 & 샌드박스
2. LifeCycle & 메모리
3. 파일시스템 / 스토리지 접근
4. 권한(Permission) 시스템

[커널 & 아키텍처 & 샌드박스]

 

Android - iOS 비교

1.커널&아키텍처

  Android iOS
커널 Linux 커널 기반
- POSIX Message Queue, POSIX Shared Memory, unix domain socket  등 사용 가능
XNU 커널 (Mach 마이크로 커널+ BSD 서브시스템 혼합)
- POSIX Shared Memory, unix domain socket 등 사용 가능
개발사 Google (오픈소스 AOSP) Apple (클로즈드 소스)
런타임 ART (Android Runtime)* Objective-C 런타임 / Swift*
언어 기반 Java/Kotlin → DEX 바이트코드* Swift/ObjC → 네이티브 컴파일*

-----------------------------------------------------------------!!!!!!!!!!!!!!!!!!!!!!!---------------------------------------------------------------------
2. 샌드박스(=앱에게 주어진 격리된 실행 공간) 

  Android iOS
격리 기준    
system call 허용 여부    
샌드박스 앱마다 고유한 UID가 부여됨 * 커널이 UID 단위로 리소스 접근 통제 *
     
     


격리 기준 UID (신원) system call 종류 (행위)
system call 허용 여부 허용 (호출 가능)
일부 차단 (호출 불가)

e.g. OS 전역 네임스페이스 등록
통제 시점 커널 내부 (객체 접근 시) 커널 진입 전 (Seatbelt)
같은 앱 내부 자유롭게 사용 가능 동일하게 차단
차단 주체 Linux 커널 (UID mismatch) Seatbelt 프로파일
격리 기준과 차단 상세


앱 실행시 Sandbox Profile이 적용

Profile이 허용된 system call 목록을 정의

e.g.
앱 A (UID 10001) → /dev/shm/queue_a (소유자: 10001)
앱 B (UID 10002) → /dev/shm/queue_a 접근 시도

→ 커널: UID 불일치 → 접근 불가능

단, 같은 앱 내부라면 자유롭게 접근 가능
shm_open() 호출 시도

→ Profile 허용 목록에 없어 호출 실패

XNU 커널에서 system call 차단
iOS 앱은 실행 시 Apple이 정의한 Sandbox Profile이 적용되어 특정 system call을 막음
e.g.

shm_open() - 데이터 저장 공간 생성 허용 샌드박스 차단
sem_open() - 동시 접근 제어 허용 샌드박스 차단
shmget() - shm_open()의 구형 방식 허용 샌드박스 차단
→ iOS에서 샌드박스 정책으로 iOS에서 boost::message_queue 사용 불가능
-----------------------------------------------------------------!!!!!!!!!!!!!!!!!!!!!!!---------------------------------------------------------------------
3.IPC 통신

  Android iOS
소켓 종류 boost::message_queue Unix Domain Socket
연결 실패시 큐에 보관 연결 전까지 유실
큐/버퍼 가득 참 send() 블로킹 send() 블로킹
프로세스 종료 시 큐 파일 남아있음 소켓 파일 삭제 필요

 

+ 프로세스 종료 시

  Android iOS
잔존 파일의 역할 실제 메시지를 담는 저장소(버퍼) 단순 연결 주소(엔드포인트)
남아있을 때 영향 오히려 유리함 — 재시작 후에도 이전 메시지를 이어받을 수 있음 불리함 — 재시작 시 같은 경로 bind() 실패의 원인이 되므로 반드시 삭제 필요

- boost::message_queue는 내부적으로 shm_open()으로 공유 메모리 객체를 생성함. 이 공유 메모리는 프로세스 생명주기와 독립적

- UDS는 bind() 호출 시 단순히 주소 역할만 하는 소켓 파일(inode)를 생성. 이전에 생성된 경로에 대해 재시작시 다시 bind()를 시도하면 boost::message_queue와는 다르게 Address already in use 에러가 발생함


이슈

수신 모듈 초기화 되지 않은 상태에서 IPC 통신 동작

iOS에서 수신 모듈이 초기화 되지 않았을 때 IPC 통신시도시 내용이 유실됨



해결

NFC 내부적으로 iOS 환경에서 bForce = true 옵션의 SendEvent 실패시 벡터에 저장

이후 수신 모듈이 켜지면 저장된 이벤트를 재전송 하도록 대응

-> message_queue가 해주던 "알아서 보관해줄께"를 NFC에서 직접 구현한 셈

[LifeCycle & 메모리 관리]

 

Android - iOS 비교

백그라운드 전환

  Android iOS
백그라운드 진입 onPause → onStop inactive → background
백그라운드 제한 상대적으로 관대 엄격한 실행 시간 제한
백그라운드 작업 실행이 보장됨
실행 시간 제한 없음
즉시 실행 조건부로 또는 그냥 가능

OS 재량으로 실행됨
실행 시간이 각각 수십 초 ~ 수 분, 30초 이내로 짧음
즉시 실행 불가능
Thread 실행 백그라운드에서도 계속 모든 Thread 중단
앱 종료 감지 onDestroy 비교적 신뢰 가능 종료 감지 콜백 없음


라이프사이클

Android iOS

Foreground에서 Background 전환
Resumed → onPaush() → Paused→ onStop() → Stopped

Background에서 Foreground 전환
Stopped → onRestart() → Started → onResume() → Resumed
Foreground에서 Background 전환
Active → (willResignActive) → Inactive → (didEnterBackground) → Background

Background에서 Foreground 전환
Background → (willEnterForeground) → Inactive → (didBecomeActive) → Active
  iOS는 Inactive가 중간 상태로 반드시 거침
iOS의 Suspend는 Android의 Stopped와 비슷하지만, 메모리 부족 시 콜백 없이 강제로 종료됨
iOS는 Android의 onDestroy()에 해당하는 명시적 종료 콜백이 없음
iOS에서 Background → Suspended 전환, Suspended에서 앱 종료를 OS가 전적으로 결정함




메모리 관리

  Android iOS
메모리 관리 ART (Android Runtime)
- 런타임에 힙을 스캔, 참조되지 않는 객체를 찾아 회수
ARC (Automatic Reference Counting)
- 컴파일에 컴파일러가 객체 참조/해제 시점마다 retain/release 호출 코드를 자동으로 삽입
백그라운드 프로세스 상대적으로 유지 허용 적극적으로 종료 (메모리 부족 시)
OOM Killer Linux OOM Killer 동작* Jetsam (iOS 전용 메모리 관리 데몬)*
멀티태스킹 진정한 멀티태스킹* 제한적 멀티태스킹 (상태 저장 후 동결)*

 

이슈

iOS에서 백그라운드 전환시 프로세스 상태체크 타이머가 중지됨

 


원인

백그라운드 실행 정책 차이


해결

AppStatus가 Foreground로 변경될 때 체크 시작, Background로 변경될 때 체크 종료 및 TickTime 목록 초기화

 

 

[파일시스템 / 스토리지 접근]

 

  Android iOS
Overview
앱 내부 저장소 앱 전용 공간으로 UID가 다른 앱은 커널이 접근 차단
- 한 건물(파일 시스템) 안에서 각자 방 열쇠(UID)가 다름
앱별로 UUID 컨테이너(Documents, Library, tmp가 존재)가 생성
- 애초에 건물 자체가 앱마다 따로 존재
외부 저장소 접근 SD카드, Downloads 폴더 자유 접근 가능 불가 — 외부 저장소 개념 자체가 없음
앱간 파일 공유 FileProvider가 URI로 변환해 전달 반드시 OS가 중개하는 방식만 허용

 

Android 앱간 파일 공유

A 앱   FileProvider   B 앱
앱의 파일 경로
data/app.a/
->  content://URI 변환 -> URI로 읽기
(직접 경로는 모름)

 

iOS 앱간 파일 공유 - 타 앱으로 보내기

A 앱 B 앱 비고
UIActivityViewController 표시  
공유 시트에서 B 앱 선택    
OS가 파일을 B 앱애 전달    
  Share Extension이 파일 수신  

 

iOS 앱간 파일 공유 - 타 앱에서 받아오기

A 앱 B 앱 비고
파일 공유 요청    
UIDocumentPicker 표시  
사용자가 파일 선택    
  OS가 보안 범위 URL 발급  
URL로 파일 접근    

[권한(Permission) 시스템]

 

  Android iOS
권한 선언 위치  AndroidManifest.xml Info.plist
권한 설치시 자동 부여 Normal Permission외 자동 부여

(Android Normal Permission 예
INTERNET  / BLUETOOTH / SET_ALARM / USE_PINGERPRINT...)
전부 런타임 부여
권한 미선언 시 런타임 요청 거부 앱 크래시
런타임 재요청 가능 불가 — Settings 유도만

(Apple은 권한 변경 주도권을 앱이 아닌 사용자에게만 줌
-> iOS에서 권한을 거부하면 denied로 기록되고 해당 권한 관련 다이얼로그 표시를 아예 차단함)
목적 문자열 불필요 필수 (없으면 크래시)

"This app use ~ "가 목적 문자열
Info.plist에 키-값 형태로 선언됨