brunch

You can make anything
by writing

C.S.Lewis

by Chansuk Yang Mar 15. 2019

안드로이드 Q Scoped Storage
이해하기

개발자를 위한 안드로이드 Q #2

개발자를 위한 안드로이드 Q #6

안드로이드 Q Scoped Storage에서 살아남기

시작하기 전에...

포스트는 Scoped Storage 관련된 내용을 다루며, 3월 14일 공개된 안드로이드 Q 베타 버전 기준으로 작성되었습니다. 이후, 정식 버전에서는 기능 및 API가 변경될 수 있으며, 기능에 관한 소감이나 의견은 개인적인 의견으로 회사의 공식 의견과는 다를 수 있습니다.


TL;DR;

안드로이드 Q부터는 Scoped Stroage 개념이 적용됩니다. EXTERNAL_STORAGE 관련 권한이 새롭게 변경되고,  더 이상 이른바 '외부 저장소(일반적으로 'mnt/sdcard/' 경로로 알려짐)'를 자유롭게 읽고 쓸 수 없습니다. 예고된 바에 의하면 타깃 SDK 버전과 관계없이 적용될 것으로 보이며, EXTERNAL_STORAGE 권한을 사용하는 모든 앱은 크고 작은 영향을 받을 것으로 보입니다.

2019년 4월 26일자로 안드로이드 개발자 블로그를 통해, 타깃 SDK 버전이 Q이상인 경우에만 Scoped Storage 적용을 받는것으로 수정되었습니다. 공식 블로그 문서를 참고 부탁드립니다. 


안드로이드 Q 이전

전통적으로 안드로이드 플랫폼의 저장 공간은 크게 내부 저장소와 외부 저장소로 나누어 관리됩니다. 내부 저장소는 시스템 및 개별 앱이 사용하는 공간입니다. 샌드박스 형식으로 잘 보호되는 영역이며, 각 앱은 개별 저장 공간 (아래 그림의 'com.app.a' 형태로 구분된 공간)을 할당받습니다. 이 곳은 Context#getFilesDir() 등 플랫폼 API를 통해 접근할 수 있고, 앱 동작에 필요한 파일을 저장할 수 있습니다. 각 앱은 자신에게 할당된 저장 공간만 접근할 수 있습니다.


기존 안드로이드(Q 이전) 저장소 구분

반면 외부 저장소는 하나의 거대한 공용 저장소로 동작합니다. 외부 저장소를 읽고 쓸 수 있는 권한이 있으면, 누가 생성한 파일인지, 어떤 경로에 저장된 파일인지 관계없이 모든 파일에 접근이 가능합니다. 별다른 제한 없이 모든 종류의 파일을 생성할 수 있습니다. 위 그림에서 처럼, 외부 저장소에도 개별 앱을 위한 별도의 공간이 마련되어 있습니다. 다만, 이 곳은 앱이 권한 요청 없이 해당 공간에 파일을 읽고 쓸 수 있고, 앱 삭제 시 함께 지워진다는 점을 제외하면 (예를 들어, 'com.app.a' 앱은 EXTERNAL_STROAGE 권한 없이도 Private Files 공간의 'com.app.a' 폴더에 파일을 읽고 쓸 수 있습니다) Public Files 공간과 큰 차이가 없습니다. 다시 말해 EXTERNAL_STROAGE 권한이 있는 앱은 여전히 Private Files을 읽고 쓸 수 있습니다.


기존 외부 저장소 관리 방식은 앱 간 파일 공유가 쉬운 등 개발 상의 이점이 있지만, 특정 앱이 사용하고 있는 파일을 추적하기 어렵고, 개별 앱들이 간접적인 방식으로 다른 앱들의 정보를 확인할 수 있는 등 잠재적 위험성을 갖고 있습니다. 따라서, 모든 앱들은 외부 저장소를 사용할 때 주의가 필요하며 안드로이드 보안 권장 사항을 준수해야 합니다. 보다 자세한 내용은 CheckPoint에서 공개한 Man-in-the-Disk: A New Attack Surface for Android Apps 포스트를 참고하셔도 좋을 것 같네요.


