Android 中PackageManagerService源代码分析

来源:互联网 发布:linux语言包大全 编辑:程序博客网 时间:2024/06/07 15:23

写了一个通过PackageManager获取手机上所有已安装app的信息Demo,欢迎下载收藏!
http://download.csdn.net/download/m0_37094131/10033582

通过上一篇博客中,我们可以了解到系统启动之后会注册各种系统服务,其中有一个就是PackageManagerService(简称PMS)。PMS启动后,会扫描系统中已安装的apk目录。

  • 系统App的安装目录为 /system/app
  • 第三方应用的目录为 /data/app

PMS的作用:
PMS会解析apk包下的AndroidManifest.xml文件得到App的相关信息,而每一个AndroidManifest.xml文件下的< application>节点下又包含了Activity、Service等组件的注册信息,当PMS扫描并且解析完这些信息后就构建了整个apk的信息树。
信息树

好了,大致讲啦一些PMS的作用,那么现在就开始来分析一下,该类的源代码吧,分析一下,它到底是如何完成它的工作的(解析已安装apk信息)!

第一步:先看看该类(PackageManagerService)的构造函数
(这里先说一句,我之前是想在AndroidStudio中看该类的源代码的,无奈的是,看到的是红色的字,ctrl+鼠标左键点击不进去,所以后来只能通过导出sdk中的源代码目录,放到Source Insight 软件中看了)

