系統(tǒng)權(quán)限
Android 是一個(gè)權(quán)限分隔的操作系統(tǒng),其中每個(gè)應(yīng)用都有其獨(dú)特的系統(tǒng)標(biāo)識(shí)(Linux 用戶 ID 和組 ID)。系統(tǒng)各部分也分隔為不同的標(biāo)識(shí)。Linux 據(jù)此將不同的應(yīng)用以及應(yīng)用與系統(tǒng)分隔開(kāi)來(lái)。
其他更詳細(xì)的安全功能通過(guò)“權(quán)限”機(jī)制提供,此機(jī)制會(huì)限制特定進(jìn)程可以執(zhí)行的具體操作,并且根據(jù) URI 權(quán)限授權(quán)臨時(shí)訪問(wèn)特定的數(shù)據(jù)段。
本文檔介紹應(yīng)用開(kāi)發(fā)者可以如何使用 Android 提供的安全功能。一般性的 Android 安全性概覽在“Android 開(kāi)源項(xiàng)目”中提供。
安全架構(gòu)
Android 安全架構(gòu)的中心設(shè)計(jì)點(diǎn)是:在默認(rèn)情況下任何應(yīng)用都沒(méi)有權(quán)限執(zhí)行對(duì)其他應(yīng)用、操作系統(tǒng)或用戶有不利影響的任何操作。這包括讀取或?qū)懭胗脩舻乃接袛?shù)據(jù)(例如聯(lián)系人或電子郵件)、讀取或?qū)懭肫渌麘?yīng)用程序的文件、執(zhí)行網(wǎng)絡(luò)訪問(wèn)、使設(shè)備保持喚醒狀態(tài)等。
由于每個(gè) Android 應(yīng)用都是在進(jìn)程沙盒中運(yùn)行,因此應(yīng)用必須顯式共享資源和數(shù)據(jù)。它們的方法是聲明需要哪些權(quán)限來(lái)獲取基本沙盒未提供的額外功能。應(yīng)用以靜態(tài)方式聲明它們需要的權(quán)限,然后 Android 系統(tǒng)提示用戶同意。
應(yīng)用沙盒不依賴用于開(kāi)發(fā)應(yīng)用的技術(shù)。特別是,Dalvik VM 不是安全邊界,任何應(yīng)用都可運(yùn)行原生代碼(請(qǐng)參閱 Android NDK)。各類應(yīng)用 — Java、原生和混合 — 以同樣的方式放在沙盒中,彼此采用相同程度的安全防護(hù)。
應(yīng)用簽署
所有 APK(.apk 文件)都必須使用證書簽署,其私鑰由開(kāi)發(fā)者持有。此證書用于識(shí)別應(yīng)用的作者。證書不需要由證書頒發(fā)機(jī)構(gòu)簽署;Android 應(yīng)用在理想情況下可以而且通常也是使用自簽名證書。證書在 Android 中的作用是識(shí)別應(yīng)用的作者。這允許系統(tǒng)授予或拒絕應(yīng)用對(duì)簽名級(jí)權(quán)限的訪問(wèn),以及授予或拒絕應(yīng)用獲得與另一應(yīng)用相同的 Linux 身份的請(qǐng)求。
用戶 ID 和文件訪問(wèn)
在安裝時(shí),Android 為每個(gè)軟件包提供唯一的 Linux 用戶 ID。此 ID 在軟件包在該設(shè)備上的使用壽命期間保持不變。在不同設(shè)備上,相同軟件包可能有不同的 UID;重要的是每個(gè)軟件包在指定設(shè)備上的 UID 是唯一的。
由于在進(jìn)程級(jí)實(shí)施安全性,因此任何兩個(gè)軟件包的代碼通常都不能在同一進(jìn)程中運(yùn)行,因?yàn)樗鼈冃枰鳛椴煌?Linux 用戶運(yùn)行。您可以在每個(gè)軟件包的 AndroidManifest.xml 的 [manifest] 標(biāo)記中使用 [sharedUserId] 屬性,為它們分配相同的用戶 ID。這樣做以后,出于安全目的,兩個(gè)軟件包將被視為同一個(gè)應(yīng)用,具有相同的用戶 ID 和文件權(quán)限。請(qǐng)注意,為保持安全性,只有兩個(gè)簽署了相同簽名(并且請(qǐng)求相同的 sharedUserId)的應(yīng)用才被分配同一用戶 ID。
應(yīng)用存儲(chǔ)的任何數(shù)據(jù)都會(huì)被分配該應(yīng)用的用戶 ID,并且其他軟件包通常無(wú)法訪問(wèn)這些數(shù)據(jù)。使用 [getSharedPreferences(String, int)]、[openFileOutput(String, int)] 或 [openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory) 創(chuàng)建新文件時(shí),可以使用 [MODE_WORLD_READABLE] 和/或 [MODE_WORLD_WRITEABLE] 標(biāo)記允許任何其他軟件包讀取/寫入文件。設(shè)置這些標(biāo)記時(shí),文件仍歸您的應(yīng)用所有,但其全局讀取和/或?qū)懭霗?quán)限已適當(dāng)設(shè)置,使任何其他應(yīng)用都可看見(jiàn)它
使用權(quán)限
基本 Android 應(yīng)用默認(rèn)情況下未關(guān)聯(lián)權(quán)限,這意味著它無(wú)法執(zhí)行對(duì)用戶體驗(yàn)或設(shè)備上任何數(shù)據(jù)產(chǎn)生不利影響的任何操作。要利用受保護(hù)的設(shè)備功能,必須在[應(yīng)用清單]中包含一個(gè)或多個(gè) [<uses-permission>]標(biāo)記。
例如,需要監(jiān)控傳入的短信的應(yīng)用要指定:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.RECEIVE_SMS" />
...
</manifest>
如果您的應(yīng)用在其清單中列出正常權(quán)限(即,不會(huì)對(duì)用戶隱私或設(shè)備操作造成很大風(fēng)險(xiǎn)的權(quán)限),系統(tǒng)會(huì)自動(dòng)授予這些權(quán)限。如果您的應(yīng)用在其清單中列出危險(xiǎn)權(quán)限(即,可能影響用戶隱私或設(shè)備正常操作的權(quán)限),系統(tǒng)會(huì)要求用戶明確授予這些權(quán)限。Android 發(fā)出請(qǐng)求的方式取決于系統(tǒng)版本,而系統(tǒng)版本是應(yīng)用的目標(biāo):
- 如果設(shè)備運(yùn)行的是 Android 6.0(API 級(jí)別 23)或更高版本,并且應(yīng)用的 [
targetSdkVersion]是 23 或更高版本,則應(yīng)用在運(yùn)行時(shí)向用戶請(qǐng)求權(quán)限。用戶可隨時(shí)調(diào)用權(quán)限,因此應(yīng)用在每次運(yùn)行時(shí)均需檢查自身是否具備所需的權(quán)限。如需了解有關(guān)在應(yīng)用中請(qǐng)求權(quán)限的詳細(xì)信息,請(qǐng)參閱使用系統(tǒng)權(quán)限培訓(xùn)指南。 - 如果設(shè)備運(yùn)行的是 Android 5.1(API 級(jí)別 22)或更低版本,并且應(yīng)用的
targetSdkVersion是 22 或更低版本,則系統(tǒng)會(huì)在用戶安裝應(yīng)用時(shí)要求用戶授予權(quán)限。如果將新權(quán)限添加到更新的應(yīng)用版本,系統(tǒng)會(huì)在用戶更新應(yīng)用時(shí)要求授予該權(quán)限。用戶一旦安裝應(yīng)用,他們撤銷權(quán)限的唯一方式是卸載應(yīng)用。
通常,權(quán)限失效會(huì)導(dǎo)致 [SecurityException] 被扔回應(yīng)用。但不能保證每個(gè)地方都是這樣。例如,[sendBroadcast(Intent)] 方法在數(shù)據(jù)傳遞到每個(gè)接收者時(shí)會(huì)檢查權(quán)限,在方法調(diào)用返回后,即使權(quán)限失效,您也不會(huì)收到異常。但在幾乎所有情況下,權(quán)限失效會(huì)記入系統(tǒng)日志。
Android 系統(tǒng)提供的權(quán)限請(qǐng)參閱 [Manifest.permission]。此外,任何應(yīng)用都可定義并實(shí)施自己的權(quán)限,因此這不是所有可能權(quán)限的詳盡列表。
可能在程序運(yùn)行期間的多個(gè)位置實(shí)施特定權(quán)限:
- 在調(diào)用系統(tǒng)時(shí),防止應(yīng)用執(zhí)行某些功能。
- 在啟動(dòng) Activity 時(shí),防止應(yīng)用啟動(dòng)其他應(yīng)用的 Activity。
- 在發(fā)送和接收廣播時(shí),控制誰(shuí)可以接收您的廣播,誰(shuí)可以向您發(fā)送廣播。
- 在訪問(wèn)和操作內(nèi)容提供程序時(shí)。
- 綁定至服務(wù)或啟動(dòng)服務(wù)
自動(dòng)權(quán)限調(diào)整
隨著時(shí)間的推移,平臺(tái)中可能會(huì)加入新的限制,要想使用特定 API,您的應(yīng)用可能必須請(qǐng)求之前不需要的權(quán)限。因?yàn)楝F(xiàn)有應(yīng)用假設(shè)可隨意獲取這些 API 應(yīng)用的訪問(wèn)權(quán)限,所以 Android 可能會(huì)將新的權(quán)限請(qǐng)求應(yīng)用到應(yīng)用清單,以免在新平臺(tái)版本上中斷應(yīng)用。Android 將根據(jù)為 [targetSdkVersion] 屬性提供的值決定應(yīng)用是否需要權(quán)限。如果該值低于在其中添加權(quán)限的版本,則 Android 會(huì)添加該權(quán)限。
例如,API 級(jí)別 4 中加入了 [WRITE_EXTERNAL_STORAGE] 權(quán)限,用以限制訪問(wèn)共享存儲(chǔ)空間。如果您的 [targetSdkVersion] 為 3 或更低版本,則會(huì)向更新 Android 版本設(shè)備上的應(yīng)用添加此權(quán)限。
注意:如果某權(quán)限自動(dòng)添加到應(yīng)用,則即使您的應(yīng)用可能實(shí)際并不需要這些附加權(quán)限,Google Play 上的應(yīng)用列表也會(huì)列出它們。
為避免這種情況,并且刪除您不需要的默認(rèn)權(quán)限,請(qǐng)始終將 [targetSdkVersion] 更新至最高版本。可在 [Build.VERSION_CODES] 文檔中查看各版本添加的權(quán)限。
正常權(quán)限和危險(xiǎn)權(quán)限
系統(tǒng)權(quán)限分為幾個(gè)保護(hù)級(jí)別。需要了解的兩個(gè)最重要保護(hù)級(jí)別是正常權(quán)限和危險(xiǎn)權(quán)限:
-
正常權(quán)限涵蓋應(yīng)用需要訪問(wèn)其沙盒外部數(shù)據(jù)或資源,但對(duì)用戶隱私或其他應(yīng)用操作風(fēng)險(xiǎn)很小的區(qū)域。例如,設(shè)置時(shí)區(qū)的權(quán)限就是正常權(quán)限。如果應(yīng)用聲明其需要正常權(quán)限,系統(tǒng)會(huì)自動(dòng)向應(yīng)用授予該權(quán)限。
從API級(jí)別26開(kāi)始,以下權(quán)限分類為PROTECTION_NORMAL:
| 正常權(quán)限 | 意義 |
|---|---|
| ACCESS_LOCATION_EXTRA_COMMANDS | 允許應(yīng)用程序訪問(wèn)額外的位置提供程序命令 |
| ACCESS_NETWORK_STATE | 允許應(yīng)用程序訪問(wèn)有關(guān)網(wǎng)絡(luò)的信息 |
| ACCESS_NOTIFICATION_POLICY | 對(duì)希望訪問(wèn)通知政策的應(yīng)用程序的標(biāo)記許可 |
| ACCESS_WIFI_STATE | 允許應(yīng)用訪問(wèn)有關(guān)Wi-Fi網(wǎng)絡(luò)的信息 |
| BLUETOOTH | 允許應(yīng)用連接到配對(duì)的藍(lán)牙設(shè)備 |
| BLUETOOTH_ADMIN | 允許應(yīng)用程序發(fā)現(xiàn)并配對(duì)藍(lán)牙設(shè)備 |
| BROADCAST_STICKY | 允許應(yīng)用程序廣播粘性意圖。這些廣播的數(shù)據(jù)在完成后由系統(tǒng)保存,以便客戶可以快速檢索該數(shù)據(jù)而無(wú)需等待下一個(gè)廣播 |
| CHANGE_NETWORK_STATE | 允許應(yīng)用程序更改網(wǎng)絡(luò)連接狀態(tài) |
| CHANGE_WIFI_MULTICAST_STATE | 允許應(yīng)用程序進(jìn)入Wi-Fi多播模式 |
| CHANGE_WIFI_STATE | 允許應(yīng)用更改Wi-Fi連接狀態(tài) |
| DISABLE_KEYGUARD | 允許應(yīng)用程序在不安全的情況下禁用鍵盤鎖 |
| EXPAND_STATUS_BAR | 允許應(yīng)用程序展開(kāi)或折疊狀態(tài)欄 |
| GET_PACKAGE_SIZE | 允許應(yīng)用程序找出任何包裹使用的空間 |
| INSTALL_SHORTCUT | 允許應(yīng)用程序在Launcher中安裝快捷方式。在Android O(API級(jí)別26)及更高版本中,INSTALL_SHORTCUT廣播不再對(duì)您的應(yīng)用產(chǎn)生任何影響,因?yàn)樗撬接械碾[式廣播。相反,您應(yīng)該使用該類中的[requestPinShortcut()] 方法創(chuàng)建應(yīng)用程序快捷方式 [ShortcutManager]
|
| INTERNET | 允許應(yīng)用程序打開(kāi)網(wǎng)絡(luò)套接字 |
| KILL_BACKGROUND_PROCESSES | 允許應(yīng)用程式致電 [killBackgroundProcesses(String)]
|
| MANAGE_OWN_CALLS | 允許調(diào)用應(yīng)用程序通過(guò)自我管理的[ConnectionService]API 管理自己的調(diào)用 |
| MODIFY_AUDIO_SETTINGS | 允許應(yīng)用修改全局音頻設(shè)置 |
| NFC | 允許應(yīng)用程序通過(guò)NFC執(zhí)行I / O操作 |
| READ_SYNC_SETTINGS | 允許應(yīng)用程式讀取同步設(shè)定 |
| READ_SYNC_STATS | 允許應(yīng)用讀取同步統(tǒng)計(jì)信息 |
| RECEIVE_BOOT_COMPLETED | |
| REORDER_TASKS | 允許應(yīng)用程序接收 [ACTION_BOOT_COMPLETED]系統(tǒng)完成引導(dǎo)后廣播的內(nèi)容。如果您未請(qǐng)求此權(quán)限,則當(dāng)時(shí)您將不會(huì)收到廣播。盡管擁有此權(quán)限并不會(huì)產(chǎn)生任何安全隱患,但它可能會(huì)增加系統(tǒng)啟動(dòng)所需的時(shí)間,并允許應(yīng)用程序在用戶不知情的情況下自行運(yùn)行,從而對(duì)用戶體驗(yàn)產(chǎn)生負(fù)面影響。因此,您必須明確聲明您使用此工具以使其對(duì)用戶可見(jiàn) |
| REQUEST_COMPANION_RUN_IN_BACKGROUND | 允許伴隨應(yīng)用在后臺(tái)運(yùn)行 |
| REQUEST_COMPANION_USE_DATA_IN_BACKGROUND | 允許配套應(yīng)用在后臺(tái)使用數(shù)據(jù) |
| REQUEST_DELETE_PACKAGES | |
| REQUEST_IGNORE_BATTERY_OPTIMIZATIONS | 允許應(yīng)用程序請(qǐng)求刪除軟件包。定位API [P]或更高版本的應(yīng)用必須擁有此權(quán)限才能使用[ACTION_UNINSTALL_PACKAGE]或 [uninstall(VersionedPackage, IntentSender)]
|
| REQUEST_INSTALL_PACKAGES | 允許應(yīng)用程序請(qǐng)求安裝軟件包。定位API大于25的應(yīng)用必須擁有此權(quán)限才能使用[ACTION_INSTALL_PACKAGE]
|
| SET_ALARM | 允許應(yīng)用程序廣播一個(gè)意圖為用戶設(shè)置警報(bào) |
| SET_TIME_ZONE | 允許應(yīng)用程序設(shè)置系統(tǒng)時(shí)區(qū) |
| SET_WALLPAPER | 允許應(yīng)用程式設(shè)定墻紙 |
| SET_WALLPAPER_HINTS | 允許應(yīng)用程式設(shè)定壁紙?zhí)崾?/td> |
| TRANSMIT_IR | 允許使用設(shè)備的紅外發(fā)射器(如果可用) |
| UNINSTALL_SHORTCUT | 此權(quán)限不再受支持 |
| USE_FINGERPRINT | 允許應(yīng)用使用指紋硬件 |
| VIBRATE | 允許訪問(wèn)振動(dòng)器 |
| WAKE_LOCK | 允許使用電源管理器的WakeLocks讓處理器免于睡眠或屏幕變暗 |
| WRITE_SYNC_SETTINGS | 允許應(yīng)用程序?qū)懭胪皆O(shè)置 |
-
危險(xiǎn)權(quán)限涵蓋應(yīng)用需要涉及用戶隱私信息的數(shù)據(jù)或資源,或者可能對(duì)用戶存儲(chǔ)的數(shù)據(jù)或其他應(yīng)用的操作產(chǎn)生影響的區(qū)域。例如,能夠讀取用戶的聯(lián)系人屬于危險(xiǎn)權(quán)限。如果應(yīng)用聲明其需要危險(xiǎn)權(quán)限,則用戶必須明確向應(yīng)用授予該權(quán)限
權(quán)限組
所有危險(xiǎn)的 Android 系統(tǒng)權(quán)限都屬于權(quán)限組。如果設(shè)備運(yùn)行的是 Android 6.0(API 級(jí)別 23),并且應(yīng)用的 [targetSdkVersion] 是 23 或更高版本,則當(dāng)用戶請(qǐng)求危險(xiǎn)權(quán)限時(shí)系統(tǒng)會(huì)發(fā)生以下行為:
- 如果應(yīng)用請(qǐng)求其清單中列出的危險(xiǎn)權(quán)限,而應(yīng)用目前在權(quán)限組中沒(méi)有任何權(quán)限,則系統(tǒng)會(huì)向用戶顯示一個(gè)對(duì)話框,描述應(yīng)用要訪問(wèn)的權(quán)限組。對(duì)話框不描述該組內(nèi)的具體權(quán)限。例如,如果應(yīng)用請(qǐng)求
[READ_CONTACTS]權(quán)限,系統(tǒng)對(duì)話框只說(shuō)明該應(yīng)用需要訪問(wèn)設(shè)備的聯(lián)系信息。如果用戶批準(zhǔn),系統(tǒng)將向應(yīng)用授予其請(qǐng)求的權(quán)限。 - 如果應(yīng)用請(qǐng)求其清單中列出的危險(xiǎn)權(quán)限,而應(yīng)用在同一權(quán)限組中已有另一項(xiàng)危險(xiǎn)權(quán)限,則系統(tǒng)會(huì)立即授予該權(quán)限,而無(wú)需與用戶進(jìn)行任何交互。例如,如果某應(yīng)用已經(jīng)請(qǐng)求并且被授予了
[READ_CONTACTS]權(quán)限,然后它又請(qǐng)求[WRITE_CONTACTS],系統(tǒng)將立即授予該權(quán)限。
任何權(quán)限都可屬于一個(gè)權(quán)限組,包括正常權(quán)限和應(yīng)用定義的權(quán)限。但權(quán)限組僅當(dāng)權(quán)限危險(xiǎn)時(shí)才影響用戶體驗(yàn)??梢院雎哉?quán)限的權(quán)限組。
如果設(shè)備運(yùn)行的是 Android 5.1(API 級(jí)別 22)或更低版本,并且應(yīng)用的 [targetSdkVersion]是 22 或更低版本,則系統(tǒng)會(huì)在安裝時(shí)要求用戶授予權(quán)限。再次強(qiáng)調(diào),系統(tǒng)只告訴用戶應(yīng)用需要的權(quán)限組,而不告知具體權(quán)限。

