http://blog.csdn.net/jscese/article/details/24243171 在我的第一篇博客里面http://blog.csdn.net/jscese/article/details/12184513#comments,有提到AndroidManifest.xml中的android:sharedUserId="android.uid.system",代表的意思是和系統相同的uid,可以擁有修改系統時間,文件操作等權限。 也有提到怎么單獨給一個apk簽名,這里補充一下android的簽名權限控制機制。 一:簽名類型 android的標准簽名key有: testkey media platform shared 以上的四種,可以在源碼的/build/target/product/security里面看到對應的密鑰,其中shared.pk8代表私鑰,shared.x509.pem公鑰,一定是成對出現的。 其中testkey是作為android編譯的時候默認的簽名key,如果系統中的apk的android.mk中沒有設置LOCAL_CERTIFICATE的值,就默認使用testkey。 而如果設置成: LOCAL_CERTIFICATE := platform 就代表使用platform來簽名,這樣的話這個apk就擁有了和system相同的簽名,因為系統級別的簽名也是使用的platform來簽名,此時使用android:sharedUserId="android.uid.system"才有用! 二:自定義簽名Key 在/build/target/product/security目錄下有個README,里面有說怎么制作這些key以及使用問題(android4.2): The following commands were used to generate the test key pairs: development/tools/make_key testkey '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com' development/tools/make_key platform '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com' development/tools/make_key shared '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com' development/tools/make_key media '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com' The following standard test keys are currently included: testkey -- a generic key for packages that do not otherwise specify a key. platform -- a test key for packages that are part of the core platform. shared -- a test key for things that are shared in the home/contacts process. media -- a test key for packages that are part of the media/download system. These test keys are used strictly in development, and should never be assumed to convey any sort of validity. When $BUILD_SECURE=true, the code should not honor these keys in any context. 從上面可以看出來在源碼下的/development/tools目錄下有個make_key的腳本,通過傳入兩個參數就可以生成一對簽名用的key。 其中第一個為key的名字,一般都默認成android本身有的,因為很多地方都默認使用了這些名字,我們自定義的話只需要對第二個參數動手腳,定義如下: C ---> Country Name (2 letter code) ST ---> State or Province Name (full name) L ---> Locality Name (eg, city) O ---> Organization Name (eg, company) OU ---> Organizational Unit Name (eg, section) CN ---> Common Name (eg, your name or your server’s hostname) emailAddress ---> Contact email address 另外在使用上面的make_key腳本生成key的過程中會提示輸入password,我的處理是不輸入,直接enter,不要密碼!后面解釋,用自定義的key替換/security下面的。 可以看到android源碼里面的key使用的第二個參數就是上面README里面的,是公開的,所以要release版本的系統的話,肯定要有自己的簽名key才能起到一個安全控制作用。 三:修改系統默認簽名key 在上面提到如果apk中的編譯選項LOCAL_CERTIFICATE沒有設置的話,就會使用默認的testkey作為簽名key,我們可以修改成自己想要的key,按照上面的步驟制作一個releasekey,修改android配置在/build/core/config.mk中定義變量: DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/releasekey 在主makefile文件里面: ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/releasekey) BUILD_VERSION_TAGS += release-keys 這樣的話默認的所有簽名將會使用releasekey。 修改完之后就要編譯了,如果上面的這些key在制作的時候輸入了password就會出現如下錯誤: Enter password for build/target/product/security/releasekey.pk8 (password will not be hidden): java.lang.NullPointerException at com.android.signapk.SignApk.decryptPrivateKey(SignApk.java:142) at com.android.signapk.SignApk.readPrivateKey(SignApk.java:166) at com.android.signapk.SignApk.main(SignApk.java:531) Enter password for build/target/product/security/releasekey.pk8 (password will not be hidden): make: *** [out/target/product/gotechcn/obj/APPS/CalendarProvider_intermediates/package.apk] 錯誤 1 make: *** 正在等待未完成的任務.... Enter password for build/target/product/security/releasekey.pk8 (password will not be hidden): java.lang.NullPointerException at com.android.signapk.SignApk.decryptPrivateKey(SignApk.java:142) at com.android.signapk.SignApk.readPrivateKey(SignApk.java:166) at com.android.signapk.SignApk.main(SignApk.java:531) make: *** [out/target/product/gotechcn/obj/APPS/Calculator_intermediates/package.apk] 錯誤 1 Warning: AndroidManifest.xml already defines minSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest. Warning: AndroidManifest.xml already defines targetSdkVersion (in http://schemas.android.com/apk/res/android); using existing value in manifest. 'out/target/common/obj/APPS/Calendar_intermediates/classes.dex' as 'classes.dex'... Enter password for build/target/product/security/releasekey.pk8 (password will not be hidden): java.lang.NullPointerException at com.android.signapk.SignApk.decryptPrivateKey(SignApk.java:142) at com.android.signapk.SignApk.readPrivateKey(SignApk.java:166) at com.android.signapk.SignApk.main(SignApk.java:531) make: *** [out/target/product/gotechcn/obj/APPS/Calendar_intermediates/package.apk] 錯誤 1 ^Cmake: *** [out/target/product/gotechcn/obj/APPS/BasicDreams_intermediates/package.apk] 錯誤 130 我在網上找到了合理的解釋: 其實會出現這個錯誤的最根本的原因是多線程的問題。在編譯的時候為了加速一般都會執行make -jxxx,這樣本來需要手動輸入密碼的時候,由於其它線程的運行,就會導致影響當前的輸入終端,所以就會導致密碼無法輸入的情況! 再編譯完成之后也可以在build.prop中查看到變量: ro.build.tags=release-keys 這樣處理了之后編譯出來的都是簽名過的了,系統才算是release版本 我發現我這樣處理之后,整個系統的算是全部按照我的要求簽名了。 四:其它 網上看到還有另外的簽名release辦法,但是應該是針對另外的版本的,借用學習一下: make -j4 PRODUCT-product_modul-user dist 這個怎么跟平時的編譯不一樣,后面多了兩個參數PRODUCT-product_modul-user 和 dist. 編譯完成之后回在源碼/out/dist/目錄內生成個product_modul-target_files開頭的zip文件.這就是我們需要進行簽名的文件系統. 我的product_modul 是full_gotechcn,后面加“-user”代表的是最終用戶版本,關於這個命名以及product_modul等可參考http://blog.csdn.net/jscese/article/details/23931159 編譯出需要簽名的zip壓縮包之后,就是利用/security下面的准備的key進行簽名了: ./build/tools/releasetools/sign_target_files_apks -d /build/target/product/security out/dist/full_gotechcn-target_files.zip out/dist/signed_target_files.zip 簽名目標文件 輸出成signed_target_files.zip 如果出現某些apk出錯,可以通過在full_gotechcn-target_files.zip前面加參數"-e <apkname>=" 來過濾這些apk. 然后再通過image的腳本生成imag的zip文件,這種方式不適用與我目前的工程源碼,沒有做過多驗證