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时,系统则会到这个信息表中进行查找,若找不到,就会报错的,就比如有些时候,没有注册四大组件,或者没有写应有的权限!程序就会崩溃!
最后总结一下:
用张时序图来表现具体流程!
- Android 中PackageManagerService源代码分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析 .
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android -- PackageManagerService初始化分析
- Android PackageManagerService详细分析[转]
- Android PackageManagerService启动流程分析
- PackageManagerService分析
- Android system server之PackageManagerService详细分析
- android包管理服务(PackageManagerService)源码分析
- Java基础学习
- memcached底层工作原理
- nf_conntrack连接跟踪模块
- MySQL忘记密码解决办法
- 设计模式之访问者模式
- Android 中PackageManagerService源代码分析
- 如何生成 AAC ADTS 基本流与 Android MediaCodec 标签: Android 发布时间: 2013/12/10 20:29:50 本文来自: http://stackoverfl
- 小红书在容器环境的 CD 实践
- Android Study 之 初识ButterKnife(8.5.1)及简单运用
- mongoDB启动报错 ERROR: child process failed, exited with error number 上面这个错误是今天下午发现,从github down下一个应用,在应
- Jmeter构建Ant+Jmeter脚本,持续集成测试收集结果并发送邮件!
- **leetcode 44 Wildcard Matching
- 为什么要使用SLF4J而不是Log4J
- Linux中进程通讯--无名管道