權限簡介
Android系統(tǒng)上每一個獨立的應用運行在不同的系統(tǒng)空間蹋肮,以User ID和Group ID來標識矛缨。不同應用之間互相訪問數(shù)據接口資源,就牽涉到權限問題岩遗。
用戶ID
我們在安裝一個應用的時候系統(tǒng)就會為這個應用分配一個userid,這個userid是全局唯一的萄焦,在同一android系統(tǒng)的機器上不可能存在兩個相同userid的應用控轿,也就是說userid對于一個應用來說是唯一不變的,除非你卸載重新安裝了該應用拂封,但是userid并不像MAC地址一樣是全球唯一的茬射,同一個應用在不同的設備上userid可能會不同,上面說的唯一是指在同一個android設備上冒签。
Android的安全機制是進程級別的在抛,通常情況下一個應用就是一個進程,并且一個應用也只有一個進程萧恕,當然應用內實現(xiàn)多進程這個是沒有任何問題的刚梭,本文不考慮此情況。也就是說一般情況下票唆,應用A是無法直接運行在應用B的進程當中的望浩,
但是有一點就是除非應用A和應用B使用了相同的shareduserid,配置了相同的shareduserid的應用他們被系統(tǒng)視作同一個應用,對應的userid和權限都是相同的惰说,但是如果僅僅是配置了相同的shareduserid就能夠到達目的,顯然這是一個很大的漏洞缘回,為此谷歌做了另外一個限制吆视,就是必須保證簽名一致,一般的A公司的簽名肯定是跟B公司的簽名是不一樣的酥宴,也就是說想要應用A和應用B運行在同一個進程當中那么肯定得保證簽名和shareduserid是一致的啦吧,shareduserid保持一致這個很容易滿足,但是簽名一致恐怕只能是同一個公司
應用的數(shù)據和user id是相對應的拙寡,默認情況下其他應用是無法訪問的授滓,但是如果我們設置了MODE_WORLD_READABLE 或者 MODE_WORLD_WRITEABLE的flag,那么其他應用就可以變得可讀可寫了,也就是說這些數(shù)據就變成了全局的數(shù)據般堆。
用戶ID是什么
上面說了那么多userid是有多么多么的重要在孝,那么我們來看看userid在系統(tǒng)里面到底是什么
我們知道Android系統(tǒng)從4.2版本開始支持多用戶,也就產生了用戶id的概念uid淮摔,在這里uid和userid是兩個完全不同的概念私沮,android中的用戶是存在物理文件級數(shù)據差異的,譬喻有兩個用戶:用戶id分別是0和10和橙,用戶10安裝了應用A仔燕,此時對于用戶0來說是完全不可見的,不像兩個應用A和B兩者的數(shù)據雖然默認情況下是不能互相訪問的魔招,但是我們有辦法能夠實現(xiàn)晰搀。
那么用戶id到底是什么:簡單的說用戶id就是當前用戶下為了各個應用之間數(shù)據共享和訪問的
查看userid可以使用下面的命令
adb shell dumpsys packages---->adb shell dumpsys com.android.settings
Package [com.android.settings] (3d9bf40):
? ? userId=1000
? ? sharedUser=SharedUserSetting{2627759 android.uid.system/1000}
? ? pkg=Package{25c93ff com.android.settings}
? ? codePath=/system/app/CP_SystemSetting
? ? resourcePath=/system/app/CP_SystemSetting
? ? legacyNativeLibraryDir=/system/app/CP_SystemSetting/lib
? ? primaryCpuAbi=arm64-v8a
? ? secondaryCpuAbi=null
? ? versionCode=0 targetSdk=23
? ? versionName=_VER_2016.06.13_20:56:48
? ? splits=[base]
可以看到設置的userid是1000
在Android系統(tǒng)中有些常用的userid是提前定義好的,如system的用戶id就是1000办斑,這個是在代碼中提前定義好的
具體的在:include/private/android_filesystem_config.h
#ifndef?_ANDROID_FILESYSTEM_CONFIG_H_??
#define?_ANDROID_FILESYSTEM_CONFIG_H_??
#include???
#include???
#include???
#if?defined(__ANDROID__)??
#include???
#else??
#include?"android_filesystem_capability.h"??
#endif??
#define?CAP_MASK_LONG(cap_name)??(1ULL?<<?(cap_name))??
/*?This?is?the?master?Users?and?Groups?config?for?the?platform.
?*?DO?NOT?EVER?RENUMBER
?*/??
#define?AID_ROOT?????????????0??/*?traditional?unix?root?user?*/??
#define?AID_SYSTEM????????1000??/*?system?server?*/??
#define?AID_RADIO?????????1001??/*?telephony?subsystem,?RIL?*/??
#define?AID_BLUETOOTH?????1002??/*?bluetooth?subsystem?*/??
#define?AID_GRAPHICS??????1003??/*?graphics?devices?*/??
#define?AID_INPUT?????????1004??/*?input?devices?*/??
#define?AID_AUDIO?????????1005??/*?audio?devices?*/??
我們可以發(fā)現(xiàn)設置的userid和system的useri是相同的外恕,我們找到設置的源碼發(fā)現(xiàn)
android="http://schemas.android.com/apk/res/android"xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"package="com.android.settings"coreApp="true"android:sharedUserId="android.uid.system">
因此也驗證了上面的觀點。因為設置這個應用比較特殊俄周,通常會寫系統(tǒng)屬性等需要較高權限的操作吁讨。
權限分類
我們都知道通過shareduserid來實現(xiàn)數(shù)據共享有一個限制就是相同的簽名,這個是很高要求的峦朗,一般都是同一個公司開發(fā)出來的app才能滿足獲取內置到第三方ROM里面去才能滿足建丧,通常的做法是通過uses-permission來實現(xiàn),我們自己定義一個權限波势,在需要被訪問的地方加上這個權限限制這樣就能到達目的翎朱。以電子郵件為例:
我們事先定義了一個權限:com.android.email.permission.READ_ATTACHMENT
如果我們需要訪問下面的這個provider的話就需要上面定義的權限
并且我們可以看到上面的權限級別是dangerous,也就是說在安裝該應用的時候不會默認給你分配該權限尺铣,需要用戶確認的拴曲。
那么權限大概可以分成4類的
1:normal權限:也就是一般的權限,不需要用戶去確認的凛忿,譬如一個應用申請連接網絡等
2:dangerous權限:這種權限較normal權限高一些澈灼,需要用戶手動點擊確認的,譬喻應用需要讀取聯(lián)系人的信息店溢,因為這些數(shù)據是比較隱私的可能會導致你的數(shù)據泄露等
3:signature:只有當申請權限的應用程序的數(shù)字簽名與聲明此權限的應用程序的數(shù)字簽名相同時(如果是申請系統(tǒng)權限叁熔,則需要與系統(tǒng)簽名相同),才能將權限授給它
4:signatureOrSystem:簽名相同床牧,或者申請權限的應用為系統(tǒng)應用(在system image中)荣回。
第三條和第四條要求是很高,一般的只有是相同公司開發(fā)出來的應用才能滿足
權限帶來的問題
上次在公司就碰到了一個權限的問題戈咳,就是分享文件到電子郵件
當我點擊電子郵件圖標的時候突然casrh了心软,趕緊抓個日志看了下permission deny壕吹,導致調起分享功能對應的activity初始化失敗了
為啥會提示沒有權限了?
反編譯原始的Email.apk發(fā)現(xiàn)删铃,原來該權限申明成了signature的保護類型
由于分享ResolverActivity是運行在system進程中耳贬,也就是要求電子郵件的簽名必須是系統(tǒng)簽名,然后這個apk是客戶提供的泳姐,因此導致了問題的發(fā)生