Android启动过程中应用的安装过程分析 (二)

回到PMS类的构造方法,前一篇文章已经把上一次的应用程序安装信息恢复完成了.接下来会调用PMS的scanDirLI方法来安装保存在各个目录的apk

3.1 PackageManagerService.scanDirLI
    private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
        final File[] files = dir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + dir);
            return;
        }

        if (DEBUG_PACKAGE_SCANNING) {
            Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }

        Log.d(TAG, "start scanDirLI:"+dir);
        // use multi thread to speed up scanning
        int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6);
        Log.d(TAG, "max thread:" + iMultitaskNum);
        final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer(
                MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null;

        for (File file : files) {
            final boolean isPackage = (isApkFile(file) || file.isDirectory())
                    && !PackageInstallerService.isStageName(file.getName());
            if (!isPackage) {
                // Ignore entries which are not packages
                continue;
            }
           if (RegionalizationEnvironment.isSupported()) {
             if (RegionalizationEnvironment.isExcludedApp(file.getName())) {
               Slog.d(TAG, "Regionalization Excluded:" + file.getName());
               continue;
            }
           }

            final File ref_file = file;
            final int ref_parseFlags = parseFlags;
            final int ref_scanFlags = scanFlags;
            final long ref_currentTime = currentTime;
            Runnable scanTask = new Runnable() {
                public void run() {
                    try {
                        scanPackageTracedLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK,
                                ref_scanFlags, ref_currentTime, null);
                    } catch (PackageManagerException e) {
                        Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage());

                        // Delete invalid userdata apps
                        if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
                                e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
                            logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file);
                            removeCodePathLI(ref_file);
                        }
                    }
                }
            };

            if (dealer != null)
                dealer.addTask(scanTask);
            else
                scanTask.run();
        }

        if (dealer != null)
            dealer.waitAll();
        Log.d(TAG, "end scanDirLI:"+dir);
    }
  • 这块代码很好理解,在文件夹内遍历apk类型的文件,调用scanPackageTracedLI方法解析apk.这里有用到多线程的方式,具体分析见http://www.jianshu.com/p/30b25d4f0d16
3.2 PackageManagerService.scanPackageLI
    private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
            long currentTime, UserHandle user) throws PackageManagerException {
        if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
        PackageParser pp = new PackageParser(mContext);
        pp.setSeparateProcesses(mSeparateProcesses);
        pp.setOnlyCoreApps(mOnlyCore);
        pp.setOnlyPowerOffAlarmApps(mOnlyPowerOffAlarm);
        pp.setDisplayMetrics(mMetrics);

        if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
            parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
        }

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
        final PackageParser.Package pkg;
        try {
            pkg = pp.parsePackage(scanFile, parseFlags);
        } catch (PackageParserException e) {
            throw PackageManagerException.from(e);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);
    }
  • PackageParser pp = new PackageParser(mContext);创建一个PackageParser对象用于解析apk.
  • pkg = pp.parsePackage(scanFile, parseFlags);返回一个类型为package类型的pkg对象.
  • 调用另一个同名的重载版本的成员函数scanPackageLI(参数不同).
3.3 PackageParser.parsePackage
    public Package parsePackage(File packageFile, int flags) throws PackageParserException {
        if (packageFile.isDirectory()) {
            return parseClusterPackage(packageFile, flags);
        } else {
            return parseMonolithicPackage(packageFile, flags);
        }
    }
  • 判断是single apkfile 还是apk目录,分别用不同的解析方式.