开始分析:

 public static PackageManagerService main(Context context, Installer installer,            boolean factoryTest, boolean onlyCore) {        // Self-check for initial settings.        PackageManagerServiceCompilerMapping.checkProperties();        PackageManagerService m = new PackageManagerService(context, installer,                factoryTest, onlyCore);        m.enableSystemUserPackages();        ServiceManager.addService("package", m);        return m;    }

分析该类中的main函数,得知是去调用构造方法!

   public PackageManagerService(Context context, Installer installer,            boolean factoryTest, boolean onlyCore) {        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,                SystemClock.uptimeMillis());        if (mSdkVersion <= 0) {            Slog.w(TAG, "**** ro.build.version.sdk not set!");        }        mContext = context;        mFactoryTest = factoryTest;        mOnlyCore = onlyCore;        mMetrics = new DisplayMetrics();        mSettings = new Settings(mPackages);        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);        String separateProcesses = SystemProperties.get("debug.separate_processes");        if (separateProcesses != null && separateProcesses.length() > 0) {            if ("*".equals(separateProcesses)) {                mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;                mSeparateProcesses = null;                Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");            } else {                mDefParseFlags = 0;                mSeparateProcesses = separateProcesses.split(",");                Slog.w(TAG, "Running with debug.separate_processes: "                        + separateProcesses);            }        } else {            mDefParseFlags = 0;            mSeparateProcesses = null;        }        mInstaller = installer;        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,                "*dexopt*");        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());        mOnPermissionChangeListeners = new OnPermissionChangeListeners(                FgThread.get().getLooper());

其实该类的构造方法中的代码数量过多,所以我只选取部分代码进行发布,读者有兴趣可以自行去看看完整的源码。


 File frameworkDir = new File(Environment.getRootDirectory(), "framework");            final VersionInfo ver = mSettings.getInternalVersion();            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);

这段代码中第一行写的是,加载FrameWork资源。


// Collected privileged system packages.            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");            scanDirTracedLI(privilegedAppDir, mDefParseFlags                    | PackageParser.PARSE_IS_SYSTEM                    | PackageParser.PARSE_IS_SYSTEM_DIR                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);// Collect ordinary system packages.            final File systemAppDir = new File(Environment.getRootDirectory(), "app");            scanDirTracedLI(systemAppDir, mDefParseFlags                    | PackageParser.PARSE_IS_SYSTEM                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);// Collect all vendor packages.            File vendorAppDir = new File("/vendor/app");            try {                vendorAppDir = vendorAppDir.getCanonicalFile();            } catch (IOException e) {                // failed to look up canonical path, continue with original one            }            scanDirTracedLI(vendorAppDir, mDefParseFlags                    | PackageParser.PARSE_IS_SYSTEM                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);// Collect all OEM packages.            final File oemAppDir = new File(Environment.getOemDirectory(), "app");            scanDirTracedLI(oemAppDir, mDefParseFlags                    | PackageParser.PARSE_IS_SYSTEM                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

该段代码写的是去扫描不同文件夹下的目录,去scan其中的apk文件!,以上都是和系统核心应用有关的!


            // Remove any shared userIDs that have no associated packages            mSettings.pruneSharedUsersLPw();            //若不是系统核心应用            if (!mOnlyCore) {                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,                        SystemClock.uptimeMillis());                        //去跟踪扫描第三方app安装的目录                scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);                scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags                        | PackageParser.PARSE_FORWARD_LOCK,                        scanFlags | SCAN_REQUIRE_KNOWN, 0);                scanDirLI(mEphemeralInstallDir, mDefParseFlags                        | PackageParser.PARSE_IS_EPHEMERAL,                        scanFlags | SCAN_REQUIRE_KNOWN, 0);                /**                 * Remove disable package settings for any updated system                 * apps that were removed via an OTA. If they're not a                 * previously-updated app, remove them completely.                 * Otherwise, just revoke their system-level permissions.                 */

该段代码中就写到了去扫描第三方app安装的目录文件夹。其实细心的读者可能都已经发现了,不管是系统核心应用文件夹,还是第三方app的文件夹,都是通过scanDirTracedLI()该函数去扫描的,现在进入到该方法中,去查看该方法的逻辑!

 private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) {        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir");        try {            scanDirLI(dir, parseFlags, scanFlags, currentTime);        } finally {            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);        }    }

其实该方法内部调用的是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));        }        for (File file : files) {            final boolean isPackage = (isApkFile(file) || file.isDirectory())                    && !PackageInstallerService.isStageName(file.getName());            if (!isPackage) {                // Ignore entries which are not packages                continue;            }            try {                scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,                        scanFlags, currentTime, null);            } catch (PackageManagerException e) {                Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());                // Delete invalid userdata apps                if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&                        e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {                    logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);                    removeCodePathLI(file);                }            }        }    }

该方法中,会去判断该文件夹目录下,是否存在Apk文件,若不存在,则继续寻找,若存在Apk文件,则调用scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
该函数去扫描Apk文件中的Package。那么去看下该方法。

/**     *  Traces a package scan.     *  @see #scanPackageLI(File, int, int, long, UserHandle)     */    private PackageParser.Package scanPackageTracedLI(File scanFile, final int parseFlags,            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage");        try {            return scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);        } finally {            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);        }    }

该方法和之前的scanDirTracedLI方法类似,该方法内部实际上调用的是scanPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);该方法。

    /**     *  Scans a package and returns the newly parsed package.     *  Returns {@code null} in case of errors and the error code is stored in mLastScanError     */    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解析包的对象        PackageParser pp = new PackageParser();        pp.setSeparateProcesses(mSeparateProcesses);        pp.setOnlyCoreApps(mOnlyCore);        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);    }

该方法就是真正的去扫描Package包了,每个App都有一个唯一的包名(Package)。它的代码中有解析包的代码逻辑,它并不在PMS该类中,而是在PackageParser类中,一个专门解析包的类中!现在去看一下pp.parsePackage(scanFile, parseFlags);该方法的逻辑!

 /**     * Parse the package at the given location. Automatically detects if the     * package is a monolithic style (single APK file) or cluster style     * (directory of APKs).     * <p>     * This performs sanity checking on cluster style packages, such as     * requiring identical package name and version codes, a single base APK,     * and unique split names.     * <p>     * Note that this <em>does not</em> perform signature verification; that     * must be done separately in {@link #collectCertificates(Package, int)}.     *     * @see #parsePackageLite(File, int)     */    public Package parsePackage(File packageFile, int flags) throws PackageParserException {        if (packageFile.isDirectory()) {            return parseClusterPackage(packageFile, flags);        } else {            return parseMonolithicPackage(packageFile, flags);        }    }

