Android  安装一个 APK 的时候首先会解析 APK ,这里要做很多事情,其中一个事情就是解析 Manifest.xml 文件,并将所有 APK Manifest 封装到各种对象中并保存在内存当中 解析 Manifest 的类是非常重要的,该类就是 frameworks\base\core\java\android\content\pm\PackageParser PackageManagerService 会调用 PackageParser.parserPackage 方法来解析 APK 清单,下面开始分析 PackageParser 的实现: PackageParser 是使用的 XMLPullParser 工具来对 XML 进行解析的,然后分别通过 android.content.pm 下各种 xxxInfo类 来进行封装:   public Package parsePackage(File sourceFile, String destCodePath,
            DisplayMetrics metrics, int flags) {
     //最后要跑出的解析错误信息
        mParseError = PackageManager.INSTALL_SUCCEEDED;
        //获得要解析的文件的路径
        mArchiveSourcePath = sourceFile.getPath();
       
        //如果要解析的不是文件类型就跳过并且返回该方法
        if (!sourceFile.isFile()) {
            Log.w(TAG, "Skipping dir: " + mArchiveSourcePath);
            //更新错误信息
            mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
            return null;
        }
       
        //如果文件不是以.apk结尾并且flag没有确定一定是APK,那么也返回
        if (!isPackageFilename(sourceFile.getName())
                && (flags&PARSE_MUST_BE_APK) != 0) {
            if ((flags&PARSE_IS_SYSTEM) == 0) {
                // We expect to have non-.apk files in the system dir,
                // so don't warn about them.
                Log.w(TAG, "Skipping non-package file: " + mArchiveSourcePath);
            }
            //更新错误信息
            mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
            return null;
        }
        if ((flags&PARSE_CHATTY) != 0 && Config.LOGD) Log.d(
            TAG, "Scanning package: " + mArchiveSourcePath);
        XmlResourceParser parser = null;
        AssetManager assmgr = null;
        boolean assetError = true;
        try {
            assmgr = new AssetManager();
           
            //将一个文件添加到AssetManager中并返回一个唯一标识
            int cookie = assmgr.addAssetPath(mArchiveSourcePath);
            if(cookie != 0) {
             //通过标识去AssetManager中找到标识对应资源中的Manifest清单文件,并返回一个XML的解析器
                parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
                //走到这里证明一切顺利
                assetError = false;
            } else {
                Log.w(TAG, "Failed adding asset path:"+mArchiveSourcePath);
            }
        } catch (Exception e) {
            Log.w(TAG, "Unable to read AndroidManifest.xml of "
                    + mArchiveSourcePath, e);
        }
        if(assetError) {
            if (assmgr != null) assmgr.close();
            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
            return null;
        }
        String[] errorText = new String[1];
        Package pkg = null;
        Exception errorException = null;
        try {
            // XXXX todo: need to figure out correct configuration.
            Resources res = new Resources(assmgr, metrics, null);
            //这个是真正在解析的package的方法,是private method
            pkg = parsePackage(res, parser, flags, errorText);
        } catch (Exception e) {
            errorException = e;
            mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
        }

        if (pkg == null) {
            if (errorException != null) {
                Log.w(TAG, mArchiveSourcePath, errorException);
            } else {
                Log.w(TAG, mArchiveSourcePath + " (at "
                        + parser.getPositionDescription()
                        + "): " + errorText[0]);
            }
            parser.close();
            assmgr.close();
            if (mParseError == PackageManager.INSTALL_SUCCEEDED) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
            }
            return null;
        }