3.4 PackageParser.parseMonolithicPackage
    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
        // When mOnlyPowerOffAlarmApps is true, only parse power off alarm packages
        if (mOnlyPowerOffAlarmApps) {
            if (!isPowerOffAlarmPackage(lite.packageName)) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                   "Not a powerOffAlarmApp: " + apkFile);
            }
        }

        if (!mOnlyPowerOffAlarmApps && mOnlyCoreApps) {
            if (!lite.coreApp) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Not a coreApp: " + apkFile);
            }
        }

        final AssetManager assets = new AssetManager();
        try {
            final Package pkg = parseBaseApk(apkFile, assets, flags);
            pkg.setCodePath(apkFile.getAbsolutePath());
            pkg.setUse32bitAbi(lite.use32bitAbi);
            return pkg;
        } finally {
            IoUtils.closeQuietly(assets);
        }
    }
  • parseMonolithicPackage最终会调用parseBaseApk方法做解析.
3.5 PackageParser.parseBaseApk
    private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();

        String volumeUuid = null;
        if (apkPath.startsWith(MNT_EXPAND)) {
            final int end = apkPath.indexOf('/', MNT_EXPAND.length());
            volumeUuid = apkPath.substring(MNT_EXPAND.length(), end);
        }

        mParseError = PackageManager.INSTALL_SUCCEEDED;
        mArchiveSourcePath = apkFile.getAbsolutePath();

        if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);

        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);

        Resources res = null;
        XmlResourceParser parser = null;
        try {
            res = new Resources(assets, mMetrics, null);
            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                    Build.VERSION.RESOURCES_SDK_INT);
            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

            final String[] outError = new String[1];
            final Package pkg = parseBaseApk(res, parser, flags, outError);
            if (pkg == null) {
                throw new PackageParserException(mParseError,
                        apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
            }

            pkg.setVolumeUuid(volumeUuid);
            pkg.setApplicationVolumeUuid(volumeUuid);
            pkg.setBaseCodePath(apkPath);
            pkg.setSignatures(null);

            return pkg;

        } catch (PackageParserException e) {
            throw e;
        } catch (Exception e) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                    "Failed to read manifest from " + apkPath, e);
        } finally {
            IoUtils.closeQuietly(parser);
        }
    }
  • parser = assets.openXmlResourceParser 打开xml类型文件manifest.xml,获得XmlResourceParser类型对象parser
  • final Package pkg = parseBaseApk(res, parser, flags, outError); 这里调用同名的重载方法parseBaseApk,真正开始解析manifest文件.
3.6 PackageParser.parseBaseApk
 private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
        final String splitName;
        final String pkgName;

        try {
            Pair packageSplit = parsePackageSplitNames(parser, parser);
            pkgName = packageSplit.first;
            splitName = packageSplit.second;

            if (!TextUtils.isEmpty(splitName)) {
                outError[0] = "Expected base APK, but found split " + splitName;
                mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
                return null;
            }
        } catch (PackageParserException e) {
            mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
            return null;
        }

        final Package pkg = new Package(pkgName);

        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifest);

        pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
        pkg.baseRevisionCode = sa.getInteger(
                com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
        pkg.mVersionName = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_versionName, 0);
        if (pkg.mVersionName != null) {
            pkg.mVersionName = pkg.mVersionName.intern();
        }

        pkg.coreApp = parser.getAttributeBooleanValue(null, "coreApp", false);

        sa.recycle();

        return parseBaseApkCommon(pkg, null, res, parser, flags, outError);
    }
  • pkgName = packageSplit.first;获取应用程序的包名,final Package pkg = new Package(pkgName);创建一个以包名为参数的pkg对象,用户保存后面解析的配置信息.
  • mVersionCode,mVersionName是应用程序的版本号,版本名等信息.
  • 最后调用parseBaseApkCommon方法继续解析manifest.xml文件.
