'Android key signing'에 해당되는 글 1건

  1. 2014.01.06 [퍼옴][안드로이드][프레임워크]Platform key signing 완벽 분석

출처:http://kimyow.blog.me/50116380850

이 글이 가장 인기있는 글이네요.

지금와서 다시 읽어보니, 내용이 너무 두서없는 것 같아, 좀 더 이해가 쉽도록 수정을 했습니다. 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 사용이 가능하며 원하는 모든 기능이 정상 동작 될 것이다.

Posted by code cat