亚欧色一区w666天堂,色情一区二区三区免费看,少妇特黄A片一区二区三区,亚洲人成网站999久久久综合,国产av熟女一区二区三区

  • 發布文章
  • 消息中心
點贊
收藏
評論
分享
原創

Android權限管理和鑒權過程

2023-08-21 03:05:21
59
0

Android系統權限(xian)是(shi)建立在(zai)框架層上的(de)一套權限(xian)解析分(fen)配和鑒權流(liu)(liu)程(cheng),其主要(yao)數(shu)據結構和校(xiao)驗流(liu)(liu)程(cheng)主要(yao)在(zai)pms(包(bao)管理(li)服務)中實現。

簡單理解系(xi)統(tong)權(quan)限(xian)機制主要分(fen)為權(quan)限(xian)解析(xi)、權(quan)限(xian)分(fen)配、鑒(jian)權(quan)這三(san)個主要內容。

Sdk版本大于等于23后,新增了動態權限(xian)管(guan)理(li)(li),讓(rang)Android系(xi)統權限(xian)管(guan)理(li)(li)更加靈活(huo)和自主。

下面(mian)來分析(xi)下Android 5.1上面(mian)的權(quan)限管(guan)理和鑒(jian)權(quan)過程(cheng)。

權限的數據結構

涉及(ji)到系統(tong)權限的(de)數(shu)據(ju)結構如上圖所示(shi),分(fen)別(bie)來(lai)分(fen)析每(mei)個(ge)數(shu)據(ju)結構的(de)內容(rong)和(he)作用(yong)。

Ø BasePermission

系統權(quan)限(xian)(xian)的(de)(de)基本表示單(dan)元是BasePermission,Settings中(zhong)(zhong)維護了一個總的(de)(de)權(quan)限(xian)(xian)映射(she)表mPermissions,所有(you)的(de)(de)權(quan)限(xian)(xian)都會(hui)添加(jia)到mPermissions列表中(zhong)(zhong),其中(zhong)(zhong)key是權(quan)限(xian)(xian)的(de)(de)名字(zi),value是具體的(de)(de)BasePermission實例。

[/frameworks/base/services/core/java/com/android/server/pm/Settings.java]

// Mapping from permission names to info about them.
final ArrayMap<String, BasePermission> mPermissions =  new ArrayMap<String, BasePermission>();

  我(wo)們(men)都(dou)知道絕大部分權限(xian)已經在(zai)系(xi)統中(zhong)定義好,如READ_EXTERNAL_STORAGE讀寫外部存儲權限(xian)、READ_PHONE_STATE讀取(qu)手機(ji)狀態信(xin)息權限(xian)等,這些權限(xian)的定義都(dou)在(zai)framework-res.apk中(zhong),在(zai)掃描framework-res.apk過程中(zhong)解析并(bing)添(tian)加到mPermissions映射表中(zhong)。系(xi)統權限(xian)的定義:

[/frameworks/base/core/res/AndroidManifest.xml]

系統中(zhong)絕大部(bu)分的權限(xian)定義都(dou)在frameworks/base/services/core/res/AndroidManifest.xml中(zhong),最終會打包進framework-res.apk中(zhong)并經過解(jie)析保存到(dao)Settings的mPermissions映射表中(zhong)。

Ø PackageParser.Permission

PackageParser.Permission在上面分(fen)析PackageParser解析apk過程(cheng)中有(you)提及過,解析apk的(de)AndroidManifest.xml文件中的(de)標簽后得(de)到的(de)權限表示。

PackageParser.Permission中(zhong)包含一個對應的(de)PermissionInfo。

Ø PermissionInfo

權(quan)限(xian)信息的表示,其(qi)中包(bao)含權(quan)限(xian)等級的定義(yi)(NORMAL, DANGER, SIGNERATURE),另外實(shi)現(xian)了序列(lie)化(hua),用(yong)戶(hu)于進程(cheng)間通信。每個BasePermission實(shi)例(li)中包(bao)含一個PermissionInfo的實(shi)例(li)。