在这个方法中,它有分类,若该packageFile是一个目录,则调用parseClusterPackage方法,若该packageFile是一个单独的apk文件,则直接调用parseMonolithicPackage这个方法!由于我们分析的是单个apk,所以就去这个方法去看一下!

 *             {@link #parsePackage(File, int)}. Eventually this method will     *             be marked private.     */    @Deprecated    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {        final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);        if (mOnlyCoreApps) {            if (!lite.coreApp) {                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,                        "Not a coreApp: " + apkFile);            }        }        final AssetManager assets = new AssetManager();        try {        //解析apk            final Package pkg = parseBaseApk(apkFile, assets, flags);            pkg.setCodePath(apkFile.getAbsolutePath());            pkg.setUse32bitAbi(lite.use32bitAbi);            return pkg;        } finally {            IoUtils.closeQuietly(assets);        }    }

我们可以看到在该方法中,它其实调用了parseBaseApk()这个方法,然后返回给Package对象。现在一步一步沿着代码去一探究竟!

 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(cookie, ANDROID_MANIFEST_FILENAME);

   /** File name in an APK for the Android manifest. */    private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";

这里我们发现了,解析apk文件,首先会去解析AndroidManifest.xml文件,用AssetManager的assets对象去加载xml文件资源!
得到这个parser之后,又会去调用 final Package pkg = parseBaseApk(res, parser, flags, outError);这是一个重载方法,之前的没有parser这个参数。现在就去看一下该重载方法。

private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,            String[] outError) throws XmlPullParserException, IOException {        final String splitName;        final String pkgName;        try {            Pair<String, String> 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);    }

该方法中其实就已经有一些大家可能熟悉的东西了,比如

  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);

没错这里的mVersionCode和mVersionName就是每个app都有的版本号,以及版本名称。然后在该方法的末尾又写了 return parseBaseApkCommon(pkg, null, res, parser, flags, outError);这行代码,现在去看下这个方法!

 private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,            XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,            IOException {        mParseInstrumentationArgs = null;        mParseActivityArgs = null;        mParseServiceArgs = null;        mParseProviderArgs = null;        int type;        boolean foundApp = false;        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] = "<manifest> 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);        }        pkg.installLocation = sa.getInteger(                com.android.internal.R.styleable.AndroidManifest_installLocation,                PARSE_DEFAULT_INSTALL_LOCATION);        pkg.applicationInfo.installLocation = pkg.installLocation;

从这个方法名中可以得知这是一个解析apk中都共用的一些逻辑代码。这里我想跟读者说一声,有些时候看源码会略显枯燥,但大部分是因为看不懂代码的逻辑,就会感觉到枯燥,其实,有些时候看不懂代码逻辑,可以去看看方法名称的含义,一般每个方法名称,以及每个类的名称,都会有其中特定的含义,都会帮助你更好的理解源代码的内涵!由于该方法的代码数过多,所以我就挑一些主要的源码来复制一下!

