1.引言
android system/etc 中有很多配置文件,例如白名單,例如system-private 權限區(qū)別,還例如 如何配置aapp的內存。這些都是懵逼的。抱著好奇心態(tài),決定深入進去看看一般是怎么設置的。參考鏈接:https://blog.csdn.net/superkris/article/details/7709504/
2.Android的權限規(guī)則
2.1 基于UserID的進程級別的安全機制
進程有獨立的地址空間,進程與進程間默認是不能互相訪問的,Android通過為每一個apk分配唯一的linux userID來實現(xiàn),名稱為"app_"加一個數(shù)字,比如app_43不同的UserID,運行在不同的進程,所以apk之間默認便不能相互訪問。
Android提供了如下的一種機制,可以使兩個apk打破前面講的這種壁壘。 在AndroidManifest.xml中利用sharedUserId屬性給不同的package分配相同的userID,通過這樣做,兩個package可以被當做同一個程序, 系統(tǒng)會分配給兩個程序相同的UserID。當然,基于安全考慮,兩個apk需要相同的簽名,否則沒有驗證也就沒有意義了
2.2 默認apk生成的數(shù)據對外是不可見的
實現(xiàn)方法是:Android會為程序存儲的數(shù)據分配該程序的UserID。借助于Linux嚴格的文件系統(tǒng)訪問權限,便實現(xiàn)了apk之間不能相互訪問似有數(shù)據的機制。 例:我的應用創(chuàng)建的一個文件,默認權限如下,可以看到只有UserID為app_21的程序才能讀寫該文件
2.3 root權限和system權限
-
root權限
擁有root權限的用戶,其uid=0. 擁有系統(tǒng)約定的最高權限。可以訪問絕大部分文件
-
system 權限
system/app 下面的apk
system/priv-app 下面的apk。
倆者的區(qū)別在于:倆者雖然都是系統(tǒng)app,但是system/priv-app 中所具有的權限,要大于system/app
-
特權權限
特權應用程序是位于
/system/priv-app目錄下的系統(tǒng)應用程序 。過去,設備制造商幾乎無法控制可對特權應用授予哪些簽名|特許權限。從 Android 8.0 開始,制造商必須在/etc/permissions目錄下的系統(tǒng)配置 XML 文件中明確授予特許權限。從 Android 9 開始,實現(xiàn)人員必須明確授予或拒絕授予所有特許權限,否則設備將無法啟動。
frameworks\base\core\res\AndroidManifest.xml 定義了各種廣播,普通權限,危險權限,特權權限:
<!-- Allows notifications to be colorized
<p>Not for use by third-party applications. @hide -->
<permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
android:protectionLevel="signature|setup" /> //setting 具備的
<!-- Allows access to keyguard secure storage. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
android:protectionLevel="signature" /> //系統(tǒng)簽名
<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
android:protectionLevel="signature|privileged" /> //系統(tǒng)簽名且還需要在system/priv-app 下
<!-- Allows an app to reset fingerprint attempt counter. Reserved for the system. @hide -->
<permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT"
android:protectionLevel="signatureorsystem " /> //系統(tǒng)簽名且還得是系統(tǒng)app(system/priv-app 或system/app)
Android 權限分成四類:
普通權限(normal permission):也叫正常權限,即使擁有了該類權限,用戶的隱私數(shù)據被泄露篡改的風險也很小。例如,設置時區(qū)的權限就是正常權限。如果應用聲明其需要正常權限,系統(tǒng)會自動向應用授予該權限。
敏感權限(dangerous permission):也叫危險權限,運行時權限,跟普通權限相反,一旦某個應該獲取了該類權限,用戶的隱私數(shù)據就面臨被泄露篡改的風險。比如 READ_CONTACTS 權限就屬于危險權限。如果應用聲明其需要危險權限,則用戶必須明確向應用授予該權限。
簽名權限(signature permission):該類權限只對擁有相同簽名的應用開放,比如手機QQ 自定義了一個permission 且在權限標簽中加入 android:protectionLevel=”signature”,而訪問它的某個數(shù)據時,必須要擁有該權限。然后微信和 QQ 發(fā)布時采用相同的簽名,微信就可以申請訪問 QQ 中的此權限,并使用對應權限控制的數(shù)據。其他程序即使知道了這個開放數(shù)據的接口,也在 Manifest 注冊了權限,但由于應用簽名不同,還是無法訪問的對應的數(shù)據。
系統(tǒng)簽名權限(signatureOrSystem permission):與 signature permission類似,但它不光要求簽名相同,還要求是同類的系統(tǒng)級應用,一般手機廠商開發(fā)的預制應用,才會用到該類權限
應用場景1:
前提:app 系統(tǒng)簽過名且放置于system/app/下
操作: 調用 Settings.System.putInt
現(xiàn)象:
Caused by: java.lang.IllegalArgumentException: You cannot keep your settings in the secure settings.
解決方案: 將app 防止于system/priv-app下
問題: 為什么放置于system/priv-app就解決了問題呢?
源碼分析:putInt方法最終會調用: enforceRestrictedSystemSettingsMutationForCallingPackage 方法
1858 private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
1859 String name, int userId) {
1860 // System/root/shell can mutate whatever secure settings they want.
1861 final int callingUid = Binder.getCallingUid();
1862 final int appId = UserHandle.getAppId(callingUid);
1863 if (appId == android.os.Process.SYSTEM_UID
1864 || appId == Process.SHELL_UID
1865 || appId == Process.ROOT_UID) {
1866 return;
1867 }
1868
1869 switch (operation) {
1870 case MUTATION_OPERATION_INSERT:
1871 // Insert updates.
1872 case MUTATION_OPERATION_UPDATE: {
1873 if (Settings.System.PUBLIC_SETTINGS.contains(name)) {
1874 return;
1875 }
1876
1877 // The calling package is already verified.
1878 PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
1879
1880 // Privileged apps can do whatever they want. 只要是特權應用,就可以直接插入數(shù)據
1881 if ((packageInfo.applicationInfo.privateFlags
1882 & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
1883 return;
1884 }
1885 // 檢查是否具備插入數(shù)據的資格,沒得就會拋出異常
1886 warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk(
1887 packageInfo.applicationInfo.targetSdkVersion, name);
1888 } break;
18
1910 }
應用場景2:
前提:國內 app 采用系統(tǒng)簽名,放在/system/priv-app/下,但是沒有添加 android:sharedUserId="android.uid.system
操作:app本身是一個service,需要有讀寫權限
現(xiàn)象:app中直接進行創(chuàng)建/刪除文件,報錯,提示沒得讀寫權限
解決方案:
Y:\aosp\device\google\marlin\default-permissions.xml:
<exceptions>
<exception package="com.verizon.mips.services">
<permission name="android.permission.PROCESS_OUTGOING_CALLS" fixed="false"/>
<permission name="android.permission.READ_PHONE_STATE" fixed="false"/>
<permission name="android.permission.RECEIVE_SMS" fixed="false"/>
</exception>
</exceptions>
default-permissions 配置文件會在第一次開機的時候加載。所以假如直接更改開發(fā)版中的default-permissions。需要格式化開發(fā)板,恢復出廠模式、
應用場景3:
前提:國內 app 采用系統(tǒng)簽名,放在/system/priv-app/下,但是沒有添加 android:sharedUserId="android.uid.system且android:persistent="false"
操作: 代碼中直接使用startService啟動服務
現(xiàn)象:
Not allowed to start service Intent { flg=0x1000000 cmp=packagename/.servicename (has extras) }: app is in background uid UidRecord{52db80 u2357s1000 TRNB bg:+2m42s199ms idle procs:3 seq(0,0,0)}
問題: app系統(tǒng)簽名且置于/system/app/下 但是為啥startService 還報錯呢?且為什么加上android:persistent="true"就ok了呢
解答:
startService 啟動服務流程中,有一個方法appServicesRestrictedInBackgroundLocked
int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Persistent app?
if (mPackageManagerInt.isPackagePersistent(packageName)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " is persistent; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
}
// Non-persistent but background whitelisted?
if (uidOnBackgroundWhitelist(uid)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " on background whitelist; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
}
// Is this app on the battery whitelist?
if (isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ false)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " on idle whitelist; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
}
// None of the service-policy criteria apply, so we apply the common criteria
return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
}
應用場景4:
前提:AndroidManifest 中添加android:sharedUserId="android.uid.system"
操作:代碼中調用安裝apk的代碼
現(xiàn)象:彈出如下所示的dialog
問題:為什么會彈出這個框?如何解決這個問題
第一個問題解答:ActivityManagerService#checkGrantUriPermissionLocked
if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
9715 if ("com.android.settings.files".equals(grantUri.uri.getAuthority())
9716 || SystemConfig.getInstance().getAuthoriesInPreloadedApks().contains(
9717 grantUri.uri.getAuthority())) {
9718 // Exempted authority for
9719 // 1. cropping user photos and sharing a generated license html
9720 // file in Settings app
9721 // 2. sharing a generated license html file in TvSettings app
9722 } else {
9723 Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
9724 + " grant to " + grantUri + "; use startActivityAsCaller() instead");
9725 return -1;
9726 }
9727 }
callUid為SYSTEM_UID,且不滿足倆個if 則return -1 ,于是就出現(xiàn)上述的安裝失敗情況。
解決方式有倆種:
- 去掉android:sharedUserId
- 更改SystemConfig.java