안드로이드 Q의 Scoped Storage

사용자 정보 보호를 위해, 안드로이드 Q부터는 '공용 저장소'로서 외부 저장소의 개념이 근본적으로 변화됩니다. 기존 외부 저장소의 Public Files 공간이 완전히 사라지며, 대신 '사진 및 동영상', '음악', '다운로드', '샌드 박스 구조의 개별 앱 공간'으로 나누어 관리됩니다.

안드로이드 Q 버전의 저장소 구분

우선, 개별 앱 공간은 기본적으로는 내부 저장소와 유사한 방식으로 동작합니다.

각 앱은 추가 권한 없이 개별 앱에 할당된 저장 공간을 읽고 쓸 수 있습니다.

개별 앱 공간은 샌드박스 형식으로 격리(isolated)됩니다. 앱은 다른 앱의 저장 공간에 접근할 수 없습니다.


새롭게 추가된 사진, 음악, 다운로드 공간은 공용 공간입니다. 이 공간은 다음과 같은 특징을 갖고 있습니다.

각 공용 공간은 MediaStore를 통해서만 읽고 쓸 수 있습니다.

해당 타입에 맞는 파일만 저장할 수 있습니다 (다운로드 공간은 타입 제한 없음)

추가 권한 없이도 각 공용 공간에 파일을 생성하고, 자신이 생성 한 파일을 읽을 수 있습니다.

앱 삭제 시 해당 앱이 소유한 모든 파일이 삭제됩니다.  


다시 말해, 외부 저장소에 저장되는 모든 파일의 오너십(Ownership)이 명확히 구분됩니다. 자신이 소유한 파일을 읽고 쓰기 위해서는 별도의 권한을 요청할 필요가 없습니다. 공용 공간에 저장된 미디어 파일 중 다른 앱이 생성한  미디어 파일에 접근하는 경우에만 권한이 필요합니다. 이를 위해 안드로이드 Q에서는 새롭게 READ_MEDIA_IMAGES,  READ_MEDIA_VIDEO,  READ_MEDIA_AUDIO 권한이 추가되었습니다. 이해하기 쉬운 직관적인 이름입니다. 다만 다음 두 가지 점에 주의를 기울여야 합니다.


'WRTIE_' 형태의 권한이 존재하지 않습니다.

다운로드 공간 접근을 위한 권한이 존재하지 않습니다. 


우선, '쓰기' 권한이 없기 때문에 자신이 생성한 파일 외에 다른 앱이 생성한 파일을 수정할 수 없습니다. 각각의 파일은 모두 오너십이 지정되어 있기 때문에, 어떤 앱이 얼마나 많은 저장 공간을 차지하고 있는지 쉽게 확인 가능하고, 앱 삭제 시 해당 파일을 모두 삭제할 수 있습니다. 만일, 앱 삭제 후에도 파일을 보존할 필요가 있는 경우에는 MediaStore를 통해 파일을 생성한 후 메타데이터를 추가해야 합니다. 


또한, 다운로드 공간에 관한 권한이 없기 때문에, 각 앱은 다른 앱이 다운로드 공간에 생성한 파일을 직접 읽을 수 없습니다. Q 가이드 문서에 따르면, 다운로드 폴더에 저장된 파일은 (자신이 생성한 파일 제외) 반드시 기본 파일 선택기(System File Picker)를 통해 사용자가 명시적으로 특정 파일을 선택한 경우에만 접근이 가능합니다.

System File Picker를 통한 다운로드 폴더 파일 선택


내 앱에는 무슨 일이 생길까?

외부 저장소를 관리하는 방법이 크게 바뀌는 만큼, 기존에 외부 저장소 읽기, 쓰기 권한을 사용하던 많은 앱들이 직접 간접적인 영향을 받게 됩니다. 개인적으로 주의가 필요하다고 생각되는 사례를 정리해 보았습니다.


