Android의 StorageStatsManagerService는 Storage stats에 대한 정보를 제공해주는 Service입니다. 이를 이용하여 App이 디바이스에서 차지하는 size를 계산할 때 사용할 수 있습니다. App뿐만이 아니라 UID, User 별로 차지하는 정보도 알 수 있습니다.
이 Service는 PACKAGE_USAGE_STATS
권한을 요구합니다.
<permission android:name="android.permission.PACKAGE_USAGE_STATS"
android:protectionLevel="signature|privileged|development|appop" />
protectionLevel이 "signature|privileged|appop"
이기 때문에 일반 앱들이 이 권한을 얻으려면 사용자가 세팅앱에 들어가서 앱에게 권한을 부여해줘야 합니다.
권한 요청
먼저 프로젝트를 만들고 AndroidManifest.xml에 permission을 선언합니다.
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
그리고 앱에서 다음 인텐트를 실행하면 이 권한을 부여할 수 있는 세팅앱의 액티비티가 실행됩니다.
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
startActivity(intent);
나의 앱을 선택하고 기능을 활성해해주면 권한을 받을 수 있습니다.
ADB로 권한 부여하기
만약 테스트 목적이라면 adb로 이 권한을 앱에 부여할 수 있습니다.
앱을 설치하고, 다음 adb 명령어를 입력하면 com.codechacha.storagestatssample
앱에 PACKAGE_USAGE_STATS
권한을 줄 수 있습니다.
$ adb shell pm grant com.codechacha.storagestatssample android.permission.PACKAGE_USAGE_STATS
권한이 잘 설정되었는지는 다음 명령어로 간단히 확인해 볼 수 있습니다.
install permissions
에 우리가 추가한 권한이 granted=true
로 되어있어야 합니다.
$ adb shell dumpsys package com.codechacha.storagestatssample
Package [com.codechacha.storagestatssample] (ff5c605):
...
requested permissions:
android.permission.PACKAGE_USAGE_STATS
install permissions:
android.permission.PACKAGE_USAGE_STATS: granted=true
...
특정 Package(App)의 Storage stats 얻기
MainActivity.java
에 아래 코드를 입력합니다.
queryIntentActivities()
로 Launcher에 보여지는 앱 정보들을 가져왔고
StorageStats.queryStatsForPackage(UUID, packageName, UserHandle)
로 각각의 앱에 대한 stats를 얻었습니다.
UUID는 앱이 설치된 Storage의 unique id입니다. 앱이 설치된 Storage의 UUID는 ResolveInfo에서 얻을 수 있습니다. UserHandle은 설치된 User의 handle입니다. 현재 앱이 실행중인 UserHandle을 가져왔습니다.
private void getStorageStatsForPackage() {
StorageStatsManager statsManager = getSystemService(StorageStatsManager.class);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> ris = getPackageManager().queryIntentActivities(intent, 0);
Log.d(TAG, "getStorageStatsForPackage");
if (ris != null) {
for (ResolveInfo ri : ris) {
UUID uuid = ri.activityInfo.applicationInfo.storageUuid;
String packageName = ri.activityInfo.packageName;
UserHandle user = android.os.Process.myUserHandle();
Log.d(TAG, "packageName: " + packageName);
try {
StorageStats stats = statsManager.queryStatsForPackage(
uuid, packageName, user);
Log.d(TAG, "App size: " + stats.getAppBytes() +
", Cache size: " + stats.getCacheBytes() +
", Data size: " + stats.getDataBytes());
} catch (IOException e) {
e.printStackTrace();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
}
}
로그로 결과를 보면 아래처럼 출력이 됩니다.
10-08 23:32:34.617 4660 4660 D MainActivity: App size: 4096, Cache size: 16384, Data size: 36864
10-08 23:32:34.617 4660 4660 D MainActivity: packageName: com.android.deskclock
10-08 23:32:34.617 4660 4660 D MainActivity: App size: 4096, Cache size: 16384, Data size: 126976
10-08 23:32:34.617 4660 4660 D MainActivity: packageName: com.android.settings
10-08 23:32:34.618 4660 4660 D MainActivity: App size: 21114880, Cache size: 16384, Data size: 143360
10-08 23:32:34.620 4660 4660 D MainActivity: packageName: com.google.android.dialer
10-08 23:32:34.620 4660 4660 D MainActivity: App size: 389120, Cache size: 77824, Data size: 143360
Android developer를 보면 StorageStas API에 대한 설명이 나옵니다.
간단히 정리하면...
- getAppBytes()
Apk, 최적화된 dex 파일, native library 등을 포함하는 App의 size를 리턴합니다.
- getCacheBytes()
모든 Cached data의 size를 리턴합니다. Context.getCacheDir()와 Context.getCodeCacheDir()에 있는 경로의 파일들의 크기를 계산합니다.
- getDataBytes()
모든 data의 size를 리턴합니다. Context.getDataDir(), Context.getCacheDir(), Context.getCodeCacheDir()들의 경로에 있는 파일들을 크기를 계산합니다.
입니다. 여기서 cache와 data는 겹쳐지는 영역이 있습니다. data가 cache를 포함하고 있습니다. 만약 전체 크기를 구하려면 cache를 제외한 App과 Data영역을 더하면 됩니다.
특정 UID의 Storage stats 얻기
UID는 UserId를 말합니다. 일반적으로 1개의 앱은 1개의 UID로 구성되어있습니다. 하지만 SharedUID는 여러 앱이 1개의 UID를 공유할 수 있어서, 1개의 UID를 사용하는 앱이 5개가 될 수 있습니다.
여기서는 특정 UID를 사용하는 모든 앱의 size를 구합니다. 어떤 UID를 사용하는 앱이 디바이스에 5개가 설치되어있다면 5개의 앱에 대한 size를 구합니다.
아래 코드처럼 입력합니다. queryStatsForUid(UUID, UID)
를 입력하면 UID에 대한 StorageStats를 리턴해줍니다.
UUID는 Default를 입력했습니다. Default는 단말의 내장 Storage를 의미합니다.
private void getStorageStatsForUid() {
StorageStatsManager statsManager = getSystemService(StorageStatsManager.class);
int systemUid = 1000;
try {
StorageStats stats = statsManager.queryStatsForUid(
UUID_DEFAULT, systemUid);
Log.d(TAG, "[System UID] App size: " + stats.getAppBytes() +
", Cache size: " + stats.getCacheBytes() +
", Data size: " + stats.getDataBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
결과를 보면 입력한 UID를 사용하는 앱들의 전체 size를 알 수 있습니다.
10-08 23:33:47.939 4861 4861 D MainActivity: [System UID] App size: 32768, Cache size: 131072, Data size: 438272
특정 User의 Storage stats 얻기
User는 사용자로, Multi User Mode에서 사용자를 말합니다. 일반적으로 Android에서는 User를 여러개 생성할 수 있는데요. 그 User를 말합니다. 특정 User에 설치된 앱들에 대한 StorageStats를 얻을 수 있습니다.
아래 코드처럼 입력합니다. queryStatsForUser(UUID, UserHandle)
을 입력하면 특정 User에 대한 StorageStats를 얻을 수 있습니다.
private void getStorageStatsForUser() {
StorageStatsManager statsManager = getSystemService(StorageStatsManager.class);
UserHandle user = android.os.Process.myUserHandle();
try {
StorageStats stats = statsManager.queryStatsForUser(
UUID_DEFAULT, user);
Log.d(TAG, "[Current User] App size: " + stats.getAppBytes() +
", Cache size: " + stats.getCacheBytes() +
", Data size: " + stats.getDataBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
결과는 아래처럼 출력이 됩니다.
10-08 23:33:47.944 4861 4861 D MainActivity: [Current User] App size: 36626432, Cache size: 19062784, Data size: 106500096
참고
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력