태그 보관물: 퍼미션

System 앱의 퍼미션 획득

설명하기 번거롭고 아무도 궁금해하지 않는 System 앱으로서 permission 획득(granted)하는 방법을 알아보자. 미리 이야기 할 것은, 안드로이드에 system이란 protectionLevel은 없다. signatureOrSystem이 있는데, 이 protectionLevel을 가진 permission의 획득 방법 두 가지 중 system 앱으로서 획득하는 방법에 대해 설명한다.

설명을 하기 위해서는 먼저 앱을 단말 내장 여부에 따라 구분해야 한다. 앱을 내장 여부에 따라 구분하는 일이 적어서 용어가 정착되지 않았는데, 여기서는 스토어/프리로드 앱으로 표현하겠다.

  • 스토어(store) 앱 : 단말에 내장되어 있지 않고, 단말 제조사나 구글의 앱 스토어에서 받아 설치(or 업데이트)할 수 있다. 일반 앱이나 서드파티 앱이라고도 부른다.
  • 프리로드(preload) 앱 : 단말에 내장되어 있고, 단말 제조사나 구글의 앱 스토어에서 업데이트 할 수도 있다.

프리로드 앱 중에서 특히 /system/priv-app/ 에 설치된 앱을 system 앱이라 한다. 혹은 프리빌리지드(privileged) 앱이라고도 부른다. 이 앱이 protectionLevel가 signatureOrSystem인 permission을 획득(granted)할 수 있다.

system 앱으로서 permission을 획득하는 방법을 설명했으니, permission에 영향을 줄 수 있는 system 앱의 특성을 살펴보자.

이를 위해서는 먼저 두 앱 간 설치/업데이트/삭제 시 차이점을 설명해야 한다. 스토어 앱은 최초 설치 시 /data/app/에 자리를 잡고, 업데이트 시에도 같은 위치에 덮어 씌운다. 삭제 시 업데이트 여부에 관계없이 /data/app/에 설치되었던 앱과 데이터가 사라진다.

프리로드 앱은 최초 설치 시 /system/priv-app/에 자리 잡고, 업데이트 시 /data/app/에 자리 잡는다. 삭제는 업데이트 여부에 따라 다르다. 최초 버전은 삭제할 수 없고, 업데이트 버전만 삭제할 수 있다. 삭제 시 /data/app/에 설치되었던 업데이트 버전의 앱이 사라진다.

이를 설명한 이유는 system 앱은 최초/업데이트 버전 여부에 따라 설치위치가 달라지고, 이에 따라 permission 획득도 달라질 수 있기 때문이다. 업데이트 버전에 <user-permission/> 선언을 신규추가한 경우 protectionLevel이 signatureOrSystem인 permission을 획득할 수 없다. 위에 설명한 것 처럼 업데이트 버전은 /system/priv-app/이 아닌 /data/app/에 설치되기 때문이다.

다만, 내장된 버전이 AndroidManifest의 <use-permission> 선언을 통해 이미 획득한 permission은 업데이트 버전도 선언만 하면 상속받는 것처럼 획득할 수 있다. 꼭 새 permission을 system 앱으로서 획득하고 싶다면 바이너리에 포함해야 한다.

그 밖에

  • 안드로이드의 permission에 4가지 protectionLevel에 대한 소개는 이 글을 확인하자.
  • 프리로드 앱은 system 앱 외에 다른 종류도 있다. 최초 부팅 시에 설치 되어있지만, 삭제 가능하며 단말 초기화(factory reset) 시 다시 설치된다. 이들은 /data/app/에 설치되므로 단말에 내장된 점을 제외하고 일반 앱과 같다.
  • 처음에 system앱은 /system/이하에 설치되는 앱을 말하며 system앱 모두가 권한을 가졌다. 그러나, /system/priv-app/에 설치되는 앱에만 권한을 주도록 정책이 축소&변경된다.  (아마도) 이 때 system앱과 구별하기 위해 previleged 앱이라 부르다 현재는 특별한 권한을 가진 앱을 가리킨다는 점에서 혼용하는 것 같다.

