2014년 5월 20일 화요일

[Android] Platform key signing 완벽 분석

출처 kimyow | 사랑혜영
원문 http://kimyow.blog.me/50116380850
 

[Android] Platform key signing 완벽 분석


Platform key signing 을 하는 이유는 뭘까?

왜 굳이 Platform key 로 signing 을 해야 할까?

일반적인 apk 의 경우, (일반 개발자, 3rd party 가 개발한 APK) 자신이 만든 apk 를, data 영역에 install 할 수 있으며, 또는 rooting 한 폰의 system 영역에 설치할 수 있고, 이를 실행할 수 있다.

여기서 일반적인 apk 란, 통상적을 제공되는 sdk 에서 개발 된 apk 를 말한다.
(Vendor가 아닌, 일반적인 모든 개발자가 Eclipse 등 SDK를 사용하여 개발한 Application) 

Full image build 과정에서 생성되는 System image(Framework.jar)를 사용하면, 소위말하는 Internal or Hidden API 를 사용하여 build 할 수 있다.

SDK 로 제공되는 android.jar 에는 포함되지 않는 API(method) 들이 많다. 
이는 Android가 일반 개발자에게는 open 하지 않는 기능들이라고 봐도 좋다.

오직 Device 를 만들어서 파는 Vendor(삼성/LG)들만이 사용할 수 있다.

Settings.apk 의 경우,

타 모델의 apk 또는 source 를 구한다 한 들, 쉽게 자신의 phone 에 설치 & 실행이 안 될 것이다.
(Setting 만이 가지고 있는 특정 기능을 포기한 후 build 한다면, 가능하다.)

이미 당신이 가지고 있는 폰은 Vendor 가 User mode 로 build 한, 특정 key 로 signing 된 image 를 사용하기 때문이다.
( Debug or Engineer 모드로 build 된 image 가 탑재된 상태로 시장에 출시되지 않겠죠? )

User mode build 시, Vendor 는 android 에서 제공되는 known key (보통, \build\target\product\security\ 안에 있다.) 로 signing 하지 않으며, 각자의 unique 한 key 를 만들어서 signing 한다. 개발 편의를 위해서 default key 로 signing 하기도 하는데, 이는 eclipse 가 build 시 signing 하는 key 와 동일하다.

즉, Vendor 입장에서는 개발 단계와 양산 단계의 signing key 가 다른 것이다.

System 권한이 필요한 Setting 의 경우, Platform key 로 signing 후 설치된다. System과 동일한 uid 를 가져야 동일한 권한으로 data/code 사용이 가능하며 이를 위해서는 system 과 동일한 platform key 로 signing 되어야 한다.

하지만, 이미 당신이 가지고 있는 device(phone) 의 platform key 를 가지고 있지 않은 이상, 아무리 source build 를 성공해도 만들어진 Settings.apk 를 설치하기란 불가능하다.
(설치하려고 하면, INSTALL_FAILED_SHARED_USER_INCOMPATIBLE error 가 뜰 것이다.)

물론, 위에서 언급했듯이 Setting 만의 특정 기능을 뺀다면 가능하다.

Setting 만의 특정 기능이란, 타 application 을 memory 상에서 깨끗하게 kill 할 수 있는 기능이다.

이는 위에서 언급한 internal api 를 사용해야 하므로, 3rd party application 에선 사용이 불가능하며, system 권한/자격이 필요한 기능이다.

System 권한, 자격을 포기한다면, 굳이 platform key 로 signing 할 필요 없으며, 일반적인 application 으로써, 어떤 device 든지 기 설치되어 있는 settings.apk 만 확실히 제거한 후, 당신이 빌드한 새로운 settings.apk를 재설치해서 사용이 가능하다.

이 system 자격, 권한을 포기한다는 의미가, AndroidManifest.xml 에서 속성으로 명시된,
android:sharedUserId="android.uid.system" 항목을 삭제하는 것이다.

위 의미는 system process 와 같은 uid 를 사용하므로써, system process 의 code & data 를 똑 같이 공유할 수 있는 권한을 해당 application 에게 준다는 의미이다.

따라서 위 항목을 지우고 build 한 apk 를 설치하면 아주 자~~알 설치될 것이다.

하지만,~~ Settings > Applications >Manage applications 에서 "Force stop" 버튼을 클릭 하는 순간 unexpected error, 즉 setting application 이 죽을 것이다.

System 자격이 있는 넘이 호출해야 할 함수를 자격이 없는 application이 호출했기 때문에 Permission error 가 나는 것이다.

대표적인 Internal api method 인, ActivityManager 의 forceStopPackage() 를 예로 들어보자.- Internal API이므로, 일반 개발자에게는 open 되어 있지 않은 함수다.

보통 Market에서 download 받아 설치하는 일반적인 system application의 경우(TaskManager), ActivityManager.killBackgroundProcesses() 로 application 을 kill하는데, 이는 application 우선순위가 Background 이하인 application 만 kill 하는 제약을 가지고 있다.(Visible, Foreground, Service 우선순위는 완벽하게 kill 할 수 없다.)