以上(shang)三個類結構(gou)是系統權限部分的定義,下(xia)面四(si)個類結構(gou)和(he)pkg強相(xiang)關,表示pkg的權限狀態。

Ø GrantedPermissions

表(biao)示一(yi)(yi)個(ge)pkg已經(jing)(jing)賦予(yu)的(de)(de)權限(xian),類里面定義了一(yi)(yi)個(ge)字符串列(lie)表(biao)grantedPermissions保存pkg已經(jing)(jing)被賦予(yu)的(de)(de)所有權限(xian)。

[/frameworks/base/services/core/java/com/android/server/pm/GrantedPermissions.java]

class GrantedPermissions {
    int pkgFlags; 
    ArraySet<String> grantedPermissions = new ArraySet<String>();

Ø PackageSettingBase

PackageSettingBase繼承(cheng)了GrantedPermissions類(lei)并添加更多和 pkg相關(guan)的(de)信息(xi),是(shi)一個pkg信息(xi)的(de)基(ji)本表示類(lei)。PackageSettingBase保存為了如pkg的(de)codePath, resourcePath, signature等信息(xi),同時PackageSettingBase是(shi)GrantedPermissions的(de)子類(lei),因為也包(bao)含了pkg被賦予的(de)權(quan)限列(lie)表。

Ø PackageSetting

PackageSetting繼承了PackageSettingBase類(lei)(lei),并新增如PackageParser.Package和SharedUserSetting。那(nei)么以(yi)后(hou)只(zhi)要獲(huo)得一(yi)個(ge)pkg的(de)(de)PackageSetting實(shi)例(li),就(jiu)可以(yi)獲(huo)得對應的(de)(de)SharedUserSetting實(shi)例(li),通(tong)過這個(ge)SharedUserSetting實(shi)例(li)來獲(huo)得與(yu)其(qi)sharedUser的(de)(de)其(qi)他(ta)pkg信息。同(tong)時PackageSetting是GrantedPermissions的(de)(de)子類(lei)(lei),那(nei)么也就(jiu)意味著只(zhi)要拿(na)到(dao)pkg的(de)(de)PackageSetting實(shi)例(li)就(jiu)可以(yi)知(zhi)道(dao)pkg已經被賦(fu)予了哪些(xie)權(quan)限。

Ø SharedUserSetting

SharedUserSetting繼承(cheng)了(le)(le)GrantedPermissions,類里面保存了(le)(le)一個(ge)packages的列(lie)表,表示(shi)這(zhe)個(ge)列(lie)表中(zhong)的所有應用共享該uid。同時共享這(zhe)個(ge)uid所賦予(yu)的所有權限。

權限管理
我(wo)們知道在pms構(gou)造方(fang)法中(zhong)掃(sao)描(miao)apk后,創(chuang)建對應的(de)PackageSetting實例(li)并賦予給pkg的(de)mExtras,以(yi)后我(wo)們就可以(yi)通過(guo)(guo)pkg.mExtras獲得相應的(de)PackageSetting實例(li)。一(yi)開始掃(sao)描(miao)過(guo)(guo)程中(zhong),PackageSetting實例(li)中(zhong)保(bao)存的(de)grantedPermissions列表為空,權(quan)限的(de)賦予會在pms構(gou)造方(fang)法的(de)結束(shu)部分(fen),通過(guo)(guo)調用(yong)updatePermissionsLPw方(fang)法遍歷(li)所有(you)已經(jing)安裝的(de)pkg,一(yi)個一(yi)個的(de)根(gen)據其請求(qiu)的(de)權(quan)限來確定(ding)是否賦予。

首先來看(kan)看(kan)updatePermissionsLPw方法:

[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

    private void updatePermissionsLPw(String changingPkg,PackageParser.Package pkgInfo, int flags) {
        // Make sure there are no dangling permission trees.
        // 更新permission trees列表,去除無效的permission tree
        // Make sure all dynamic permissions have been assigned to a package,
        // and make sure there are no dangling permissions.
        // 更新permission列表,去除無效無主的permission定義
        if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
            for (PackageParser.Package pkg : mPackages.values()) {
                if (pkg != pkgInfo) {
                    grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
                            changingPkg);
                }
            }
        }
        if (pkgInfo != null) {
            grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
        }
    }