참조

 

안드로이드 package dump 분석

이 글은 단말 dumpstate 파일 중에서 패키지 정보에 대한 부분만 소개하는 글이다. dumpstate의 설명을 찾는면, 이 글을 살펴보자.

패키지 dump는 dumpstate에도 포함되어 있고, 아래와 같은 명령어를 통해 단말에서 패키지 dump만 뽑을 수도 있다.

 adb shell dumpsys package <패키지 이름>

패키지 dump는 아래와 같은 모양을 갖고, 앱의 정보를 총망라하여 보여준다.

Package [com.android.calendar] (4a50e0):
    userId=10118
    pkg=Package{330fe6f com.android.calendar}
...

예를 들면,

  • 단말에서 처리가능한 MINE 타입, 스키마(Scheme) , 액션 정보
  • 등록한 권한(permission)
  • 버전 정보(versionName, versionCode)
  • 설치 위치(codePath, resourcePath)
  • 시그니처 정보(apkSigningVersion, signatures)

등 이다. 이 중에서 정보의 축약이 심해 이해가 잘 안되는 것들만 살펴보자.

퍼미션(permissions)

현재 이 단말에 설치된 퍼미션 목록을 표시한다.

예시는 아래와 같다.

DUMP OF SERVICE package:
Permissions:
  Permission [android.permission.READ_SMS] (45b275c):
    sourcePackage=android
    uid=1000 gids=null type=0 prot=dangerous
    perm=Permission{df5fa65 android.permission.READ_SMS}

  …

  Permission [android.permission.RECEIVE_SMS] (39c6e40):
    sourcePackage=android
    uid=1000 gids=null type=0 prot=dangerous
    perm=Permission{8b2a179 android.permission.RECEIVE_SMS}

 

플래그(flags)

패키지의 속성(property)을 표시하는 플래그다. 아래와 같이 속성을 가지고 있다면 표시되고, 속성이 없다면 표시되지 않는다.

Package [com.android.phone] (5328729):
	...
	flags=[ SYSTEM HAS_CODE PERSISTENT ALLOW_CLEAR_USER_DATA ]
	...
Package [com.google.android.apps.magazines] (6a6fc41):
	...
	flags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP KILL_AFTER_RESTORE EXTERNAL_STORAGE ]
	...

위 예제의 전화 앱(com.android.phone)은 SYSTEM HAS_CODE PERSISTENT ALLOW_CLEAR_USER_DATA 속성을 갖고 있다.

패키지가 속성들의 가지고 있는지 판단하는 기준은 com.android.server.pm.Settings 소스 코드에서 살펴볼 수 있다.

