當系統(tǒng)啟動之后澎办,就會注冊各種系統(tǒng)服務(wù)耸彪,如WindowManagerService碌上、ActivityManagerService等掀鹅,其中就有PackageManagerService揽碘。PMS啟動之后次屠,就會掃描已安裝的apk目錄,并解析apk下的androidmanifest.xml文件得到app的信息雳刺,而在androidmanifest.xml中又包含了activity帅矗、service等組件的注冊信息,當PMS解析完成之后煞烫,整個app的信息樹就被構(gòu)建出來了浑此。
那么PMS是如何工作的呢,我們來一起分析一下滞详。
PMS的創(chuàng)建
通常情況下凛俱,我們可以通過以下方式獲取到PackageManager:
PackageManager packageManager = getPackageManager();
點進去可以發(fā)現(xiàn)PackageManager也是一個抽象類,而mBase就是Context:
@Override
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
所以我們直接看Context的實現(xiàn)類ContextImpl:
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
跳轉(zhuǎn)到ActivityThread:
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
可以發(fā)現(xiàn)同樣和WMS一樣都是通過ServiceManager.getService("package")來獲得IBinder對象料饥,并最終轉(zhuǎn)化為PackageManager蒲犬。
那么PMS是如何添加到ServiceManager中的呢?
這個時候我們需要去看SystemServer.java
岸啡,這個類會創(chuàng)建系統(tǒng)的服務(wù):
private PowerManagerService mPowerManagerService;
private ActivityManagerService mActivityManagerService;
private WebViewUpdateService mWebViewUpdateService;
private DisplayManagerService mDisplayManagerService;
private PackageManagerService mPackageManagerService;
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
// PackageManagerService.java
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();
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
UserHandle.USER_SYSTEM);
ServiceManager.addService("package", m);
return m;
}
可以發(fā)現(xiàn)原叮,在SystemServer中PMS最終通過PackageManagerService.main
函數(shù)創(chuàng)建出來,并通過ServiceManager.addService("package", m)添加到ServiceManager中巡蘸。
PMS的工作原理
PMS的主要工作就是解析已安裝的apk目錄奋隶,并解析AndroidManifest.xml文件,最終解析出整個apk的信息樹悦荒。
首先我們先看PMS的構(gòu)造函數(shù):
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// 獲取/data目錄
File dataDir = Environment.getDataDirectory();
// 獲取/data/data目錄唯欣,也就是第三方軟件目錄
mAppInstallDir = new File(dataDir, "app");
// 獲取framework資源、系統(tǒng)app資源
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
// 加載framework資源
scanDirTracedLI(frameworkDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
// 加載系統(tǒng)應(yīng)用
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
// 加載第三方應(yīng)用
scanDirLI(mEphemeralInstallDir, mDefParseFlags
| PackageParser.PARSE_IS_EPHEMERAL,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
}
從上面的代碼可以看到搬味,PMS不僅要加載已經(jīng)安裝好的apk境氢,還需要加載framework的相關(guān)西苑,當加載好了之后才開始掃描指定目錄下的apk文件并解析碰纬。
接下來我們繼續(xù)看scanDirLI:
private void scanDirLI(File dir, final int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// 如果不是package文件萍聊,continue
continue;
}
try {
// 解析apk文件
scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
}
}
}
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);
}
}
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
long currentTime, UserHandle user) throws PackageManagerException {
// 創(chuàng)建包解析器
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 {
// 解析apk
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);
}
通過一系列的調(diào)用最終發(fā)現(xiàn)解析apk是通過PackageParser也就是包解析器,對apk文件進行parsePackage方法的解析:
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
// 解析單個apk
return parseMonolithicPackage(packageFile, flags);
}
}
@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);
}
}
// 構(gòu)建AssetManager
final AssetManager assets = new AssetManager();
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.setCodePath(apkFile.getAbsolutePath());
pkg.setUse32bitAbi(lite.use32bitAbi);
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
// 構(gòu)建資源
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);
// 獲取AndroidManifest.xml解析器
parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
final String[] outError = new String[1];
// 解析
final Package pkg = parseBaseApk(res, parser, flags, outError);
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);
}
}
可以發(fā)現(xiàn)調(diào)用parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME)
獲取AndroidManifest.xml解析器
private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
從這我們可以得出一個結(jié)論如果一個apk包沒有AndroidManifest.xml文件悦析,那么我們在打開的時候就會報錯寿桨,包括lib文件。
我們繼續(xù)追蹤她按,現(xiàn)在到了parseBaseApk方法:
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
String[] outError) throws XmlPullParserException, IOException {
final String splitName;
final String pkgName;
// 解析apk的包名
Pair<String, String> packageSplit = parsePackageSplitNames(parser, parser);
pkgName = packageSplit.first;
splitName = packageSplit.second;
// 構(gòu)建package對象
final Package pkg = new Package(pkgName);
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
// 獲取apk的versioncode牛隅、versionname等信息
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);
}
上面這個方法我們通過解析AndroidManifest.xml獲取到了apk包的相關(guān)信息炕柔。
最終return調(diào)用的parseBaseApkCommon
方法才是解析xml文件的函數(shù)。
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;
parseBaseApplication(pkg, res, parser, flags, outError)媒佣;
}
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
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);
}
}
由于代碼太長匕累,只截取了一點典型代碼,通過上面我們終于發(fā)現(xiàn)了activity默伍、receiver等標簽欢嘿,可以發(fā)現(xiàn)就是普通的xml解析,解析出來之后并返回一個Activity的實例也糊,在加入到activities列表中炼蹦。
public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
public final ArrayList<Service> services = new ArrayList<Service>(0);
最終通過解析所有的標簽,把所有的節(jié)點信息都保存到對應(yīng)的list中狸剃。
到這一步的時候掐隐,整個apk的信息樹就已經(jīng)被建立好了,整個apk的應(yīng)用名钞馁、包名虑省、圖標、activity僧凰、service等信息都存儲到了系統(tǒng)中探颈。