定義和實(shí)施權(quán)限
要實(shí)施您自己的權(quán)限,必須先使用一個(gè)或多個(gè) [<permission>]元素在 AndroidManifest.xml 中聲明它們。
例如,想要控制誰(shuí)可以開(kāi)始其中一個(gè) Activity 的應(yīng)用可如下所示聲明此操作的權(quán)限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp" >
<permission android:name="com.example.myapp.permission.DEADLY_ACTIVITY"
android:label="@string/permlab_deadlyActivity"
android:description="@string/permdesc_deadlyActivity"
android:permissionGroup="android.permission-group.COST_MONEY"
android:protectionLevel="dangerous" />
...
</manifest>
注:系統(tǒng)不允許多個(gè)軟件包使用同一名稱聲明權(quán)限,除非所有軟件包都使用同一證書簽署。如果軟件包聲明權(quán)限,則系統(tǒng)不允許用戶安裝具有相同權(quán)限名稱的其他軟件包,除非這些軟件包使用與第一個(gè)軟件包相同的證書簽署。為避免命名沖突,建議對(duì)自定義權(quán)限使用相反域名樣式命名,例如 com.example.myapp.ENGAGE_HYPERSPACE。[protectionLevel] 屬性是必要屬性,用于指示系統(tǒng)如何向用戶告知需要權(quán)限的應(yīng)用,或者誰(shuí)可以擁有該權(quán)限,具體如鏈接的文檔中所述。
[android:permissionGroup]屬性是可選屬性,只是用于幫助系統(tǒng)向用戶顯示權(quán)限。大多數(shù)情況下,您要將此設(shè)為標(biāo)準(zhǔn)系統(tǒng)組(列在 [android.Manifest.permission_group] 中),但您也可以自己定義一個(gè)組。建議使用現(xiàn)有的組,因?yàn)檫@樣可簡(jiǎn)化向用戶顯示的權(quán)限 UI。
需要為權(quán)限提供標(biāo)簽和描述。這些是用戶在查看權(quán)限列表([android:label])或單一權(quán)限詳細(xì)信息([android:description])時(shí)可以看到的字符串資源。標(biāo)簽應(yīng)簡(jiǎn)短;用幾個(gè)詞描述權(quán)限保護(hù)的功能的關(guān)鍵部分。描述應(yīng)該用幾個(gè)句子描述權(quán)限允許持有人執(zhí)行的操作。我們的約定是用兩個(gè)句子描述:第一句描述權(quán)限,第二句向用戶提醒為應(yīng)用授予權(quán)限后可能出現(xiàn)的錯(cuò)誤類型。
下面是 CALL_PHONE 權(quán)限的標(biāo)簽和描述示例:
<string name="permlab_callPhone">directly call phone numbers</string>
<string name="permdesc_callPhone">Allows the application to call
phone numbers without your intervention. Malicious applications may
cause unexpected calls on your phone bill. Note that this does not
allow the application to call emergency numbers.</string>
您可以使用 Settings 應(yīng)用和 shell 命令 adb shell pm list permissions 查看系統(tǒng)中當(dāng)前定義的權(quán)限。要使用 Settings 應(yīng)用,請(qǐng)轉(zhuǎn)到 Settings > Applications。選擇一個(gè)應(yīng)用并向下滾動(dòng)查看該應(yīng)用使用的權(quán)限。對(duì)于開(kāi)發(fā)者,adb '-s' 選項(xiàng)以類似于用戶將會(huì)看到的形式顯示權(quán)限:
$ adb shell pm list permissions -s
All Permissions:
Network communication: view Wi-Fi state, create Bluetooth connections, full
Internet access, view network state
Your location: access extra location provider commands, fine (GPS) location,
mock location sources for testing, coarse (network-based) location
Services that cost you money: send SMS messages, directly call phone numbers
自定義權(quán)限建議
應(yīng)用可以定義自己的自定義權(quán)限,并通過(guò)定義 [<uses-permission>] 元素請(qǐng)求其他應(yīng)用的自定義權(quán)限。不過(guò),您應(yīng)該仔細(xì)評(píng)估您的應(yīng)用是否有必要這樣做。
- 如果要設(shè)計(jì)一套向彼此顯示功能的應(yīng)用,請(qǐng)盡可能將應(yīng)用設(shè)計(jì)為每個(gè)權(quán)限只定義一次。如果所有應(yīng)用并非使用同一證書簽署,則必須這樣做。即使所有應(yīng)用使用同一證書簽署,最佳做法也是每個(gè)權(quán)限只定義一次。
- 如果功能僅適用于使用與提供應(yīng)用相同的簽名所簽署的應(yīng)用,您可能可以使用簽名檢查避免定義自定義權(quán)限。當(dāng)一個(gè)應(yīng)用向另一個(gè)應(yīng)用發(fā)出請(qǐng)求時(shí),第二個(gè)應(yīng)用可在遵從該請(qǐng)求之前驗(yàn)證這兩個(gè)應(yīng)用是否使用同一證書簽署。
- 如果您要開(kāi)發(fā)一套只在您自己的設(shè)備上運(yùn)行的應(yīng)用,則應(yīng)開(kāi)發(fā)并安裝管理該套件中所有應(yīng)用權(quán)限的軟件包。此軟件包本身無(wú)需提供任何服務(wù)。它只是聲明所有權(quán)限,然后套件中的其他應(yīng)用通過(guò) [
<uses-permission>]元素請(qǐng)求這些權(quán)限。
實(shí)施 AndroidManifest.xml 中的權(quán)限
您可以通過(guò) AndroidManifest.xml 應(yīng)用高級(jí)權(quán)限,限制訪問(wèn)系統(tǒng)或應(yīng)用的全部組件。要執(zhí)行此操作,在所需的組件上包含 [android:permission](https://developer.android.com/reference/android/R.attr.html#permission) 屬性,為用于控制訪問(wèn)它的權(quán)限命名。
[Activity] 權(quán)限(應(yīng)用于 [<activity>] 標(biāo)記)限制誰(shuí)可以啟動(dòng)相關(guān)的 Activity。在 [Context.startActivity()] 和 [Activity.startActivityForResult()] 時(shí)會(huì)檢查權(quán)限;如果調(diào)用方?jīng)]有所需的權(quán)限,則調(diào)用會(huì)拋出 [SecurityException]。
**[Service]** 權(quán)限(應(yīng)用于[<service>]標(biāo)記)限制誰(shuí)可以啟動(dòng)或綁定到相關(guān)的服務(wù)。在[Context.startService()]、[Context.stopService()]和[Context.bindService()]時(shí)會(huì)檢查權(quán)限;如果調(diào)用方?jīng)]有所需的權(quán)限,則調(diào)用會(huì)拋出[SecurityException]`。
[BroadcastReceiver] 權(quán)限(應(yīng)用于 [<receiver>] 標(biāo)記)限制誰(shuí)可以發(fā)送廣播給相關(guān)的接收方。在 [Context.sendBroadcast()] 返回后檢查權(quán)限,因?yàn)橄到y(tǒng)會(huì)嘗試將提交的廣播傳遞到指定的接收方。因此,權(quán)限失效不會(huì)導(dǎo)致向調(diào)用方拋回異常;只是不會(huì)傳遞該 intent。同樣,可以向 [Context.registerReceiver()] 提供權(quán)限來(lái)控制誰(shuí)可以廣播到以編程方式注冊(cè)的接收方。另一方面,可以在調(diào)用 [Context.sendBroadcast()] 時(shí)提供權(quán)限來(lái)限制允許哪些 BroadcastReceiver 對(duì)象接收廣播(請(qǐng)參閱下文)。
[ContentProvider] 權(quán)限(應(yīng)用于 [<provider>] 標(biāo)記)限制誰(shuí)可以訪問(wèn) [ContentProvider] 中的數(shù)據(jù)。(內(nèi)容提供程序有重要的附加安全工具可用,稱為 URI 權(quán)限,將在后面介紹。)與其他組件不同,您可以設(shè)置兩個(gè)單獨(dú)的權(quán)限屬性:[android:readPermission] 限制誰(shuí)可以讀取提供程序,[android:writePermission] 限制誰(shuí)可以寫入提供程序。請(qǐng)注意,如果提供程序有讀取和寫入權(quán)限保護(hù),僅擁有寫入權(quán)限并不表示您可以讀取提供程序。第一次檢索提供程序時(shí)將會(huì)檢查權(quán)限(如果沒(méi)有任何權(quán)限,將會(huì)拋出 SecurityException),對(duì)提供程序執(zhí)行操作時(shí)也會(huì)檢查權(quán)限。使用 [ContentResolver.query()] 需要擁有讀取權(quán)限;使用 [ContentResolver.insert()]、[ContentResolver.update()]、[ContentResolver.delete()] 需要寫入權(quán)限。在所有這些情況下,沒(méi)有所需的權(quán)限將導(dǎo)致調(diào)用拋出 [SecurityException]。
發(fā)送廣播時(shí)實(shí)施權(quán)限
除了實(shí)施誰(shuí)可以向注冊(cè)的 [BroadcastReceiver] 發(fā)送 intent 的權(quán)限(如上所述),您還可以指定在發(fā)送廣播時(shí)需要的權(quán)限。通過(guò)使用權(quán)限字符串調(diào)用 [Context.sendBroadcast()],您可以要求接收方的應(yīng)用必須擁有該權(quán)限才可接收您的廣播。
請(qǐng)注意,接收者和廣播者可能需要權(quán)限。此時(shí),這兩項(xiàng)權(quán)限檢查都必須通過(guò)后方可將 intent 傳遞到相關(guān)的目標(biāo)。
其他權(quán)限實(shí)施
可對(duì)任何服務(wù)調(diào)用實(shí)施任意細(xì)化的權(quán)限。這可通過(guò) [Context.checkCallingPermission()] 方法完成。使用所需的權(quán)限字符串調(diào)用,它將返回一個(gè)整數(shù),表示權(quán)限是否已授予當(dāng)前的調(diào)用進(jìn)程。請(qǐng)注意,僅在執(zhí)行從另一個(gè)進(jìn)程傳入的調(diào)用(通常是通過(guò)從服務(wù)發(fā)布的 IDL 界面或者指定給另一進(jìn)程的某種其他方式完成)時(shí)才可使用此方法。
檢查權(quán)限還有許多其他有用的方法。如果您有另一個(gè)進(jìn)程的 pid,可以使用 Context 方法 [Context.checkPermission(String, int, int)] 檢查針對(duì)該 pid 的權(quán)限。如果您有另一個(gè)應(yīng)用的軟件包名稱,可以使用直接的 PackageManager 方法 [PackageManager.checkPermission(String, String)] 了解是否已為特定軟件包授予特定權(quán)限。
URI 權(quán)限
到目前為止所述的是標(biāo)準(zhǔn)權(quán)限系統(tǒng),內(nèi)容提供程序僅僅使用此系統(tǒng)通常是不夠的。內(nèi)容提供程序可能需要通過(guò)讀取和寫入權(quán)限保護(hù)自己,而其直接客戶端也需要將特定 URI 傳給其他應(yīng)用以便于它們運(yùn)行。郵件應(yīng)用中的附件是一個(gè)典型的示例。應(yīng)通過(guò)權(quán)限保護(hù)對(duì)郵件的訪問(wèn),因?yàn)檫@是敏感的用戶數(shù)據(jù)。但是,如果將圖像附件的 URI 提供給圖像查看程序,該圖像查看程序不會(huì)有打開(kāi)附件的權(quán)限,因?yàn)樗鼪](méi)有理由擁有訪問(wèn)所有電子郵件的權(quán)限。
此問(wèn)題的解決方法是采用 per-URI 權(quán)限機(jī)制:在啟動(dòng) Activity 或返回結(jié)果給 Activity 時(shí),調(diào)用方可以設(shè)置 [Intent.FLAG_GRANT_READ_URI_PERMISSION] 和/或 [Intent.FLAG_GRANT_WRITE_URI_PERMISSION]。這將授予接收 Activity 權(quán)限訪問(wèn) intent 中的特定數(shù)據(jù) URI,而不管它是否具有訪問(wèn) intent 對(duì)應(yīng)的內(nèi)容提供程序中數(shù)據(jù)的任何權(quán)限。
此機(jī)制支持常見(jiàn)的能力式模型,其中用戶交互(打開(kāi)附件、從列表中選擇聯(lián)系人等)驅(qū)動(dòng)臨時(shí)授予細(xì)化的權(quán)限。這是一項(xiàng)關(guān)鍵功能,可將應(yīng)用所需的權(quán)限縮小至只與其行為直接相關(guān)的權(quán)限。
但授予細(xì)化的 URI 權(quán)限需要與擁有這些 URI 的內(nèi)容提供程序進(jìn)行一定的合作。強(qiáng)烈建議內(nèi)容提供程序?qū)嵤┐斯δ?,并且通過(guò) [android:grantUriPermissions] 屬性或 [<grant-uri-permissions>] 標(biāo)記聲明支持此功能。
在 [Context.grantUriPermission()]、[Context.revokeUriPermission()] 和 [Context.checkUriPermission()] 方法中可以找到更多信息。
2018/3/14