...
static final Object[] FLAG_DUMP_SPEC = new Object[] {
ApplicationInfo.FLAG_SYSTEM, "SYSTEM",
ApplicationInfo.FLAG_DEBUGGABLE, "DEBUGGABLE",
ApplicationInfo.FLAG_HAS_CODE, "HAS_CODE",
ApplicationInfo.FLAG_PERSISTENT, "PERSISTENT",
ApplicationInfo.FLAG_FACTORY_TEST, "FACTORY_TEST",
ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING, "ALLOW_TASK_REPARENTING",
ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA, "ALLOW_CLEAR_USER_DATA",
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, "UPDATED_SYSTEM_APP",
ApplicationInfo.FLAG_TEST_ONLY, "TEST_ONLY",
ApplicationInfo.FLAG_VM_SAFE_MODE, "VM_SAFE_MODE",
ApplicationInfo.FLAG_ALLOW_BACKUP, "ALLOW_BACKUP",
ApplicationInfo.FLAG_KILL_AFTER_RESTORE, "KILL_AFTER_RESTORE",
ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
...

위 코드를 보면, ApplicationInfo.FLAG_SYSTEM가 true 이면 “SYSTEM” 속성을 가진 것으로 패키지 dump에 표시 되겠다. 그러므로, 저 코드를 참고하여 ApplicationInfo의 구글 API 가이드의 상수 설명을 보면 플래그의 의미를 알 수 있다. 그 중에 설명이 충분하지 않은 것들을 정리해보자.

  • “SYSTEM”
    프리로드 된 앱이 갖는 속성이다. 단말 제조사에서 바이너리 발행 시, /system/* 폴더에 앱을 탑재해야 한다. 그 예로, /system/priv-app/, /system/app/, /system/framework/ 이 있다.
    설치 위치가 /system/*이 아닌 /data/app/라도 시스템을 업데이트 한 경우라면 “SYSTEM” 속성을 가질 수 있다. 시스템을 업데이트한 경우에는 속성이 상속되기 때문이다.
    참고로, 이 속성은 패키지의 시그니처나 “PRIVILEGED”처럼 퍼미션 허가 여부에 영향을 미친다.
  • “UPDATED_SYSTEM_APP”
    시스템 앱을 업데이트한 앱이다. 설치 공간은 /data/app/*일 것이며, “SYSTEM” 속성도 함께 갖고 있다.
  • “PERSISTENT”
    항상 실행되는지 여부를 가리키는 플래그로 항상 동작해야하는 소수의 시스템 앱만 선언한다.
    AndroidManifest.xml 파일 내 <application/>의 파라미터로 명시적 선언해야한다.
    예) 전화, NFC 앱
  • “EXTERNAL_STORAGE”
    외부 저장공간에 저장된 경우에 표시되는 속성이다.
    앱의 제작자가 AndroidManifest.xml 파일 내 <manifest/>의 android:installLocation 파라미터로 명시적 선언되어야 이동이 가능하다.
    만약 이동 가능한 앱이라면, “Settings – Apps – <어플리케이션 이름> 선택 – Storage 선택 – 저장공간 이동”, SD카드가 있어야 메뉴가 노출된다.
    예) 구글 뉴스 앱
  • “LARGE_HEAP”
    앱 실행 시 시스템으로 부터 더 큰 Heap 메모리를 할당받는다.
    AndroidManifest.xml 파일 내 <application/>의 파라미터로 명시적 선언해야 한다.
    시스템에 따라, 앱에 할당하는 기본 Heap 메모리 크기가 다르므로, LARGE_HEAP 속성을 선언했을 때 추가할당하는 heap 크기도 단말마다 다를 수 있다.

프라이빗 플래그(privateFlags)

privateFlags라는 속성 중에서, 한 가지만 살펴보자.

Package [com.android.phone] (5328729):
    ...
    privateFlags=[ PRIVILEGED DEFAULT_TO_DEVICE_PROTECTED_STORAGE DIRECT_BOOT_AWARE PARTIALLY_DIRECT_BOOT_AWARE PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION ]
    ...
  • “PRIVILEGED”
    앱 중에서 /system/* 이하에 설치된 경우 “SYSTEM” 속성을 갖고 있다고 했다. 시스템 앱 중에서도 설치된 상세 위치가 /system/priv-app/*인 경우 추가적으로 privateFlags에 이 속성을 갖는다.
    참고로, 이 속성은 “SYSTEM” 플래그나 패키지 시그니처러럼 퍼미션 허가 여부에 영향을 미칠 수 있다.

패키지 시그니처(signatures)

패키지의 시그니처 정보를 확인할 수 있다.

Package [com.android.phone] (5328729):
	...
	signatures=PackageSignatures{15f0d38 [b378e95c]}
	...
Package [com.google.android.apps.magazines] (6a6fc41):
	...
    signatures=PackageSignatures{6261b7d [e3ca78d8]}
	...    

위 예시 속 패키지는 com.android.phone은 기본 전화 앱, com.google.android.apps.magazines는 구글 뉴스 앱이다.  signatures 파라미터의 대괄호 안에 signature가 있고, 이 값이 같은 앱들은 같은 keystore를 통해 signing이 된 것이다.

참고로, 시그니처도 “SYSTEM”이나 “PRIVILEGED” 속성과 갖이 퍼미션 허가 여부에 영향을 미친다.

패키지 상태(활성화, 강제 종료 등)

패키지 활성화(enable) 여부나 강제 종료 여부도 확인할 수 있다.

...
User 0:  installed=true hidden=false stopped=false notLaunched=false enabled=0
...

위 패키지 정보 로그 중, stopped 파라미터는 설정 > 어플리케이션 관리자 > 앱 > 강제 종료 되었는지 여부를 가리킨다.

또 enabled 파라미터는 패키지 활성화 여부를 보여준다. 0(Default), 1(Enabled), 2(Diabled), 3(Disabled by user), 4(Diabled until used) 등으로 여기에 사용되는 값은 안드로이드 버전에 따라 추가되기도 하니, PackageManager의 상수들을 참조하면 된다.

그 밖에

  • 프리로드 앱(단말에 처음부터 포함된 앱)이 업데이트 된 경우, 프리로드 앱 정보와 업데이트 된 앱 의 패키지 정보가 모두 보인다.
  • 플래그 중에는 ApplicationInfo.FLAG_IS_GAME 처럼, deprecated된 것도 있다.
  • 퍼미션 허가 여부에 대한 자세한 내용은 이 글을 살펴보자.

참고

안드로이드 플랫폼 퍼미션(permission)

L OS부터 안드로이드 어플리케이션은 퍼미션을 protectionLevel에 따라 4가지로 구분하고 있다. 앱 개발자 입장에서는 얼마나 쉽게 권한을 얻을 수 있느냐가 중요한데, 이를 순서대로 정리하면 아래와 같다.

  • normal : <use-permission/> 선언 후, 사용자 동의 없이 사용 가능
  • dangerous : <use-permission/> 선언 후, 사용자 동의 하에 사용 가능
  • signatureOrSystem : 아래 signature에 해당하거나, 단말 출시 시 미리 내장되어 출시된 앱인 경우 사용 가능
  • signature : <permission/> 선언한 앱(여기서는 플랫폼)과 <use-permission/> 선언한 앱이 동일한 인증서로 사인된 경우 사용 가능

위 4가지 중에서 일반 개발자(이하, 서드파티 개발자)는 normal이나 dangerous의 protectionLevel을 가진 권한은 얻을 수 있으나, signature나 signatureOrSystem의 protectionLevel을 가진 권한은 얻을 수 없다. 보통 단말 제조사에서 출시시 단말에 포함하는 앱(이하, 프리로드 앱)들이 이런 권한을 사용할 수 있다. 위에 언급된 것처럼, 단말 출시 시 특정 폴더에 앱을 포함하거나, 플랫폼을 사인하는데 사용한 인증서를 사용해 앱을 사인해야 하기 때문이다. 다만, 이 글을 보면 개발 단계에서 우회적인 방법을 통해 인증서를 확보하여 signature 레벨의 권한을 테스트 해볼 수 있다.

안드로이드 개발자사이트에는 안드로이드에서 지원하는 퍼미션 목록이 정리된 페이지가 없다. 대신, 안드로이드 프레임워크 내의 AndroidManifest.xml 소스코드를 통해 각 protectionLevel 별 권한(permission) 목록을 확인할 수 있다. 참고로, normal과 dangerous, signature는 그대로, System 앱은 privileged로 표시되어 있다. 예를 들면, signatureOrSystem 앱이라면 아래와 같이 protectionLevel이 표시된다.

<permission android:name="[퍼미션이름]" android:protectionLevel="signature|privileged" />

그 밖에

  • system의 protectionLevel은 특정 폴더(/data/priv-app/*)에 앱이 자리잡고 있어야 올바르게 동작한다. 이 위치는 보통 핸드폰의 바이너리를 만들 때 결정되므로, 서드파티가 임의로 넣을 수는 없다. (물론, 루팅은 예외)
  • protectionLevel이 system 인 퍼미션은 업데이트를 통해 신규 획득할 수 없다. 이에 대한 설명은 이 글을 참조하자.
  • 단말 제조 과정에서 앱이 들어가는 프로세스를 이해하는데 도움이 될만한 인포그라픽을  HTC에서 공개했다.
Android-update-process
Android OS 업데이트 프로세스 by HTC

참조