3.7 PackageParser.parseBaseApkCommon
   private Package parseBaseApkCommon(Package pkg, Set acceptedTags, Resources res,
            XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
            IOException {
         .....
        TypedArray sa = res.obtainAttributes(parser,
                com.android.internal.R.styleable.AndroidManifest);

        String str = sa.getNonConfigurationString(
                com.android.internal.R.styleable.AndroidManifest_sharedUserId, 0);
        if (str != null && str.length() > 0) {
            String nameError = validateName(str, true, false);
            if (nameError != null && !"android".equals(pkg.packageName)) {
                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);
        }
        .....
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
      ......
 if (tagName.equals(TAG_APPLICATION)) {
                if (foundApp) {
                    if (RIGID_PARSER) {
                        outError[0] = " has more than one ";
                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                        return null;
                    } else {
                        Slog.w(TAG, " has more than one ");
                        XmlUtils.skipCurrentTag(parser);
                        continue;
                    }
                }

                foundApp = true;
                if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
                    return null;
                }
      ......
      else if (tagName.equals(TAG_USES_PERMISSION)) {
                if (!parseUsesPermission(pkg, res, parser)) {
                    return null;
                }
     .....
}
  • pkg.mSharedUserId = str.intern();解析manifest中的共享userid信息
  • while循环中解析了application和uses-permission标签,一个uses-permission标签对应一个资源访问权限(一个资源访问权限对应这一个Linux用户组Id)
  • 每一个manifest都必须有一个application标签,用来描述应用程序四大组件的信息,方法是parseBaseApplication(pkg, res, parser, flags, outError).
3.8 PackageParser.parseBaseApplication
private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
......
final int innerDepth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }

            String tagName = parser.getName();
            if (tagName.equals("activity")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, false,
                        owner.baseHardwareAccelerated);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);

            } else if (tagName.equals("receiver")) {
                Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.receivers.add(a);

            } else if (tagName.equals("service")) {
                Service s = parseService(owner, res, parser, flags, outError);
                if (s == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.services.add(s);

            } else if (tagName.equals("provider")) {
                Provider p = parseProvider(owner, res, parser, flags, outError);
                if (p == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.providers.add(p);

            } else if (tagName.equals("activity-alias")) {
                Activity a = parseActivityAlias(owner, res, parser, flags, outError);
                if (a == null) {
                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                    return false;
                }

                owner.activities.add(a);
       ......
}
  • 在manifest.xml中,分别使用activity,recevier,service和provider标签来描述四大组件.分别把解析得到的信息保存在,以owner描述的package对象的activities,receivers之类的动态数组中.
  • 至此算是完成一个应用程序的解析,接着PMS会调用另一个重载版本的成员函数scanPackageLI,以便可以获得前面解析得到的应用信息,以及为这个应用程序分配Linux用户ID.
3.9 PackageParser.scanPackageLI
    private PackageParser.Package scanPackageLI(PackageParser.Package pkg, File scanFile,
            final int policyFlags, int scanFlags, long currentTime, UserHandle user)
            throws PackageManagerException {
        // If the package has children and this is the first dive in the function
        // we scan the package with the SCAN_CHECK_ONLY flag set to see whether all
        // packages (parent and children) would be successfully scanned before the
        // actual scan since scanning mutates internal state and we want to atomically
        // install the package and its children.
        if ((scanFlags & SCAN_CHECK_ONLY) == 0) {
            if (pkg.childPackages != null && pkg.childPackages.size() > 0) {
                scanFlags |= SCAN_CHECK_ONLY;
            }
        } else {
            scanFlags &= ~SCAN_CHECK_ONLY;
        }

        // Scan the parent
        PackageParser.Package scannedPkg = scanPackageInternalLI(pkg, scanFile, policyFlags,
                scanFlags, currentTime, user);

        // Scan the children
        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
        for (int i = 0; i < childCount; i++) {
            PackageParser.Package childPackage = pkg.childPackages.get(i);
            scanPackageInternalLI(childPackage, scanFile, policyFlags, scanFlags,
                    currentTime, user);
        }


        if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
            return scanPackageLI(pkg, scanFile, policyFlags, scanFlags, currentTime, user);
        }

        return scannedPkg;
    }
  • single apk直接调用scanPackageInternalLI进行apk解析,接着又会调用第三个重载方法scanPackageLI,最后调用到scanPackageDirtyLI.

你可能感兴趣的:(Android启动过程中应用的安装过程分析 (二))