1. 외부 저장소를 참조하는 파일 경로(File Path)는 더 이상 동작하지 않습니다.

샌드 박스 모델이 적용되면서, 안드로이드 Q부터는 개별 앱마다 루트 디렉터리가 모두 달라집니다. 더 이상 파일 절대 경로를 사용할 수 없습니다. 만일 특정 파일 접근 및 공유를 위해 절대 경로를 사용하고 있다면, 파일을 찾을 수 없다는 등의 오류가 발생할 수 있습니다. 또한, 샌드 박스 모델이 적용됨으로 각 앱은 전체 외부 저장소 구조나 내용을 확인할 수 없습니다. 개인적으로 애용하는 ASTRO 파일 관리자 앱을 기준으로 Scoped Storage 적용 전 후 표시되는 루트 디렉터리를 비교해보았습니다.

왼쪽이 안드로이드 P의 외부 저장소 루트 디렉터리의 모습이고, 오른쪽이 안드로이드 Q BETA1 버전의 루트 디렉터리 모습니다. Q 버전에서는 자신에게 할당된 격리 공간의 내용만 확인할 수 있고, 그 외 다른 폴더는 확인하거나 접근할 수 없습니다.


2. 사용자를 당황하게 만드는 두 번의 권한 요청 팝업이 뜹니다.

안드로이드 Q에서는 더 이상 EXTERNAL_STORAGE 권한이 사용되지 않습니다. 다만, 타깃 버전이 Q 미만인 앱이 EXTERNAL_STORAGE 권한을 요청하면, 이미지, 비디오, 오디오 공용 공간을 접근하기 위한 권한이 요청됩니다. 개발자 입장에서는 다행이지만, 사용자 입장에서는 어리둥절할 수 있습니다. 권한 요청이 '이미지 &비디오'와 '음악'으로 나누어져 두 번 요청되고, 당연히 권한에 관한 설명도 달라집니다.

구글 드라이브에서 다운로드 기능을 선택할 때 표시되는 권한 요청 팝업

위 권한 요청 다이얼로그는 구글 드라이브에서 '파일 다운로드 기능'을 사용하려고 할 때 나타났습니다. 기본적으로 '쓰기' 권한 자체가 없어졌기 때문에 권한 설명의 내용에 이에 관한 내용이 빠져 있고, 파일 다운로드와는 별 상관없어 보이는 음악, 사진 및 동영상 접근 권한을 요청하고 있기 때문에, 사용자 입장에서 섣불리 권한을 허용하긴 힘들 것 같네요.


참고로 확인해보니, 사용자가 두 권한 중 하나만 허용해도 EXTERNAL_STORAGE 권한을 허용한 것으로 값이 반환됩니다.


어떻게 수정할 수 있을까?

(4월 11일 추가) Scoped Storage 마이그레이션을 위한 보다 자세한 내용은 추가로 포스팅한 '안드로이드 Q Scoped Storage에서 살아남기' 포스트를 참하시면 좋습니다.

지금까지 Scoped Storage가 적용되면 어떤 변경 사항이 있는지 나름대로 정리해보았습니다. 처음 이야기드린 대로 아주 많은 앱의 동작에 영향을 줄 것으로 예상됩니다. 각각의 앱과 제공하는 서비스의 성격에 따라 방법이 달라지겠지만, Scoped Storage 마이그레이션을 위해 기본적으로 염두에 두어야 할 사항을 정리해보았습니다.


1. 꼭 필요한 권한인지 확인합니다.

정말로 대부분의 경우 외부 저장소 접근을 위한 권한을 요청할 필요가 없습니다. 또한 해당 권한을 갖고 있어도 할 수 있는 일도 굉장히 제한됩니다. 우선 EXTERNAL_STORAGE 권한이 꼭 필요한지 다시 생각해 볼 필요가 있습니다. 앱 동작을 위해 필요한 파일을 읽고 쓰기 위해서는 내부 저장소와 마찬가지로 샌드 박스 형태로 제공되는 개별 앱 공간을 활용합니다. 이 영역을 접근하기 위해서는 별도의 권한이 필요하지 않습니다.