updatePermissionsLPw方法中主要(yao)做兩個事情,檢查無效的(de)permissiontree和permission定義,另(ling)外(wai)一(yi)個就(jiu)是根(gen)據(ju)傳(chuan)入的(de)flags是否帶有UPDATE_PERMISSIONS_ALL來遍歷mPackages包列表來更新所有安裝包的(de)權(quan)限(xian)信息。重點分析grantPermissionsLPw方法。

[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

 
     private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace, String packageOfInterest) {        
final PackageSetting ps = (PackageSetting) pkg.mExtras; 
        final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
              ArraySet<String> origPermissions = gp.grantedPermissions;
        boolean changedPermission = false;  
        /* 獲得解析pkg中請求的權限數量,循環一個一個去決定是否分配給該應用或者sharedUserId */     
        final int N = pkg.requestedPermissions.size();
        for (int i=0; i<N; i++) {
            final String name = pkg.requestedPermissions.get(i);
            final boolean required = pkg.requestedPermissionsRequired.get(i);
            final BasePermission bp = mSettings.mPermissions.get(name);
            /* 檢查應用申請的這個權限是否存在有效,如果無效,忽略 */
            if (bp == null || bp.packageSetting == null) {
                if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
                    Slog.w(TAG, "Unknown permission " + name  + " in package " + pkg.packageName);
                }
                continue;
            }
            final String perm = bp.name;
            boolean allowed;
            boolean allowedSig = false;
            final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
            if (level == PermissionInfo.PROTECTION_NORMAL || level == PermissionInfo.PROTECTION_DANGEROUS) {
                /* 權限等級為NORMAL和DANGER的權限,只要申請就分配 */
                allowed = (required || origPermissions.contains(perm)
                        || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
            } else if (bp.packageSetting == null) {
                /* 無頭的權限,直接拒絕 */
                allowed = false;
            } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
/* 權限等級要求簽名的,檢查該pkg簽名是否和platform apk簽名一致,一致則返回 */
                allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
                if (allowed) { allowedSig = true; }
            } else {
                allowed = false;
            }
            if (allowed) {                
                if (allowed) {
                    if (!gp.grantedPermissions.contains(perm)) {
                        /* 權限允許賦予后,如果pkg已獲得權限列表中沒有,則添加 */
                        changedPermission = true;
                        gp.grantedPermissions.add(perm);
                        gp.gids = appendInts(gp.gids, bp.gids);
                    } 
                } 
            } else {
            /* 權限不允許 */
                if (gp.grantedPermissions.remove(perm)) {
/* 如果已獲取權限列表中存在去除的該權限,說明apk版本有變化 */
                    changedPermission = true;
                    gp.gids = removeInts(gp.gids, bp.gids);
                }
            }
        }
   } 
 

grantPermissionsLPw方法中實(shi)現了(le)5.1權(quan)限賦予的(de)(de)(de)(de)(de)流程。主要(yao)流程首先獲(huo)得pkg的(de)(de)(de)(de)(de)PackageSettings實(shi)例(li),上面我們知道pkg的(de)(de)(de)(de)(de)PackageSettings實(shi)例(li)中包含了(le)應(ying)用(yong)已經獲(huo)得的(de)(de)(de)(de)(de)權(quan)限列(lie)(lie)表grantedPermissions。第一次開機掃描應(ying)用(yong)的(de)(de)(de)(de)(de)過程中,這個列(lie)(lie)表為空(kong)。通過遍歷包解析后得到的(de)(de)(de)(de)(de)requestPermissions列(lie)(lie)表的(de)(de)(de)(de)(de)權(quan)限的(de)(de)(de)(de)(de)等(deng)級來判斷是(shi)否授權(quan),如果請求的(de)(de)(de)(de)(de)權(quan)限授權(quan)成功后,就(jiu)會保存(cun)進入grantedPermissions列(lie)(lie)表中。

