Android源码解析之(⼗⼆)--系统启动并解析Manifest的流程转载请标明出处:
最近有同学问我关于Manifest何时被系统解析的问题,正好也分析到这⼀块了,索性这⼀章就讲解⼀下android系统何时解析Manifest 吧,这⾥的Manifest指的是android安装⽂件apk中的l⽂件是何时被解析的。
⼤家应该都知道,Android系统启动之后,我们就可以在⼀个应⽤中打开另⼀个从未打开过的应⽤,或者是在⼀个应⽤中发送⼴播,如果另外⼀个应⽤设置了这个⼴播的接收器,那么这个应⽤进程就会被启动并接收该⼴播并作出相应的处理,这样的例⼦很多,我们可以猜测到Android系统在启动的时候就会抓取到了系统中所有安装的应⽤信息(应该是解析apk⽂件的Manifest信息),即在Android系统的启动过程中就已经解析了系统中安装应⽤的l⽂件并保存起来了,那么这个过程具体是如何的呢?
其实android系统启动过程中解析Manifest的流程是通过PackageManagerService服务来实现的。这⾥我们重点分析⼀下PackageManagerService服务是如何解析Manifest的。
⾸先看⼀下在SystemServer进程启动过程中是如何启动PackageManagerService服务的:
private void startBootstrapServices() {
.
..
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = PackageManager();
...
}
在SystemServer进程启动过程中会调⽤SystemServer类的startBootstrapServices⽅法(主要⽤于启动ActivityManagerService服务和PackageManagerService服务),然后会在这个⽅法中会调⽤PackageManagerService.main静态⽅法,这个⽅法主要是⽤来初始化PackageManagerService服务并执⾏相关逻辑的。下⾯我来看⼀下main⽅法的具体逻辑:
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
ServiceManager.addService("package", m);
return m;
}
可以发现main⽅法的实现逻辑主要是创建了⼀个PackageManagerService对象,并将这个对象添加到ServierManager中为其他组件提供服务。好吧,看来PackageManagerService的初始化操作主要是在PackageManagerService的构造⽅法中了,下⾯我们来看⼀下其构造⽅法的实现逻辑:
File dataDir = DataDirectory();
mAppDataDir = new File(dataDir, "data");
error parse new
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
PackageManagerService的构造⽅法代码量⽐较⼤,这⾥就不贴出所有的代码了,我们主要和解析Manifest相关的主要代码,在构造⽅法中有这样⼏段代码。可以发现在构造⽅法中,解析了系统中⼏个apk的安装⽬录,这⼏个⽬录就是系统中安装apk的⽬录,android系统会默认解析这⼏个⽬录下apk⽂件,也就是说如果我们android⼿机在其他的⽬录下存在apk⽂件系统是不会默认解析的,反过来说,如果我们把我们的apk⽂件移动到这⼏个⽬录下,那么重新启动操作系统,该apk⽂件就会被系统解析并执⾏相关的逻辑操作,具体做什么操作呢?我们看下⾯的实现。
/ overlay packages if they reside in VENDOR_OVERLAY_DIR.
File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
// Find base frameworks (resource packages without code).
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
// Collected privileged system packages.
final File privilegedAppDir = new RootDirectory(), "priv-app");
scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
/
/ Collect ordinary system packages.
final File systemAppDir = new RootDirectory(), "app");
scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all vendor packages.
File vendorAppDir = new File("/vendor/app");
try {
vendorAppDir = CanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all OEM packages.
final File oemAppDir = new OemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
在我们刚刚的PackageManagerService.mani⽅法中,解析完刚刚的⼏个系统⽬录之后系统会调⽤scanDirLI⽅法,那么这个⽅法主要是做什么⽤的呢?看它的名字应该是遍历这个系统⽬录。好吧,这个⽅法主要就是⽤于解析上⾯⼏个⽬录下的apk⽂件的。不信?我们看⼀下scanDirLI⽅法的具体实现:
private void scanDirLI(File dir, 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" + HexString(parseFlags));
}
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.Name());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
try {
scanPackageLI(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 &&
< == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
if (file.isDirectory()) {
} else {
file.delete();
}
}
}
}
}
可以放下其⾸先会遍历该⽬录下的所有⽂件,并判断是否是apk⽂件,如果是apk⽂件则调⽤scanPackageLI⽅法,scanPackageLI⽅法的名字很明显,就是⽤于解析这个apk⽂件的。
继续看⼀下scanPakcageLI⽅法的实现:
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser();
pp.setSeparateProcesses(mSeparateProcesses);
pp.setOnlyCoreApps(mOnlyCore);
pp.setDisplayMetrics(mMetrics);
if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) {
parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY;
}
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
...
}
好吧,这个⽅法也⽐较复杂,这⾥只是列出重点相关的代码,我们可以发现在这个⽅法中创建了⼀个P
ackagerParser对象,并调⽤了parsePackage⽅法,这个⽅法其实就是解析Manifest的主要⽅法,我们可以看⼀下其具体的实现:
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
可以发现,若我们解析的File对象是⼀个⽂件夹则执⾏调⽤parseClusterPackage⽅法,否则调⽤执⾏parseMonolithicPackage⽅法,很明显的因为我们这⾥解析的是apk⽂件(在上⼀⽅法中我们循环遍历得到了apk⽂件,这⾥的File对象就代表了⼀个个的apk⽂件信息),所以这⾥会执⾏parseMonolithicPackage⽅法,然后我们来看⼀下parseMonolithicPackage⽅法:
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
if (mOnlyCoreApps) {
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (!App) {
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);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
可以看出,这⾥⼜调⽤了parseBaseApk⽅法:
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
...
final Package pkg = parseBaseApk(res, parser, flags, outError);
...
}
可以看出,这个parseBaseApk⽅法调⽤了其重载的parseBaseApk⽅法:
while ((type = ()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || Depth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = Name();
if (tagName.equals("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, attrs, flags, outError)) {
return null;
}
} else if (tagName.equals("overlay")) {
pkg.mTrustedOverlay = trustedOverlay;
sa = res.obtainAttributes(attrs,
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);
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("key-sets")) {
if (!parseKeySets(pkg, res, parser, attrs, outError)) {
return null;
}
} else if (tagName.equals("permission-group")) {
if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
return null;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。