BroadcastReceiver
BroadcastReceiver는 Android 4대 컴포넌트 중 하나이다.
시스템에서 발생하는 이벤트를 수신하기 위한 목적을 가지고 있다.
예를 들어, 화면이 꺼졌다가 켜진다던지, 단말 부팅이 완료되었다던지, 또는 개발자가 임의로 시스템에 이벤트를 전달하여 Receiver들에게 전달할 수도 있다.
이러한 이벤트를 전달하는 단위를 Android에서는 Broadcast라고 부른다.
이름 뜻 그대로, 방송이라는 의미를 가지고 있다.
그렇기 때문에 이러한 방송을 보고 싶어하는 어플리케이션에서는 이를 수신할 수 있다.
Broadcast는 크게 2가지로 구분된다.
바로 명시적 브로드캐스트 vs 암시적 브로드캐스트 이다.
명시적 브로드캐스트 (Explict Broadcast)
특정 대상(Package, BroadcastReceiver ...)를 명시적으로 지정하여 전달하는 Broadcast를 의미한다.
단 하나의 BroadcastReceiver를 대상으로 전송하는 브로드캐스트이다.
명시적 브로드캐스트는 Manifest에 등록한 Receiver를 통해서도 전달받을 수 있다.
E.g. Package와 Broadcast 클래스를 지정
val 명시적_컴포넌트 = ComponentName(
"com.example.secondexample",
"com.example.secondexample.MyBroadcastReceiver"
)
val 명시적_인텐트 =
Intent("com.example.secondexample.ACTION_MAIN").setComponent(명시적_컴포넌트)
sendBroadcast(명시적_인텐트)
-> com.example.secondexample의 MyBroadcastReceiver 라는 Receiver에게 전달한다.
암시적 브로드캐스트 (Implict Broadcast)
수신할 수 있는 Receiver가 여러개일 수 있는 Broadcast를 의미한다.
API 26(Oreo) 이상부터는 Manifest에 등록한 Receiver로는 암시적 브로드캐스트를 수신할 수 없다.
그러나, 일부 암시적 브로드캐스트는 아직도 Manifest에서 수신할 수 있다.
대표적인 예시로 BOOT_COMPLETED가 있다.
공식문서에 따르면 앱이 부팅되었을 때, 알람 매니저를 재등록하는 등의 행위를 위해 일부는 수신가능하게끔 제한을 두지 않았다고 한다.
하지만 여전히 권장사항은 아니며, 가능한 Context의 registerReceiver()를 통해 앱이 실행 중인 동안에만 수신하는 것이 좋다.
(이유는 아래 설명한다.)
E.g. Action만 지정 (해당 Action을 filtering하는 Receiver는 모두 수신 가능)
val myAction = "com.example.secondexample.ACTION_MAIN"
val intentFilter = IntentFilter(myAction)
registerReceiver(MyBroadcastReceiver(), intentFilter)
val intent = Intent(myAction)
sendBroadcast(intent)
-> com.example.secondexample.ACTION_MAIN 라는 action을 필터링하는 receiver에게 모두 전달된다.
-> 단, API 26 이상에서는 manifest에 등록한 receiver로는 수신할 수 없다.
안드로이드에서 manifest에 등록한 receiver가 암시적 브로드캐스트를 수신하지 못하도록 제한한 이유는 크게 2가지다.
1. 기본적으로 Broadcast를 수신 가능한 Receiver가 있다면, 해당 어플리케이션을 실행시켜 프로세스를 메모리에 올린다.
이 때, 한 번에 많은 앱이 메모리에 올라가면서 화면 버벅임과 같이 사용자에게 좋지 않은 UX를 제공하는 문제가 있다.
2. 암시적 Broadcast를 전달하면, 이를 수신할 수 있는 모든 앱이 메시지를 전달받는다.
그렇다면 악성 앱 또한 예외는 아니다.
악성 앱이 Broadcast를 중간에 가로채는 Message Hooking이 발생할 수 있는 문제가 있다.
반대로 순수한 Receiver에게 악성 Broadcast를 전달하는 Message Facking 문제까지 동반된다.
이러한 여타 이슈로 암시적 브로드캐스트를 manifest에 등록한 receiver로 수신하는 것이 크게 제한되었다.
보안 이슈
위에서 언급했듯, Broadcast는 다른 프로세스와 통신하는 수단이면서도 보안을 취약하게 만드는 큰 원인 중 하나이다.
이러한 문제를 해결하기 위해 아래와 같은 방법을 사용할 수 있다.
1. 앱 내에서만 송수신하는 경우 LocalBroadcastManager 사용을 적극 권장
LocalBroadcastManager.getInstance(this).sendBroadcast(...)
만약, 하나의 앱 내에서만 Broadcast를 송수신할 것이라면 LocalBroadcastManager 사용을 적극 권장한다.
다른 앱에서 Broadcast를 수신할 수 있는 가능성을 아예 배제하여 고려사항을 최소화할 수 있다.
2. protectionLevel 속성 값을 signature로 설정한 임의의 권한을 만들어서, Receiver나 Sender에 지정함.
<permission
android:name="SENDER_PERMISSION_NAME"
android:protectionLevel="signature" />
<uses-permission android:name="SENDER_PERMISSION_NAME" />
...
<receiver
android:name=".MyBroadcastReceiver"
android:exported="true"
android:permission="SENDER_PERMISSION_NAME">
이렇게 설정하면, MyBroadcastReceiver는 SENDER_PERMISSION_NAME이라는 권한이 허용된 Broadcast만 수신하게 할 수 있다.
여기서 protectionLevel을 signature로 설정하는 것이 중요하다.
signature 값은 동일한 Key store를 가진 앱으로 권한을 제한한다. Key store는 앱마다 단 하나씩만 가질 수 있는 고유한 서명이다.
따라서 외부에서 명시적 Broadcast를 보낸다 하더라도, 해당 권한은 자신의 앱만 보유할 수 있으므로 최상의 보안을 가지게 된다.
3. 외부로부터 Broadcast를 수신하지 않는다.
<receiver … exported = false /> 처럼 설정하면 외부로부터 Broadcast를 수신하지 않는다.
4. 명시적 브로드캐스트(Explict Broadcast)를 사용한다.
'Android' 카테고리의 다른 글
[Android] Kerdy에서 다뤄온 Retrofit 에러 처리 (0) | 2023.09.04 |
---|---|
[Android] OkHttp & Retrofit (4) | 2023.06.06 |
[Android] API 33 onBackPressed() deprecated (0) | 2023.05.08 |
[Android] PendingIntent 공식문서 파헤치기 (0) | 2023.05.02 |
[Android] RecyclerView Animation (LayoutAnimation, ItemAnimator) (0) | 2023.04.28 |