Android PackageManagerService流程詳細分析(四)之權限

接着上一節(三)的分析,看看上一節的PackageManagerService構造函數的代碼如:

public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) 
{
    // 前面省略...

    // 第二節討論過
    mInstaller = installer;

    synchronized (mInstallLock) {
    // writer
    synchronized (mPackages) {
    mHandlerThread.start();
    // 第三節討論過
    mHandler = new PackageHandler(mHandlerThread.getLooper());

    // 本節分析內容
    readPermissions();

    } 

    // 後面省略...
}

進入readPermissions函數,代碼如下:
這裏寫圖片描述

在機器裏面,指定路徑有這麼一些文件:
這裏寫圖片描述

下面進入解析函數(這是重點):

private void readPermissionsFromXml(File permFile) {
    FileReader permReader = null;
    try {
        permReader = new FileReader(permFile);
    } catch (FileNotFoundException e) {
        Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
        return;
    }

    try {
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(permReader);

        XmlUtils.beginDocument(parser, "permissions");

        while (true) {
            XmlUtils.nextElement(parser);
            if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
                break;
            }

            String name = parser.getName();
            if ("group".equals(name)) {
                String gidStr = parser.getAttributeValue(null, "gid");
                if (gidStr != null) {
                    int gid = Integer.parseInt(gidStr);
                    // 保存到mGlobalGids  
                    mGlobalGids = appendInt(mGlobalGids, gid);
                } else {
                    Slog.w(TAG, "<group> without gid at "
                            + parser.getPositionDescription());
                }

                XmlUtils.skipCurrentTag(parser);
                continue;
            // 定義了權限和組id(gid)的關係,該組擁有什麼權限 
            } else if ("permission".equals(name)) {
                String perm = parser.getAttributeValue(null, "name");
                if (perm == null) {
                    Slog.w(TAG, "<permission> without name at "
                            + parser.getPositionDescription());
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }
                perm = perm.intern();
                // 進一步解析,解析結果保存到 mSettings.mPermissions
                readPermission(parser, perm);
            // 哪一個uid都擁有什麼權限(把什麼權限賦予哪個uid)
            } else if ("assign-permission".equals(name)) {
                String perm = parser.getAttributeValue(null, "name");
                if (perm == null) {
                    Slog.w(TAG, "<assign-permission> without name at "
                            + parser.getPositionDescription());
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }
                String uidStr = parser.getAttributeValue(null, "uid");
                if (uidStr == null) {
                    Slog.w(TAG, "<assign-permission> without uid at "
                            + parser.getPositionDescription());
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }
                int uid = Process.getUidForName(uidStr);
                if (uid < 0) {
                    Slog.w(TAG, "<assign-permission> with unknown uid \""
                            + uidStr + "\" at "
                            + parser.getPositionDescription());
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                }
                perm = perm.intern();
                HashSet<String> perms = mSystemPermissions.get(uid);
                if (perms == null) {
                    perms = new HashSet<String>();
                    mSystemPermissions.put(uid, perms);
                }
                perms.add(perm);
                XmlUtils.skipCurrentTag(parser);
            // 系統共享庫 
            } else if ("library".equals(name)) {
                String lname = parser.getAttributeValue(null, "name");
                String lfile = parser.getAttributeValue(null, "file");
                if (lname == null) {
                    Slog.w(TAG, "<library> without name at "
                            + parser.getPositionDescription());
                } else if (lfile == null) {
                    Slog.w(TAG, "<library> without file at "
                            + parser.getPositionDescription());
                } else {
                    //Log.i(TAG, "Got library " + lname + " in " + lfile);
                    mSharedLibraries.put(lname, lfile);
                }
                XmlUtils.skipCurrentTag(parser);
                continue;
            // 系統特徵
            } else if ("feature".equals(name)) {
                String fname = parser.getAttributeValue(null, "name");
                if (fname == null) {
                    Slog.w(TAG, "<feature> without name at "
                            + parser.getPositionDescription());
                } else {
                    //Log.i(TAG, "Got feature " + fname);
                    FeatureInfo fi = new FeatureInfo();
                    fi.name = fname;
                    mAvailableFeatures.put(fname, fi);
                }
                XmlUtils.skipCurrentTag(parser);
                continue;

            } else {
                XmlUtils.skipCurrentTag(parser);
                continue;
            }

        }
        permReader.close();
    } catch (XmlPullParserException e) {
        Slog.w(TAG, "Got execption parsing permissions.", e);
    } catch (IOException e) {
        Slog.w(TAG, "Got execption parsing permissions.", e);
    }
}

函數readPermission()代碼如下:

void readPermission(XmlPullParser parser, String name)
        throws IOException, XmlPullParserException {

    name = name.intern();

    BasePermission bp = mSettings.mPermissions.get(name);
    if (bp == null) {
        bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);
        mSettings.mPermissions.put(name, bp);
    }
    int outerDepth = parser.getDepth();
    int type;
    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
           && (type != XmlPullParser.END_TAG
                   || parser.getDepth() > outerDepth)) {
        if (type == XmlPullParser.END_TAG
                || type == XmlPullParser.TEXT) {
            continue;
        }

        String tagName = parser.getName();
        if ("group".equals(tagName)) {
            String gidStr = parser.getAttributeValue(null, "gid");
            if (gidStr != null) {
                int gid = Process.getGidForName(gidStr);
                bp.gids = appendInt(bp.gids, gid);
            } else {
                Slog.w(TAG, "<group> without gid at "
                        + parser.getPositionDescription());
            }
        }
        XmlUtils.skipCurrentTag(parser);
    }
}

總結:
解析/system/etc/permission下xml文件(framework/base/data/etc/),包括platform.xml和系統支持的各種硬件模塊的feature主要工作:
(1) 建立底層user ids和group ids同上層permissions之間的映射;可以指定一個權限與幾個組ID對應。當一個APK被授予這個權限時,它也同時屬於這幾個組;
(2) 給一些底層用戶分配權限,如給shell授予各種permission權限;把一個權限賦予一個UID,當進程使用這個UID運行時,就具備了這個權限;
(3) permission,讀取permission name添加到mSettings.mPermissions,讀取gid添加到mSettings.mPermissions;
(4) assign-permission,設置相應uid所具有的權限,保存到mSystemPermissions;
(5) library,系統增加的一些應用需要link的擴展jar庫,jar包保存到mSharedLibraries;
(6) feature,系統每增加一個硬件,都要添加相應的feature,硬件相關信息保存到mAvailableFeatures。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章