grantedPermissions列表會根(gen)據應用的(de)更新而更新。

權限管理(li)的基本流程(cheng)如(ru)上。

鑒權過程
一般客戶端調用checkPermission方法(fa)鑒權的流程如(ru)下:

①Context.java--->public int checkPermission(String permission, int pid, int uid)

②ActivityManagerService.java--->public int checkPermission(String permission, int pid, int uid)

③ActivityManagerService.java--->&nbsp;checkComponentPermission

④ActivityManager.java--->checkComponentPermission

Root用(yong)戶(uid=0)和System用(yong)戶(uid=1000)直接鑒(jian)權通(tong)過。

⑤PackageManagerService.java--->checkUidPermission

查看pms的checkUidPermission方法:

[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

    @Override
    public int checkUidPermission(String permName, int uid) {
        synchronized (mPackages) {
            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
            if (obj != null) {
                GrantedPermissions gp = (GrantedPermissions)obj;
                if (gp.grantedPermissions.contains(permName)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            } else {
                ArraySet<String> perms = mSystemPermissions.get(uid);
                if (perms != null && perms.contains(permName)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            }
        }
        return PackageManager.PERMISSION_DENIED;
    }

發現checkUidPermission方法(fa)中(zhong)(zhong)調用Settings的getUserIdLPr獲(huo)得一(yi)個Object實(shi)例,這個Object實(shi)例就是(shi)(shi)對應uid的pkgSettings實(shi)例,里面包(bao)含(han)grantedPermissions信息。最(zui)后(hou)查詢(xun)grantedPermissions列表中(zhong)(zhong)是(shi)(shi)否(fou)包(bao)含(han)所(suo)要檢查的權限即可判斷(duan)該(gai)uid是(shi)(shi)否(fou)具(ju)有該(gai)權限。

繼續分析Settings的getUserIdLPr方法:

[/frameworks/base/services/core/java/com/android/server/pm/Settings.java]

  public Object getUserIdLPr(int uid) {
        if (uid >= Process.FIRST_APPLICATION_UID) {
            final int N = mUserIds.size();
            final int index = uid - Process.FIRST_APPLICATION_UID;
            return index < N ? mUserIds.get(index) : null;
        } else {
            return mOtherUserIds.get(uid);
        }
  }

這個方(fang)法首先判斷檢查(cha)的(de)uid是否(fou)是應(ying)用(yong)的(de)uid(10000以上(shang)),如果是,通過(guo)uid來查(cha)詢(xun)mUserIds表(biao)來獲(huo)得對應(ying)uid的(de)pkgSettings實例(mUserIds就是uid和pkgSettings的(de)映(ying)射表(biao))。通過(guo)進一步分析,mUserIds列表(biao)是在手機開機后讀取packages.xml緩(huan)存(cun)生成的(de)。

鑒權流程2:

① 根據(ju)PMS解析的申請權限(xian)數據(ju),對應用添加gid

② 啟動(dong)應用進(jin)程時,指定所有對應的gid

舉(ju)例:android.permission.WRITE_EXTERNAL_STORAGE

① 應(ying)用(yong)在(zai)AndroidManifest.xml中申(shen)請android.permission.WRITE_EXTERNAL_STORAGE

② 安裝后,PMS解(jie)析(xi)該應用,并為該應用添加sdcard_rw的組ID。

③ 啟動該應(ying)用進程(cheng)時,使(shi)用上面解析的(de)gid。

0條評論
0 / 1000
hi_long
16文章(zhang)數
0粉絲數
hi_long
16 文(wen)章 | 0 粉絲
hi_long
16文章數
0粉(fen)絲(si)數
hi_long
16 文(wen)章 | 0 粉絲
原創(chuang)

Android權限管理和鑒權過程

2023-08-21 03:05:21
59
0

Android系統權限(xian)是建立在框(kuang)架層(ceng)上的一套(tao)權限(xian)解析(xi)分配和鑒權流(liu)程,其(qi)主要數據(ju)結構和校(xiao)驗流(liu)程主要在pms(包(bao)管理(li)服(fu)務)中實現。

簡單理解系統權(quan)(quan)限機制主要分為權(quan)(quan)限解析、權(quan)(quan)限分配(pei)、鑒(jian)權(quan)(quan)這三個(ge)主要內容。

Sdk版本大于等于23后,新增了動態權限(xian)管理,讓Android系統(tong)權限(xian)管理更加(jia)靈活(huo)和(he)自(zi)主。

下(xia)面(mian)來(lai)分析下(xia)Android 5.1上(shang)面(mian)的權限管理和鑒權過(guo)程。

權限的數據結構

涉及到系統權限的數據(ju)結(jie)構如(ru)上圖(tu)所示,分(fen)別來(lai)分(fen)析(xi)每個數據(ju)結(jie)構的內容和作用。

Ø BasePermission

系統權限(xian)(xian)的(de)基(ji)本表(biao)示單元(yuan)是(shi)BasePermission,Settings中維護了一個(ge)總的(de)權限(xian)(xian)映(ying)射(she)表(biao)mPermissions,所(suo)有的(de)權限(xian)(xian)都會添加到mPermissions列(lie)表(biao)中,其中key是(shi)權限(xian)(xian)的(de)名字,value是(shi)具體(ti)的(de)BasePermission實例。

[/frameworks/base/services/core/java/com/android/server/pm/Settings.java]

// Mapping from permission names to info about them.
final ArrayMap<String, BasePermission> mPermissions =  new ArrayMap<String, BasePermission>();

  我(wo)們(men)都知(zhi)道絕(jue)大部分權(quan)限(xian)(xian)已經在系統中(zhong)定義(yi)好,如READ_EXTERNAL_STORAGE讀(du)寫外部存儲權(quan)限(xian)(xian)、READ_PHONE_STATE讀(du)取手機狀態信息權(quan)限(xian)(xian)等,這(zhe)些權(quan)限(xian)(xian)的定義(yi)都在framework-res.apk中(zhong),在掃描framework-res.apk過(guo)程中(zhong)解(jie)析并添加到(dao)mPermissions映射表中(zhong)。系統權(quan)限(xian)(xian)的定義(yi):

[/frameworks/base/core/res/AndroidManifest.xml]

系統中(zhong)(zhong)(zhong)絕(jue)大部分的權限定義都在frameworks/base/services/core/res/AndroidManifest.xml中(zhong)(zhong)(zhong),最終會打(da)包進(jin)framework-res.apk中(zhong)(zhong)(zhong)并經(jing)過解析(xi)保(bao)存到Settings的mPermissions映(ying)射(she)表(biao)中(zhong)(zhong)(zhong)。

Ø PackageParser.Permission

PackageParser.Permission在上(shang)面(mian)分析(xi)PackageParser解析(xi)apk過(guo)程中有提及過(guo),解析(xi)apk的AndroidManifest.xml文件中的標簽后得到的權限表示。

PackageParser.Permission中包含(han)一個對應的PermissionInfo。

Ø PermissionInfo

權限信息的表示,其中包含權限等(deng)級的定義(NORMAL, DANGER, SIGNERATURE),另外實(shi)現了序列(lie)化(hua),用(yong)戶(hu)于進程間通信。每個BasePermission實(shi)例(li)(li)中包含一(yi)個PermissionInfo的實(shi)例(li)(li)。

以上三個(ge)(ge)類(lei)結構是系統(tong)權限(xian)部(bu)分的定義,下面(mian)四個(ge)(ge)類(lei)結構和(he)pkg強相關(guan),表示pkg的權限(xian)狀態。

Ø GrantedPermissions

表示一個pkg已經(jing)賦予的(de)權限(xian),類里面(mian)定義了(le)一個字符串列表grantedPermissions保存pkg已經(jing)被賦予的(de)所有權限(xian)。

[/frameworks/base/services/core/java/com/android/server/pm/GrantedPermissions.java]

class GrantedPermissions {
    int pkgFlags; 
    ArraySet<String> grantedPermissions = new ArraySet<String>();

Ø PackageSettingBase

PackageSettingBase繼承了GrantedPermissions類并(bing)添加更多和(he) pkg相關的(de)(de)(de)信(xin)息(xi),是(shi)一個pkg信(xin)息(xi)的(de)(de)(de)基本表(biao)示(shi)類。PackageSettingBase保存(cun)為了如pkg的(de)(de)(de)codePath, resourcePath, signature等信(xin)息(xi),同時PackageSettingBase是(shi)GrantedPermissions的(de)(de)(de)子類,因為也包含(han)了pkg被賦予的(de)(de)(de)權限(xian)列表(biao)。

Ø PackageSetting

PackageSetting繼承了PackageSettingBase類,并新增如PackageParser.Package和SharedUserSetting。那么以(yi)后(hou)只要獲(huo)得一個pkg的(de)PackageSetting實(shi)例,就(jiu)(jiu)可以(yi)獲(huo)得對應的(de)SharedUserSetting實(shi)例,通過這個SharedUserSetting實(shi)例來獲(huo)得與其sharedUser的(de)其他(ta)pkg信息。同時PackageSetting是GrantedPermissions的(de)子類,那么也就(jiu)(jiu)意(yi)味著只要拿到pkg的(de)PackageSetting實(shi)例就(jiu)(jiu)可以(yi)知道pkg已經被賦(fu)予了哪些權限(xian)。

Ø SharedUserSetting

SharedUserSetting繼(ji)承(cheng)了(le)(le)GrantedPermissions,類里(li)面保存了(le)(le)一個(ge)packages的列表(biao),表(biao)示這個(ge)列表(biao)中的所(suo)有(you)應(ying)用共享(xiang)該uid。同時(shi)共享(xiang)這個(ge)uid所(suo)賦(fu)予(yu)的所(suo)有(you)權限(xian)。

權限管理
我(wo)們(men)(men)知道(dao)在pms構造(zao)方法(fa)(fa)中(zhong)掃描apk后,創建對(dui)應的(de)PackageSetting實例(li)(li)并(bing)賦予(yu)給pkg的(de)mExtras,以后我(wo)們(men)(men)就可以通過pkg.mExtras獲得相(xiang)應的(de)PackageSetting實例(li)(li)。一(yi)開始掃描過程中(zhong),PackageSetting實例(li)(li)中(zhong)保存的(de)grantedPermissions列表為空,權(quan)(quan)限的(de)賦予(yu)會(hui)在pms構造(zao)方法(fa)(fa)的(de)結束部分,通過調用updatePermissionsLPw方法(fa)(fa)遍歷所有已經安裝的(de)pkg,一(yi)個一(yi)個的(de)根據其請求的(de)權(quan)(quan)限來確定(ding)是否賦予(yu)。

首先來看看updatePermissionsLPw方法:

[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

    private void updatePermissionsLPw(String changingPkg,PackageParser.Package pkgInfo, int flags) {
        // Make sure there are no dangling permission trees.
        // 更新permission trees列表,去除無效的permission tree
        // Make sure all dynamic permissions have been assigned to a package,
        // and make sure there are no dangling permissions.
        // 更新permission列表,去除無效無主的permission定義
        if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
            for (PackageParser.Package pkg : mPackages.values()) {
                if (pkg != pkgInfo) {
                    grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
                            changingPkg);
                }
            }
        }
        if (pkgInfo != null) {
            grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
        }
    }

updatePermissionsLPw方法(fa)中(zhong)主要做(zuo)兩個(ge)事情(qing),檢查無效的(de)(de)permissiontree和(he)permission定義,另(ling)外一個(ge)就(jiu)是根據傳入的(de)(de)flags是否帶(dai)有UPDATE_PERMISSIONS_ALL來遍歷mPackages包列表來更新所有安裝包的(de)(de)權限信息。重點(dian)分析(xi)grantPermissionsLPw方法(fa)。

[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

 
     private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace, String packageOfInterest) {        
final PackageSetting ps = (PackageSetting) pkg.mExtras; 
        final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
              ArraySet<String> origPermissions = gp.grantedPermissions;
        boolean changedPermission = false;  
        /* 獲得解析pkg中請求的權限數量,循環一個一個去決定是否分配給該應用或者sharedUserId */     
        final int N = pkg.requestedPermissions.size();
        for (int i=0; i<N; i++) {
            final String name = pkg.requestedPermissions.get(i);
            final boolean required = pkg.requestedPermissionsRequired.get(i);
            final BasePermission bp = mSettings.mPermissions.get(name);
            /* 檢查應用申請的這個權限是否存在有效,如果無效,忽略 */
            if (bp == null || bp.packageSetting == null) {
                if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
                    Slog.w(TAG, "Unknown permission " + name  + " in package " + pkg.packageName);
                }
                continue;
            }
            final String perm = bp.name;
            boolean allowed;
            boolean allowedSig = false;
            final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
            if (level == PermissionInfo.PROTECTION_NORMAL || level == PermissionInfo.PROTECTION_DANGEROUS) {
                /* 權限等級為NORMAL和DANGER的權限,只要申請就分配 */
                allowed = (required || origPermissions.contains(perm)
                        || (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
            } else if (bp.packageSetting == null) {
                /* 無頭的權限,直接拒絕 */
                allowed = false;
            } else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
/* 權限等級要求簽名的,檢查該pkg簽名是否和platform apk簽名一致,一致則返回 */
                allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
                if (allowed) { allowedSig = true; }
            } else {
                allowed = false;
            }
            if (allowed) {                
                if (allowed) {
                    if (!gp.grantedPermissions.contains(perm)) {
                        /* 權限允許賦予后,如果pkg已獲得權限列表中沒有,則添加 */
                        changedPermission = true;
                        gp.grantedPermissions.add(perm);
                        gp.gids = appendInts(gp.gids, bp.gids);
                    } 
                } 
            } else {
            /* 權限不允許 */
                if (gp.grantedPermissions.remove(perm)) {
/* 如果已獲取權限列表中存在去除的該權限,說明apk版本有變化 */
                    changedPermission = true;
                    gp.gids = removeInts(gp.gids, bp.gids);
                }
            }
        }
   } 
 

grantPermissionsLPw方(fang)法中(zhong)實(shi)現了5.1權(quan)限(xian)(xian)(xian)賦予的(de)流(liu)程(cheng)(cheng)。主要(yao)流(liu)程(cheng)(cheng)首(shou)先獲(huo)得(de)pkg的(de)PackageSettings實(shi)例(li),上面我們知道pkg的(de)PackageSettings實(shi)例(li)中(zhong)包含了應用(yong)已經(jing)獲(huo)得(de)的(de)權(quan)限(xian)(xian)(xian)列(lie)表grantedPermissions。第一次開機(ji)掃描應用(yong)的(de)過程(cheng)(cheng)中(zhong),這(zhe)個列(lie)表為(wei)空(kong)。通(tong)過遍歷包解析(xi)后(hou)得(de)到的(de)requestPermissions列(lie)表的(de)權(quan)限(xian)(xian)(xian)的(de)等級來判斷(duan)是否授(shou)權(quan),如(ru)果請(qing)求的(de)權(quan)限(xian)(xian)(xian)授(shou)權(quan)成功(gong)后(hou),就會保(bao)存(cun)進(jin)入grantedPermissions列(lie)表中(zhong)。

grantedPermissions列(lie)表(biao)會根(gen)據(ju)應(ying)用(yong)的更(geng)新而更(geng)新。

權限管理的基本流程如上。

鑒權過程
一(yi)般(ban)客戶端調用checkPermission方法鑒權的流程如下:

①Context.java--->public int checkPermission(String permission, int pid, int uid)

②ActivityManagerService.java--->public int checkPermission(String permission, int pid, int uid)

③ActivityManagerService.java---> checkComponentPermission

④ActivityManager.java--->checkComponentPermission

Root用戶(uid=0)和(he)System用戶(uid=1000)直接鑒權通過。

⑤PackageManagerService.java--->checkUidPermission

查看pms的checkUidPermission方法:

[/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java]

    @Override
    public int checkUidPermission(String permName, int uid) {
        synchronized (mPackages) {
            Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid));
            if (obj != null) {
                GrantedPermissions gp = (GrantedPermissions)obj;
                if (gp.grantedPermissions.contains(permName)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            } else {
                ArraySet<String> perms = mSystemPermissions.get(uid);
                if (perms != null && perms.contains(permName)) {
                    return PackageManager.PERMISSION_GRANTED;
                }
            }
        }
        return PackageManager.PERMISSION_DENIED;
    }

發現checkUidPermission方法中調用Settings的(de)getUserIdLPr獲得一個(ge)Object實例(li),這個(ge)Object實例(li)就是(shi)(shi)對應(ying)uid的(de)pkgSettings實例(li),里面(mian)包含grantedPermissions信息。最(zui)后(hou)查(cha)(cha)詢grantedPermissions列表中是(shi)(shi)否(fou)包含所要(yao)檢(jian)查(cha)(cha)的(de)權限(xian)即可判斷該(gai)uid是(shi)(shi)否(fou)具有(you)該(gai)權限(xian)。

繼續分(fen)析Settings的getUserIdLPr方(fang)法:

[/frameworks/base/services/core/java/com/android/server/pm/Settings.java]

  public Object getUserIdLPr(int uid) {
        if (uid >= Process.FIRST_APPLICATION_UID) {
            final int N = mUserIds.size();
            final int index = uid - Process.FIRST_APPLICATION_UID;
            return index < N ? mUserIds.get(index) : null;
        } else {
            return mOtherUserIds.get(uid);
        }
  }

這個方法首先判斷檢查(cha)的(de)uid是(shi)否是(shi)應用的(de)uid(10000以上),如果(guo)是(shi),通過uid來查(cha)詢mUserIds表來獲得對應uid的(de)pkgSettings實(shi)例(mUserIds就是(shi)uid和pkgSettings的(de)映射表)。通過進一步分析,mUserIds列表是(shi)在手機開機后(hou)讀(du)取packages.xml緩存生(sheng)成的(de)。

鑒權流程2:

① 根(gen)據PMS解析(xi)的申(shen)請權限數(shu)據,對應用添加gid

② 啟動應用進程(cheng)時,指定所有對應的(de)gid

舉例:android.permission.WRITE_EXTERNAL_STORAGE

① 應用在(zai)AndroidManifest.xml中申(shen)請android.permission.WRITE_EXTERNAL_STORAGE

② 安(an)裝(zhuang)后,PMS解析該(gai)應(ying)用(yong),并為該(gai)應(ying)用(yong)添(tian)加sdcard_rw的組ID。

③ 啟(qi)動該應用進程時,使(shi)用上面(mian)解析(xi)的gid。

文章來自個人專欄
文(wen)章 | 訂(ding)閱
0條評論
0 / 1000
請輸入你的評論
0
0