*Application 개발 시 Platform key signing이 필요한 경우
일반적인 개발자나 3rd Party 개발사에 제공되는 SDK로 개발되는 apk파일과는 달리
Vendor에게 제공되는 Internal or hidden API를 사용해서 개발한 Application은 일반적인 Device에 설치해서 실행할 수 없다. (예를 들면, Settings.apk같은 소스 파일을 구해도 실제로 폰에 설치해서 해당 기능을 이용할 수 없음)
이는 시장에 출시된 폰은 Vendor가 User mode 로 build 한 image를 사용하기 때문인데
User mode로 build하는 경우, Vendor 는 android 에서 제공되는 known key (\build\target\product\security\)가 아닌 각자의 unique 한 key 를 만들어서 signing 한다.
1) Emulator의 경우
system 권한이 필요한 appilcation 을 emulator 에 설치해서 debugging 하고 싶다면, known key 인 platform key 로 signing 하면 된다. 방법은 다음과 같다.
개발 단계와 Release 단계의 signing key 가 다르다.
따라서, system 권한이 필요한 Setting 의 경우, Platform key 로 signing 후, 설치되지만, 이미 유저가 가지고 있는 device 의 vendor 측 platform key 를 가지고 있지 않은 이상, 다른 환경에서 build 되거나, 다른 device 에서 가져온 Settings.apk 를 설치하기란 불가능하다.
(설치하려고 하면, INSTALL_FAILED_SHARED_USER_INCOMPATIBLE error 가 뜰 것이다.)
물론, 위에서 언급했듯이 Setting 만의 특정 기능을 뺀다면 가능하다.
Setting 만의 특정 기능이란, 타 application 을 memory 상에서 깨끗하게 kill 할 수 있는 기능이다.
이는 3rd party application 에선 사용이 불 가능하며, system 권한, 자격이 필요하다.
하지만 system 권한, 자격을 포기한다면, platform key 로 signing 할 필요 없으며, 이는 곳 일반적인 application 으로써, 어떤 device 든지 기 설치되어 있는 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 자격이 있는 넘이 호출해야 할 함수를 setting application 이 호출했기 때문에 permission error 가 나는 것이다.
이 함수를 실행하기 위해서는 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)
07-21 10:38:13.511: WARN/ActivityManager(1981): Force finishing activity com.lge.lmk/.activities.LmkMainActivity
"android.permission.FORCE_STOP_PACKAGES" Permission 을 명시해 줬는데 왜 그럴까?
system process 의 권한이 없기 때문이다.
system process 와 동일한 권한을 갖기위해서는?
AndroidManifest.xml 파일의 manifest attribute 에 하기와 같이 지정해 주면 된다.
android:sharedUserId="android.uid.system"
이 application process 의 uid 를 system 과 공유함으로써, system 과 동일한 권한을 갖겠다는 의미다.
참 편리하게 system 권한을 가질 수 있다고 생각할 수 있지만, 이는 어디까지 platform(system) 과 signature 가 같을 때의 경우에만 해당된다.
모든 사용자가 가지고 있는 폰은 User mode 로 빌드 된 image 가 탑재 되었고, 각 모델별 고유한 platform key 로 signing 되었기 때문에,
(Vendor 측에 아는 사람이 있어 debug 나, engineer 모드로 빌드된 image 를 구할 수 있다면??)
전체 이미지 빌드 타임에 system 과 data 영역에 들어갈 모든 apk 까지 싹 다 각각 명시된 key 값으로 signing 한다.
때문에, Signature 가 Platform과 맞지 않은 Settings application 을 폰에 탑재하는 순간, 아래와 같은 logcat msg 와 함께, 해당 apk 는 launcher 에서 볼 수 없을 것이다.(PackageManager 가 package loading 실패)
===========================================================================================
07-21 10:56:36.007: DEBUG/PackageParser(1981): Scanning package: /system/app/ApplicationManager.apk
07-21 10:56:36.007: INFO/PackageManager(1981): /system/app/ApplicationManager.apk changed; collecting certs
07-21 10:56:36.046: DEBUG/PackageManager(1981): Scanning package com.lge.lmk
07-21 10:56:36.046: DEBUG/PackageManager(1981): Shared UserID android.uid.system (uid=1000): packages=[PackageSetting{464d74d8 de.emsys.usbmode.control/1000}, PackageSetting{462eaed0 com.lge.charging_test/1000}, PackageSetting{46415808 com.google.android.location/1000}, PackageSetting{466c4260 de.emsys.usbmode.service/1000}, PackageSetting{464a8c08 com.lge.hiddenmenu/1000}, PackageSetting{46392e68 com.android.providers.subscribedfeeds/1000}, PackageSetting{4639d108 com.android.server.vpn/1000}, PackageSetting{462b8cd8 com.jungle.app.service/1000}, PackageSetting{4630d8f0 com.lge.internal/1000}, PackageSetting{46353388 com.lge.providers.flex/1000}, PackageSetting{46475660 android/1000}, PackageSetting{46298f28 com.android.settings/1000}, PackageSetting{461ff250 com.android.providers.settings/1000}, PackageSetting{46259770 com.lge.sui.widget/1000}]
07-21 10:56:36.046: WARN/PackageManager(1981): Package com.lge.lmk 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.lge.lmk has no signatures that match those in shared user android.uid.system; ignoring!
===========================================================================================
또는,(아래는 살짝 다른 유형의 error 다.)
===========================================================================================
08-09 09:47:06.046: DEBUG/PackageManager(1973): Scanning package com.lge.lmk
08-09 09:47:06.054: DEBUG/PackageManager(1973): Shared UserID android.uid.system (uid=1000): packages=[PackageSetting{462d48a8 com.android.server.vpn/1000}, PackageSetting{462af928 com.lge.internal/1000}, PackageSetting{462e8908 com.lge.sui.widget/1000}, PackageSetting{462cded0 com.lge.hiddenmenu/1000}, PackageSetting{462cdcb0 de.emsys.usbmode.control/1000}, PackageSetting{462e9ad8 com.google.android.location/1000}, PackageSetting{462af0d0 com.jungle.app.service/1000}, PackageSetting{462b06c0 android/1000}, PackageSetting{462af2d0 de.emsys.usbmode.service/1000}, PackageSetting{462e6cc0 com.android.settings/1000}, PackageSetting{462daad0 com.lge.providers.flex/1000}, PackageSetting{462dc5d8 com.android.providers.settings/1000}, PackageSetting{462e3270 com.android.providers.subscribedfeeds/1000}, PackageSetting{462e5430 com.lge.charging_test/1000}, PackageSetting{462e8c48 com.lge.lmk/1000}]
08-09 09:47:06.054: WARN/PackageManager(1973): Signature mismatch for shared user : SharedUserSetting{4621b8b0 android.uid.system/1000}
08-09 09:47:06.054: WARN/PackageManager(1973): Trying to update system app code path from /system/app/ApplicationManager_signed.apk to /system/app/ApplicationManager.apk
08-09 09:47:06.054: ERROR/PackageManager(1973): Package com.lge.lmk 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 권한을 없애는 방법도 있다.)
그래야 system 권한을 얻을 수 있다는 의미이다.
방법은 하기와 같이 platform key를 구해와서 signing 해주면 된다.
Platform key 는 어디서 구할까...??? 해당 모델의 Vendor 만이 알 수 있다.
java -jar signapk.jar platform.x509.pem platform.pk8 Unsigned.apk Signed.apk
Signed.apk 를 설치해주면 모두 정상 동작 된다.
[출처] Platform key signing 완벽 분석|작성자 사랑혜영
'안드로이드' 카테고리의 다른 글
monkeyrunner (0) | 2011.10.23 |
---|