오직 다른 앱이 생성한 특정 타입의 미디어 파일을 읽어오는데만 외부 저장소 접근 권한이 요구됩니다. 그 외 다른 앱이 생성한 임의의 파일 (PDF, TXT, ZIP 등등)에 접근하기 위해서는 반드시 시스템 기본 파일 선택기를 통해, 사용자가 대상 파일을 선택해야 합니다. 이 과정은 별도 권한 요청 없이 가능합니다. 다시 한번 강조하자면, 프로그램 상에서 사용자의 명시적 선택 없이 다른 앱이 생성한 미디어 타입이 아닌 파일에 접근할 수 있는 방법은 없습니다.


다만, Q 이전 버전을 지원하기 위해 여전히 EXTERNAL_STORAGE 권한을 매니페스트에 포함해야 할 수 있습니다. 이 경우 Q 이전 버전에서만 해당 권한을 사용하도록 아래와 같은 방식으로 <uses-permission> 태그와 함께 android:maxSdkVersion 속성을 지정해 권한을 선언할 수 있습니다.


2. 다른 앱과 파일 공유를 위해서는 ContentUri를 활용합니다.

앱의 성격에 따라 자신의 소유 파일을 다른 앱과 공유해야 할 수 있습니다. 이를 위해 더 이상 특정 File 경로를 바로 넘기는 방식을 사용할 수 없습니다. 대신, FileProvider를 사용해 해당 파일에 접근할 수 있는 ContentUri를 만들고, 파일을 공유받을 대상 앱에 임시로 Uri 접근 권한을 허용하는 방법을 사용해야 합니다.  이 방법은 Q 이전부터 안드로이드 보안 권장 사항 중 하나였습니다. 더불어 안드로이드 7.0 이후 버전부터는 다른 앱에 File 경로를 Intent로 전달하면 FileUriExposedException 오류가 발생하도록 플랫폼 동작이 변경되기도 했습니다.


3. 다른 앱이 만든 파일 내용을 수정하려면 해당 기능을 위한 기본 앱이 되어야 합니다.

사진 편집 앱이나 음악 앱인 경우 이미지에 뽀샤시 필터를 적용하거나, 태그 정보를 수정하는 등 다른 앱이 만든 미디어 파일을 직접 수정해야 할 필요가 있습니다. 외부 저장소 쓰기 권한이 없는 안드로이드 Q에서는 원칙적으로 이러한 작업을 할 수 없습니다.


다만, 안드로이드 Q에서는 사용자가 디바이스에서 수행하는 몇 가지 대표적인 작업들을 '역할'로 정의하고 각각의 작업을 수행하는 기본 앱을 지정할 수 있도록 새롭게 '역할 (Role)'이라는 기능이 추가되었습니다. 현재 안드로이드 Q 베타 1 버전에는 브라우저, 전화, 음악, 갤러리, SMS 등의 역할이 정의되어 있습니다. 특정 역할에 대해 어떤 앱이 기본 앱으로 정의되었는지는 안드로이드 설정의 '앱 및 알림 > 기본 앱 > 역할' 메뉴에 들어가면 확인할 수 있습니다.

<안드로이드 Q 베타의 '역할' 설정 메뉴>


만일 앱이 기본 음악 앱이나 갤러리 앱으로 설정되는 경우, 해당 앱은 다른 앱이 생성한 미디어 파일을 직접 수정할 수 있는 권한을 갖게 됩니다. 특정 역할에 대해 기본 앱으로 설정되기 위해서는 몇 가지 조건을 만족해야 하며, 개발자는 코드 상에서 자신의 앱이 특정 '역할'의 기본 앱으로 설정되었는지 여부를 확인할 수 있습니다. 또한, 필요한 경우 사용자에게 이를 요청할 수도 있습니다. 다만, 아직까지는 각 역할마다 오직 하나의 앱만 기본 앱으로 설정될 수 있는 것으로 보이네요. 이에 관한 보다 자세한 내용은 'Roles' 개발자 문서를 살펴보시면 좋을 것 같습니다.