parserPackage调用了重载的另外一个parserPackage   private Package parsePackage(
        Resources res, XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
        AttributeSet attrs = parser;
        //每次调用这个方法时候清空这些变量
        mParseInstrumentationArgs = null;
        mParseActivityArgs = null;
        mParseServiceArgs = null;
        mParseProviderArgs = null;
       
        //这里调用这个方法获得包名
        String pkgName = parsePackageName(parser, attrs, flags, outError);
        if (pkgName == null) {
            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
            return null;
        }
        int type;
        final Package pkg = new Package(pkgName);
        boolean foundApp = false;
       
        //从资源里获得AndroidManifest的数组
        TypedArray sa = res.obtainAttributes(attrs,
                com.android.internal.R.styleable.AndroidManifest);
       
        //继续挖掘出版本号
        pkg.mVersionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
       
        //获取版本名
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
        if (pkg.mVersionName != null) {
            pkg.mVersionName = pkg.mVersionName.intern();
        }
       
        //获得sharedUserId
        String str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
        if (str != null && str.length() > 0) {
         //验证包名是否符合规则
            String nameError = validateName(str, true);
            if (nameError != null && !"android".equals(pkgName)) {
                outError[0] = " specifies bad sharedUserId name \""
                    + str + "\": " + nameError;
                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
                return null;
            }
            pkg.mSharedUserId = str.intern();
            pkg.mSharedUserLabel = sa.getResourceId(
                    com.android.internal.R.styleable.AndroidManifest_sharedUserLabel, 0);
        }
        sa.recycle();
        //安装的位置
        pkg.installLocation = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_installLocation,
                PARSE_DEFAULT_INSTALL_LOCATION);
        // Resource boolean are -1, so 1 means we don't know the value.
        int supportsSmallScreens = 1;
        int supportsNormalScreens = 1;
        int supportsLargeScreens = 1;
        int resizeable = 1;
        int anyDensity = 1;
       
        int outerDepth = parser.getDepth();
       
        //关键时刻到了,真正的开始解析了
        while ((type=parser.next()) != parser.END_DOCUMENT
               && (type != parser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == parser.END_TAG || type == parser.TEXT) {
                continue;
            }
            String tagName = parser.getName();
            if (tagName.equals("application")) {
                if (foundApp) {
                    if (RIGID_PARSER) {
                        outError[0] = " has more than one ";
                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                        return null;
                    } else {
                        Log.w(TAG, " has more than one ");
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                }
                foundApp = true;
                if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
                    return null;
                }
            } else if (tagName.equals("permission-group")) {
                if (parsePermissionGroup(pkg, res, parser, attrs, outError) == null) {
                    return null;
                }
            } else if (tagName.equals("permission")) {
                if (parsePermission(pkg, res, parser, attrs, outError) == null) {
                    return null;
                }
            } else if (tagName.equals("permission-tree")) {
                if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
                    return null;
                }
            } else if (tagName.equals("uses-permission")) {
                sa = res.obtainAttributes(attrs,
                        com.android.internal.R.styleable.AndroidManifestUsesPermission);
                // Note: don't allow this value to be a reference to a resource
                // that may change.
                String name = sa.getNonResourceString(
                        com.android.internal.R.styleable.AndroidManifestUsesPermission_name);
                sa.recycle();               ...................................................
              ...................................................
              ...................................................篇幅有限
  这里分别把每种不同的element用不同的小方法去解析,他们的调用顺序是:    

更多相关文章

  1. android 资源文件命名规则 drawable mipmap一样的
  2. Android学习笔记Android线程模型解析
  3. 什么是aidl?Android(安卓)AIDL详解
  4. Android内核驱动——电源管理
  5. android 开发 文件读写应用案例分析
  6. ANDROID开机动画bootanimation.zip的详细制作方法
  7. js调用android本地代码失败 兼容问题
  8. android判断文件类型是否为音频文件
  9. NPM 和webpack 的基础使用

随机推荐

  1. Citrix相关问题
  2. JVM性能调优实战:让你的IntelliJ Idea纵享
  3. Android屏幕适配-资源文件夹命名与匹配规
  4. 半年北漂生活,时间与人生(上)
  5. 什么,3行Python代码就能获取海量数据?
  6. 2020 年,我的年终总结!时间与人生(下)
  7. 第一天学习C语言
  8. 华为交换机console口设置密码及状态查看
  9. 自学第五十二天
  10. 华为交换机开启Telnet服务及修改端口