int outerDepth = parser.getDepth();        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 (acceptedTags != null && !acceptedTags.contains(tagName)) {                Slog.w(TAG, "Skipping unsupported element under <manifest>: "                        + tagName + " at " + mArchiveSourcePath + " "                        + parser.getPositionDescription());                XmlUtils.skipCurrentTag(parser);                continue;            }            //节点名 --application            if (tagName.equals(TAG_APPLICATION)) {                if (foundApp) {                    if (RIGID_PARSER) {                        outError[0] = "<manifest> has more than one <application>";                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                        return null;                    } else {                        Slog.w(TAG, "<manifest> has more than one <application>");                        XmlUtils.skipCurrentTag(parser);                        continue;                    }                }                foundApp = true;                if (!parseBaseApplication(pkg, res, parser, flags, outError)) {                    return null;                }            } else if (tagName.equals(TAG_OVERLAY)) {                sa = res.obtainAttributes(parser,                        com.android.internal.R.styleable.AndroidManifestResourceOverlay);                pkg.mOverlayTarget = sa.getString(                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);                pkg.mOverlayPriority = sa.getInt(                        com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,                        -1);                sa.recycle();                if (pkg.mOverlayTarget == null) {                    outError[0] = "<overlay> does not specify a target package";                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                    return null;                }                if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {                    outError[0] = "<overlay> priority must be between 0 and 9999";                    mParseError =                        PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                    return null;                }                XmlUtils.skipCurrentTag(parser);            } else if (tagName.equals(TAG_KEY_SETS)) {                if (!parseKeySets(pkg, res, parser, outError)) {                    return null;                }            } else if (tagName.equals(TAG_PERMISSION_GROUP)) {                if (parsePermissionGroup(pkg, flags, res, parser, outError) == null) {                    return null;                }                //标签名 permission            } else if (tagName.equals(TAG_PERMISSION)) {                if (parsePermission(pkg, res, parser, outError) == null) {                    return null;                }            } else if (tagName.equals(TAG_PERMISSION_TREE)) {                if (parsePermissionTree(pkg, res, parser, outError) == null) {                    return null;                }                //标签名 uses-permisson            } else if (tagName.equals(TAG_USES_PERMISSION)) {                if (!parseUsesPermission(pkg, res, parser)) {                    return null;                }            } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)                    || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {                if (!parseUsesPermission(pkg, res, parser)) {                    return null;                }            } else if (tagName.equals(TAG_USES_CONFIGURATION)) {                ConfigurationInfo cPref = new ConfigurationInfo();                sa = res.obtainAttributes(parser,                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration);                cPref.reqTouchScreen = sa.getInt(                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqTouchScreen,                        Configuration.TOUCHSCREEN_UNDEFINED);                cPref.reqKeyboardType = sa.getInt(                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqKeyboardType,                        Configuration.KEYBOARD_UNDEFINED);                if (sa.getBoolean(                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqHardKeyboard,                        false)) {                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;                }                cPref.reqNavigation = sa.getInt(                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqNavigation,                        Configuration.NAVIGATION_UNDEFINED);                if (sa.getBoolean(                        com.android.internal.R.styleable.AndroidManifestUsesConfiguration_reqFiveWayNav,                        false)) {                    cPref.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;                }                sa.recycle();                pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);                XmlUtils.skipCurrentTag(parser);            } else if (tagName.equals(TAG_USES_FEATURE)) {                FeatureInfo fi = parseUsesFeature(res, parser);                pkg.reqFeatures = ArrayUtils.add(pkg.reqFeatures, fi);                if (fi.name == null) {                    ConfigurationInfo cPref = new ConfigurationInfo();                    cPref.reqGlEsVersion = fi.reqGlEsVersion;                    pkg.configPreferences = ArrayUtils.add(pkg.configPreferences, cPref);                }                XmlUtils.skipCurrentTag(parser);            } else if (tagName.equals(TAG_FEATURE_GROUP)) {                FeatureGroupInfo group = new FeatureGroupInfo();                ArrayList<FeatureInfo> features = null;                final int innerDepth = parser.getDepth();                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT                        && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {                        continue;                    }                    final String innerTagName = parser.getName();                    if (innerTagName.equals("uses-feature")) {                        FeatureInfo featureInfo = parseUsesFeature(res, parser);                        // FeatureGroups are stricter and mandate that                        // any <uses-feature> declared are mandatory.                        featureInfo.flags |= FeatureInfo.FLAG_REQUIRED;                        features = ArrayUtils.add(features, featureInfo);                    } else {                        Slog.w(TAG, "Unknown element under <feature-group>: " + innerTagName +                                " at " + mArchiveSourcePath + " " +                                parser.getPositionDescription());                    }                    XmlUtils.skipCurrentTag(parser);                }                if (features != null) {                    group.features = new FeatureInfo[features.size()];                    group.features = features.toArray(group.features);                }                pkg.featureGroups = ArrayUtils.add(pkg.featureGroups, group);            } else if (tagName.equals(TAG_USES_SDK)) {

这里面其实就是一个xml解析标签的过程,而从其中的if ,else if判断的字符串,我们可以得知,