테스트 및 호환성 모드

(4월 11일 추가) 안드로이드 Q 베타 2 패치 버전 이 후로 Scoped Storage 기능이 기본적으로 활성화되도록 변경되었습니다. 다만, 이미 베타 2 패치 업데이트 전에 설치된 앱에는 적용되지 않음으로, 기존에 설치된 앱을 테스트하기 위해서는 공장 초기화 혹은 앱 재설치가 필요합니다.

마지막으로, 안드로이드 Q 베타에서 Scoped Storage 기능을 테스트할 때는 두 가지 주의점이 있습니다. 먼저, 베타 1 버전에서는 기본적으로 Scoped Storage 기능이 꺼져 있습니다. 개발자 문서의 안내에 따라 아래 ADB 명령어를 통해 기능을 활성화해야 합니다.

또한, 안드로이드 Q 베타 업그레이드 전에 이미 설치되어 있던 앱이나, 위 기능을 ON 하기 전에 이미 디바이스에 설치되었던 앱들은 이른바 '호환성 모드'에서 동작하며, Scoped Storage 기능이 적용되지 않습니다. 올바를 테스트를 위해서는 해당 기능을 ON 한 후 테스트 대상 앱을 삭제 후 재설치해야 합니다.


지금까지 Scoped Storage의 개념과 주요 변경 사항을 살펴보았습니다. 참고로 호환성 모드는 사용자가 안드로이드 Q 업데이트 후, 갑자기 기존 앱 동작이 멈추는 것을 방지하기 위해 제공된다고 하며, 앱의 타깃 SDK 버전 등과는 무관하게 신규 앱 설치 시에는 적용되지 않는다고 합니다. 호환성 모드를 믿고 Scoped Storage 마이그레이션을 늦추는 것은 매우 매우 위험한 결정이 될 것으로 보입니다. 원칙적으로 호한성 모드는 이른바 최후의 방어선으로 생각하시고, 가능한 한 빨리 Scoped Storage 호환성 테스트를 진행해보시기 바랍니다.

2019년 4월 26일자로 안드로이드 개발자 블로그를 통해, 타깃 SDK 버전이 Q이상인 경우에만 Scoped Storage 적용을 받는것으로 수정되었습니다. Scoped Storage 적용 및 테스트는 타깃 SDK 버전을 올리는 시점에 맞춰 진행하면 될 것으로 보입니다. 공식 블로그 문서를 참고 부탁드립니다. 


개발자를 위한 안드로이드 Q 정리

개발자 주의가 예상되는 안드로이드 Q의 변경 사항을 정리해 '개발자를 위한 안드로이드 Q 정리'라는 브런치 매거진으로 발행하고 있습니다. 

1. 사용자 정보를 보호하기 위한 변경 사항 훑어보기

2. 새로운 외부 저장소 정책 - 'Scoped Storage'

3. 초기화할 수 없는 하드웨어 고유 식별자 사용 금지

4. 새로운 기기 위치 접근 권한 - '앱 사용 중 허가'

5. 백그라운드 액티비티 시작 제한  

6. 안드로이드 Q Scoped Storage에서 살아남기


우선적으로 베타 1 버전에는 개발자들의 주의가 필요한 (그래서 무서운) 동작 변경 사항에 관해 주로 다루었지만, 이후 베타 2 버전이 공개되면, 개발자 입장에서 재밌고 새롭게 적용해볼 만한 신기능에 관해서도 다루어 볼 예정입니다 (그런 게 있겠죠?). 그런 만큼, 안드로이드 Q 버전이 정식 출시될 때까지, 
'개발자를 위한 안드로이드 Q 정리 매거진'에 많은 관심 부탁드립니다 : ) 

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari