1. 程式人生 > >原始碼分析之應用載入過程解析AndroidManifest

原始碼分析之應用載入過程解析AndroidManifest

一.SystemServer的main方法

/**
 * The main entry point from zygote.
 */
public static void main(String[] args) {
    new SystemServer().run();
}

二.SystemServer 的startBootstrapServices()方法::

SystemServer中run()方法會初始化一系列的服務,PackageManagerService就是其中之一run()方法回撥用

startBootstrapServices() 

這個時候就會呼叫以下方法,來初始化PackageManagerService.

 PackageManagerService.main()

三.PackageManagerService的初始化:(針對使用者應用展開分析,系統應用和使用者應用目錄結構不同)

mian()方法被呼叫後會new出PackageManagerService 在其中可以發現以下目錄

File dataDir = Environment.getDataDirectory();
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mEphemeralInstallDir 
= new File(dataDir, "app-ephemeral"); mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
這幾個目錄就是對應apk的目錄,android會掃描這幾個目錄,如果存在apk會解析應用.

四.解析apk:

1.解析檔案:

呼叫private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {}

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);
這個方法比較簡單就是對apk檔案進行校驗,校驗成功後會呼叫以下方法
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);
}
}

解析出 PackageParser.Package

2.解析 AndroidManifest.xml:

此時比較重要的另外一個類就可以介紹了PackageParser,前面呼叫了scanPackageLI

private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
   ....
PackageParser pp = new PackageParser();
.... pkg = pp.parsePackage(scanFile, parseFlags); ..... return scanPackageLI(pkg, scanFile, parseFlags, scanFlags, currentTime, user);}

而這個方法又呼叫了 public Package parsePackage(File packageFile, int flags)之後又一連串的呼叫最後呼叫到

private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
        throws PackageParserException {
 .... Resources res = null;
XmlResourceParser parser = null;
....
        res = new Resources(assets, mMetrics, null);parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
        final String[] outError = new String[1];
        final Package pkg = parseBaseApk(res, parser, flags, outError);
        ....        return pkg;
.......

}
在這個方法中我們就發現了我們即熟悉而又陌生的老朋友
/** File name in an APK for the Android manifest. */
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
繼續往下看我們就會發現更多老朋友
private Package parseBaseApkCommon(Package pkg, Set<String> acceptedTags, Resources res,
XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException,
IOException {
......

    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
}
 

        if (tagName.equals(TAG_APPLICATION)) {
          .....
        } else if (tagName.equals(TAG_OVERLAY)) {
          
.....

    return pkg;
}
private static final String TAG_APPLICATION = "application";
private static final String TAG_USES_PERMISSION = "uses-permission";

等等不斷的出現,解析整個apk後的資訊存到了
/**
 * Holds information about dynamic settings.
 */
final class Settings {

這個類中