private static final String TAG_MANIFEST = "manifest";    private static final String TAG_APPLICATION = "application";    private static final String TAG_OVERLAY = "overlay";    private static final String TAG_KEY_SETS = "key-sets";    private static final String TAG_PERMISSION_GROUP = "permission-group";    private static final String TAG_PERMISSION = "permission";    private static final String TAG_PERMISSION_TREE = "permission-tree";    private static final String TAG_USES_PERMISSION = "uses-permission";    private static final String TAG_USES_PERMISSION_SDK_M = "uses-permission-sdk-m";    private static final String TAG_USES_PERMISSION_SDK_23 = "uses-permission-sdk-23";    private static final String TAG_USES_CONFIGURATION = "uses-configuration";    private static final String TAG_USES_FEATURE = "uses-feature";    private static final String TAG_FEATURE_GROUP = "feature-group";    private static final String TAG_USES_SDK = "uses-sdk";    private static final String TAG_SUPPORT_SCREENS = "supports-screens";    private static final String TAG_PROTECTED_BROADCAST = "protected-broadcast";    private static final String TAG_INSTRUMENTATION = "instrumentation";    private static final String TAG_ORIGINAL_PACKAGE = "original-package";    private static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";    private static final String TAG_USES_GL_TEXTURE = "uses-gl-texture";    private static final String TAG_COMPATIBLE_SCREENS = "compatible-screens";    private static final String TAG_SUPPORTS_INPUT = "supports-input";    private static final String TAG_EAT_COMMENT = "eat-comment";    private static final String TAG_PACKAGE = "package";    private static final String TAG_RESTRICT_UPDATE = "restrict-update";

这其实就对应了AndroidManifest.xml文件下的所有节点,下面列着不全

这里写图片描述

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /    <uses-feature android:name="android.hardware.camera" /> <!-- 使用照相机权限 -->    <uses-feature android:name="android.hardware.camera.autofocus" />    <application        android:allowBackup="true"

