原始碼分析之應用載入過程解析AndroidManifest
阿新 • • 發佈:2019-01-03
一.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這幾個目錄就是對應apk的目錄,android會掃描這幾個目錄,如果存在apk會解析應用.= new File(dataDir, "app-ephemeral"); mAsecInternalPath = new File(dataDir, "app-asec").getPath(); mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
四.解析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 {
這個類中