이에 반해 ActivityManager.forceStopPackage() 함수는 아무런 제약 사항없이 대상이 되는 application 을 메모리상에서 깨끗히 지우는 기능을 한다.

이 함수를 실행하기 위해서는 permission 이 필요한데, 
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"></uses-permission>
라고 AndroidManifest.xml 에 명시해줘야 한다.

이렇게 해서 build 된 apk 를 install 한 후, 실행 하면 하기와 같은 exception 이 발생한다.

==================================================================

07-21 10:38:13.480: WARN/ActivityManager(1981): Permission Denial:forceStopPackage() from pid=3565, uid=10110 requires android.permission.FORCE_STOP_PACKAGES
07-21 10:38:13.503: ERROR/AndroidRuntime(3565): FATAL EXCEPTION: main
07-21 10:38:13.503: ERROR/AndroidRuntime(3565): java.lang.SecurityException: Permission Denial: forceStopPackage() from pid=3565, uid=10110 requires android.permission.FORCE_STOP_PACKAGES
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at android.os.Parcel.readException(Parcel.java:1260)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at android.os.Parcel.readException(Parcel.java:1248)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at android.app.ActivityManagerProxy.forceStopPackage(ActivityManagerNative.java:2564)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at android.app.ActivityManager.forceStopPackage(ActivityManager.java:968)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at com.lge.lmk.activities.RunningProcessActivity$4.onClick(RunningProcessActivity.java:850)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java:158)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at android.os.Looper.loop(Looper.java:123)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at android.app.ActivityThread.main(ActivityThread.java:4668)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at java.lang.reflect.Method.invokeNative(Native Method)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at java.lang.reflect.Method.invoke(Method.java:521)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:878)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:636)
07-21 10:38:13.503: ERROR/AndroidRuntime(3565):     at dalvik.system.NativeStart.main(Native Method)
==================================================================


"android.permission.FORCE_STOP_PACKAGES" Permission 을 명시해 줬는데 왜 Permission error가 날까?

이 함수를 call 하는 application쪽에 System process 의 권한이 없기 때문이다.

system process 와 동일한 권한을 갖기위해서는?

AndroidManifest.xml 파일의 manifest attribute 에 하기와 같이 지정해 주면 된다.
android:sharedUserId="android.uid.system"

이 application process 의 uid 를 system 과 공유함으로써, system 과 동일한 권한을 갖겠다는 의미다.

참 편리하게 system 권한을 가질 수 있다고 생각할 수 있지만, 이는 어디까지 platform(system)  과 signature 가 같을 때의 경우에만 해당된다.

다시한번 언급하자면, 
모든 사용자가 구입한 폰은 각 Vendor 측의 고유 key로 signing 된, User mode 로 빌드 된 image 가 탑재 되었고, 각 모델별로 고유한 platform key 로 signing 되었기 때문에, 아무리 rooting 을 했건, 뭐를 했건간에, User mode 로 빌드 된 image의 key 를 바꿀 순 없다.
(Vendor 측에 아는 사람이 있어 debug 나, engineer 모드로 빌드된 image 를 구할 수 있다면??)

전체 이미지 빌드 타임에 system 과 data 영역에 들어갈 모든 APK는, 싹 다 각각 Android.mk에 명시된 key 값으로 signing 한다.

때문에, Signature 가 Platform과 맞지 않은 Settings application 을 폰에 탑재하는 순간, 아래와 같은 logcat msg 와 함께, 해당 apk 는 launcher 에서 볼 수 없을 것이다.(PackageManager 가 package loading 실패)
====================================================================
07-21 10:56:36.046: WARN/PackageManager(1981): Package com.test.application shared user changed from <nothing> to android.uid.system; replacing with new
07-21 10:56:36.054: WARN/PackageManager(1981): Signature mismatch for shared user : SharedUserSetting{462749e8 android.uid.system/1000}
07-21 10:56:36.054: ERROR/PackageManager(1981): Package com.test.application has no signatures that match those in shared user android.uid.system; ignoring!

====================================================================

또는,(아래는 살짝 다른 유형의 error 다.)
====================================================================


08-09 09:47:06.054: ERROR/PackageManager(1973): Package com.test.application signatures do not match the previously installed version; ignoring!
08-09 09:47:06.257: INFO/IQClient(2030): submitHW03 -  status- 2 level- 74
====================================================================


system 쪽과 signature mis-match 가 나서 이 어플을 loading 할 수 없다는 의미이다.

해결방법은 해당 어플도 똑같이 platform signing 을 해주는 방법밖에 없다.

그래야 system 권한을 얻을 수 있다는 의미이다.

하기와 같이 platform key 를 어디선가 구해와서 signing 해주면 된다.
(당연히 아래 platform key 가 당신의 device 에 flashing 되어 있는 image 의 signed platform key 와 동일해야 한다.)

Platform key 는 어디서 구할까...??? 해당 모델의 Vendor 만이 알 수 있다.

java -jar signapk.jar platform.x509.pem platform.pk8 Unsigned.apk Signed.apk

위 명령어로 생성된 Signed.apk 를 설치해주면 System 권한으로 internal api 사용이 가능하며 원하는 모든 기능이 정상 동작 될 것이다.

댓글 없음:

댓글 쓰기