其实每个if 判断都对应着一个具体的方法,比如
parsePermissionTree()和parseUsesPermission()方法就是对应的解析到有对应节点后的方法!

 else if (tagName.equals(TAG_PERMISSION_TREE)) {                if (parsePermissionTree(pkg, res, parser, outError) == null) {                    return null;                }            } else if (tagName.equals(TAG_USES_PERMISSION)) {                if (!parseUsesPermission(pkg, res, parser)) {                    return null;                }

当然,作为我们平常在配置文件中写的最多的四大组件之类的注册,所以我们重点看application该标签下的代码吧!

      if (tagName.equals(TAG_APPLICATION)) {                if (foundApp) {                    if (RIGID_PARSER) {                        outError[0] = "<manifest> has more than one <application>";                        mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                        return null;                    } else {                        Slog.w(TAG, "<manifest> has more than one <application>");                        XmlUtils.skipCurrentTag(parser);                        continue;                    }                }                foundApp = true;                if (!parseBaseApplication(pkg, res, parser, flags, outError)) {                    return null;                }

重点看parseBaseApplication(pkg, res, parser, flags, outError)这个方法,这个就是解析application标签下的具体逻辑!

private boolean parseBaseApplication(Package owner, Resources res,            XmlResourceParser parser, int flags, String[] outError)        throws XmlPullParserException, IOException {        final ApplicationInfo ai = owner.applicationInfo;        final String pkgName = owner.applicationInfo.packageName;        TypedArray sa = res.obtainAttributes(parser,                com.android.internal.R.styleable.AndroidManifestApplication);
 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);            } else if (parser.getName().equals("meta-data")) {                // note: application meta-data is stored off to the side, so it can                // remain null in the primary copy (we like to avoid extra copies because                // it can be large)                if ((owner.mAppMetaData = parseMetaData(res, parser, owner.mAppMetaData,                        outError)) == null) {                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                    return false;                }            } else if (tagName.equals("library")) {                sa = res.obtainAttributes(parser,                        com.android.internal.R.styleable.AndroidManifestLibrary);                // Note: don't allow this value to be a reference to a resource                // that may change.                String lname = sa.getNonResourceString(                        com.android.internal.R.styleable.AndroidManifestLibrary_name);                sa.recycle();                if (lname != null) {                    lname = lname.intern();                    if (!ArrayUtils.contains(owner.libraryNames, lname)) {                        owner.libraryNames = ArrayUtils.add(owner.libraryNames, lname);                    }                }                XmlUtils.skipCurrentTag(parser);            } else if (tagName.equals("uses-library")) {                sa = res.obtainAttributes(parser,                        com.android.internal.R.styleable.AndroidManifestUsesLibrary);                // Note: don't allow this value to be a reference to a resource                // that may change.                String lname = sa.getNonResourceString(                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_name);                boolean req = sa.getBoolean(                        com.android.internal.R.styleable.AndroidManifestUsesLibrary_required,                        true);                sa.recycle();                if (lname != null) {                    lname = lname.intern();                    if (req) {                        owner.usesLibraries = ArrayUtils.add(owner.usesLibraries, lname);                    } else {                        owner.usesOptionalLibraries = ArrayUtils.add(                                owner.usesOptionalLibraries, lname);                    }                }                XmlUtils.skipCurrentTag(parser);            } else if (tagName.equals("uses-package")) {                // Dependencies for app installers; we don't currently try to                // enforce this.                XmlUtils.skipCurrentTag(parser);            } else {                if (!RIGID_PARSER) {                    Slog.w(TAG, "Unknown element under <application>: " + tagName                            + " at " + mArchiveSourcePath + " "                            + parser.getPositionDescription());                    XmlUtils.skipCurrentTag(parser);                    continue;                } else {                    outError[0] = "Bad element under <application>: " + tagName;                    mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;                    return false;                }            }        }

看到这里,应该就明白了吧!里面有着activity,Service,provider,meta-data,library等标签了吧,这个解析过程总算是有了一个里程碑式的突破,从parseBaseApplication中我们看到这个过程就是普通的xml解析,根据不同的标签来调用不同的解析方法,例如,解析Activity则会调用,parseActivity方法,然后返回一个Activity实例,并且将这个实例添加到Package对象的activites列表中。比如parseActivity()

private Activity parseActivity(Package owner, Resources res,            XmlResourceParser parser, int flags, String[] outError,            boolean receiver, boolean hardwareAccelerated)            throws XmlPullParserException, IOException {        TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);        if (mParseActivityArgs == null) {            mParseActivityArgs = new ParseComponentArgs(owner, outError,                    R.styleable.AndroidManifestActivity_name,                    R.styleable.AndroidManifestActivity_label,                    R.styleable.AndroidManifestActivity_icon,                    R.styleable.AndroidManifestActivity_roundIcon,                    R.styleable.AndroidManifestActivity_logo,                    R.styleable.AndroidManifestActivity_banner,                    mSeparateProcesses,                    R.styleable.AndroidManifestActivity_process,                    R.styleable.AndroidManifestActivity_description,                    R.styleable.AndroidManifestActivity_enabled);        }        mParseActivityArgs.tag = receiver ? "<receiver>" : "<activity>";        mParseActivityArgs.sa = sa;        mParseActivityArgs.flags = flags;        Activity a = new Activity(mParseActivityArgs, new ActivityInfo());        if (outError[0] != null) {            sa.recycle();            return null;

继续解析activity标签下的标签

 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;            }            if (parser.getName().equals("intent-filter")) {                ActivityIntentInfo intent = new ActivityIntentInfo(a);                if (!parseIntent(res, parser, true, true, intent, outError)) {                    return null;                }                if (intent.countActions() == 0) {                    Slog.w(TAG, "No actions in intent filter at "                            + mArchiveSourcePath + " "                            + parser.getPositionDescription());                } else {                    a.intents.add(intent);                }            } else if (!receiver && parser.getName().equals("preferred")) {                ActivityIntentInfo intent = new ActivityIntentInfo(a);                if (!parseIntent(res, parser, false, false, intent, outError)) {                    return null;                }                if (intent.countActions() == 0) {                    Slog.w(TAG, "No actions in preferred at "                            + mArchiveSourcePath + " "                            + parser.getPositionDescription());                } else {                    if (owner.preferredActivityFilters == null) {                        owner.preferredActivityFilters = new ArrayList<ActivityIntentInfo>();                    }                    owner.preferredActivityFilters.add(intent);                }            } else if (parser.getName().equals("meta-data")) {                if ((a.metaData = parseMetaData(res, parser, a.metaData,                        outError)) == null) {                    return null;                }            } else if (!receiver && parser.getName().equals("layout")) {                parseLayout(res, parser, a);            } else {                if (!RIGID_PARSER) {                    Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");                    if (receiver) {                        Slog.w(TAG, "Unknown element under <receiver>: " + parser.getName()                                + " at " + mArchiveSourcePath + " "                                + parser.getPositionDescription());                    } else {                        Slog.w(TAG, "Unknown element under <activity>: " + parser.getName()                                + " at " + mArchiveSourcePath + " "                                + parser.getPositionDescription());                    }                    XmlUtils.skipCurrentTag(parser);                    continue;                } else {                    if (receiver) {                        outError[0] = "Bad element under <receiver>: " + parser.getName();                    } else {                        outError[0] = "Bad element under <activity>: " + parser.getName();                    }                    return null;                }            }        }

到最后也就加到List< Activity> activities列表中

 owner.activities.add(a);

这里只是单独举例,其他的三大组件,也是类似的逻辑,读者有兴趣的话,可以自行观看!
此时,回到之前的scanPackageLI()方法。

 private PackageParser.Package scanPackageLI(PackageParser.Package pkg, final int policyFlags,            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {        boolean success = false;        try {            final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,                    currentTime, user);            success = true;            return res;        } finally {            if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {                // DELETE_DATA_ON_FAILURES is only used by frozen paths                destroyAppDataLIF(pkg, UserHandle.USER_ALL,                        StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);                destroyAppProfilesLIF(pkg, UserHandle.USER_ALL);            }        }    }

其中调用了 final PackageParser.Package res = scanPackageDirtyLI(pkg, policyFlags, scanFlags,
currentTime, user);
这个方法,现在看看该方法。

  private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,            final int policyFlags, final int scanFlags, long currentTime, UserHandle user)            throws PackageManagerException {        final File scanFile = new File(pkg.codePath);        if (pkg.applicationInfo.getCodePath() == null ||                pkg.applicationInfo.getResourcePath() == null) {            // Bail out. The resource and code paths haven't been set.            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,                    "Code and resource paths haven't been set correctly");        }        // Apply policy        if ((policyFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {            pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;            if (pkg.applicationInfo.isDirectBootAware()) {                // we're direct b

由于代码过长,我们只看下面的关键代码

  r = null;            for (i=0; i<N; i++) {                PackageParser.Activity a = pkg.activities.get(i);                a.info.processName = fixProcessName(pkg.applicationInfo.processName,                        a.info.processName, pkg.applicationInfo.uid);                mActivities.addActivity(a, "activity");                if ((policyFlags&PackageParser.PARSE_CHATTY) != 0) {                    if (r == null) {                        r = new StringBuilder(256);                    } else {                        r.append(' ');                    }                    r.append(a.info.name);                }            }

这里我们看到,将上一步解析到的Activity,Service添加到了mActivitys,mServices中,这些类型定义是PMS中的字段,

public static final class SharedLibraryEntry {        public final String path;        public final String apk;        SharedLibraryEntry(String _path, String _apk) {            path = _path;            apk = _apk;        }    }    // Currently known shared libraries.    final ArrayMap<String, SharedLibraryEntry> mSharedLibraries =            new ArrayMap<String, SharedLibraryEntry>();    // All available activities, for your resolving pleasure.    final ActivityIntentResolver mActivities =            new ActivityIntentResolver();    // All available receivers, for your resolving pleasure.    final ActivityIntentResolver mReceivers =            new ActivityIntentResolver();    // All available services, for your resolving pleasure.    final ServiceIntentResolver mServices = new ServiceIntentResolver();    // All available providers, for your resolving pleasure.    final ProviderIntentResolver mProviders = new ProviderIntentResolver();    // Mapping from provider base names (first directory in content URI codePath)    // to the provider information.    final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority =            new ArrayMap<String, PackageParser.Provider>();    // Mapping from instrumentation class names to info about them.    final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =            new ArrayMap<ComponentName, PackageParser.Instrumentation>();    // Mapping from permission names to info about them.    final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =            new ArrayMap<String, PackageParser.PermissionGroup>();    // Packages whose data we have transfered into another package, thus    // should no longer exist.    final ArraySet<String> mTransferedPackages = new ArraySet<String>();    // Broadcast actions that are only available to the system.    final ArraySet<String> mProtectedBroadcasts = new ArraySet<String>();

这个SharedLibraryEntry其实就是PMS中的内部类,专门用来存储一些重要字段!好了到这一步,整个已安装的apk信息树就建立了,每个apk的应用名,包名,图标,Activity,Service等信息都存在系统中,当用户使用intent 跳转到某个Activity或者启动某个Service时,系统则会到这个信息表中进行查找,若找不到,就会报错的,就比如有些时候,没有注册四大组件,或者没有写应有的权限!程序就会崩溃!

最后总结一下:
用张时序图来表现具体流程!

这里写图片描述

阅读全文
0 0