一 system_server启动PMS
Android的所有Java服务都是通过system_server进程启动的,并且驻留在system_server进程中。SystemServer进程在启动时,通过创建一个ServerThread线程启动所有服务。
1.1 startBootstrapServices()
system_server的startBootstrapServices()函数会启动一些引导服务,比如:
-
ActivityManagerService
-
PowerManagerService
-
DisplayManagerService
-
SensorService
其中PackageManagerService就在这里启动。
private void startBootstrapServices() {
//启动installer服务
Installer installer = mSystemServiceManager.startService(Installer.class);
// We need the default display before we can initialize the package manager.
mSystemServiceManager.startBootPhase(SystemService.PHASE\_WAIT\_FOR\_DEFAULT\_DISPLAY);
//处于加密状态则仅仅解析核心应用
// Only run "core" apps if we're encrypting the device.
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING\_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED\_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
// 创建PMS对象 - 启动入口
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY\_TEST\_OFF, mOnlyCore);
// 是否首次启动
mFirstBoot = mPackageManagerService.isFirstBoot();
// 获取PackageManager
mPackageManager = mSystemContext.getPackageManager();
Trace.traceEnd(Trace.TRACE\_TAG\_SYSTEM\_SERVER);
}
1.2 startOtherService()
system_server的startOtherService()方法会启动其他服务,在这里也会对PMS做一些处理
private void startOtherServices() {
......
if (!mOnlyCore) {
........
try {
//将调用performDexOpt:Performs dexopt on the set of packages
mPackageManagerService.updatePackagesIfNeeded();
}.......
........
try {
//执行Fstrim,执行磁盘维护操作
//可能类似于TRIM技术,将标记为删除的文件,彻底从硬盘上移除
//而不是等到写入时再移除,目的是提高写入时效率
mPackageManagerService.performFstrimIfNeeded();
}.........
.......
try {
mPackageManagerService.systemReady();
}........
.......
}
}
PMS启动后将参与一些系统优化的工作,然后调用SystemReady方法通知系统服务进入就绪状态
在system_server进程启动过程,涉及PMS服务的主要几个处理:
-
PMS.main()
-
PMS.performDexOpt()
-
PMS.systemReady()
二 PMS.main的入口
public static final 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入口中,直接实例化一个PMS服务,并将PMS服务放入ServiceManager中,便于管理,那么重点就是实例化PMS
代码比较多,选择一些重点
new PackageManagerService(context, installer, factoryTest, onlyCore);
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;
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
// displayMetrics是一个描述界面显示,尺寸,分辨率,密度的类
mMetrics = new DisplayMetrics();
// Settings是Android的全局管理者,用于协助PMS保存所有的安装包信息
mSettings = new Settings(context);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM\_UID,
ApplicationInfo.FLAG\_SYSTEM|ApplicationInfo.FLAG\_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO\_UID,
ApplicationInfo.FLAG\_SYSTEM|ApplicationInfo.FLAG\_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG\_UID,
ApplicationInfo.FLAG\_SYSTEM|ApplicationInfo.FLAG\_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC\_UID,
ApplicationInfo.FLAG\_SYSTEM|ApplicationInfo.FLAG\_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH\_UID,
ApplicationInfo.FLAG\_SYSTEM|ApplicationInfo.FLAG\_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL\_UID,
ApplicationInfo.FLAG\_SYSTEM|ApplicationInfo.FLAG\_PRIVILEGED);
.......
mInstaller = installer;
// 获取默认的显示信息,保存到mMetrics
getDefaultDisplayMetrics(context, mMetrics);
// 获取系统配置信息
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
mHandlerThread = new ServiceThread(TAG,
Process.THREAD\_PRIORITY\_BACKGROUND, true /\*allowIo\*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, WATCHDOG\_TIMEOUT);
// 创建各种目录,此时,到了我们熟悉的Android目录了
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
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");
// 创建用户管理服务
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
.......
}
.......
}
此方法中,做了大概如下操作
-
构造DisplayMetrics类:描述界面显示,尺寸,分辨率,密度。构造完后并获取默认的信息保存到变量mMetrics中
-
构造Settings类:这个是Android的全局管理者,用于协助PMS保存所有的安装包信息
-
保存Installer对象
-
获取系统配置信息:SystemConfig构造函数中会通过readPermissions()解析指定目录下的所有xml文件,然后把这些信息保存到systemConfig中,涉及的目录有如下:
-
- /system/etc/sysconfig
- /system/etc/permissions
-
- /oem/etc/sysconfig
- /oem/etc/permissions
-
创建data下的各种目录,比如data/app, data/app-private等
其中我们最为熟悉的就是最后一点,创建各种Android目录结构
各种第三方应用都是安装在mAppInstallDir目录中,直接搜索mAppInstallDir,得知在scanDirLI()函数中调用
扫描指定文件目录下的apk文件
scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime)
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" + 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 {
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 &&
e.error == PackageManager.INSTALL\_FAILED\_INVALID\_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
if (file.isDirectory()) {
FileUtils.deleteContents(file);
}
file.delete();
}
}
}
}
扫描这个文件夹下面的所有文件,并且判断是否为apk文件,如果不是继续循环,如果是,则扫描这个路径下的文件,调用scanPackageLI()
解析package信息,其中最重要的一个类为PackageParser,这个类和插件化技术处理联系紧密
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);
.......
final PackageParser.Package pkg;
try {
// 1
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
}
其中1位置使用PackageParser对象解析对应scanFile文件下的资源,最终返回一个pkg对象,pkg为PackageParser类中的内部类Package
Package:
public final static class Package {
public String packageName;
/\*\* Names of any split APKs, ordered by parsed splitName \*/
public String\[\] splitNames;
// TODO: work towards making these paths invariant
/\*\*
\* Path where this package was found on disk. For monolithic packages
\* this is path to single base APK file; for cluster packages this is
\* path to the cluster directory.
\*/
public String codePath;
/\*\* Path of base APK \*/
public String baseCodePath;
/\*\* Paths of any split APKs, ordered by parsed splitName \*/
public String\[\] splitCodePaths;
/\*\* Flags of any split APKs; ordered by parsed splitName \*/
public int\[\] splitFlags;
public boolean baseHardwareAccelerated;
// For now we only support one application per package.
public final ApplicationInfo applicationInfo = new ApplicationInfo();
public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
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);
public final ArrayList<Instrumentation> instrumentation = new ArrayList<Instrumentation>(0);
.......
.......
.......
}
其中有我们熟悉的activities,receivers,providers,services四大组件集合,Package对象就是包含了我们Android的所有资源信息
PackageParser中的parsePackage()方法--->parseMonolithicPackage()
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(packageFile, flags);
} else {
return parseMonolithicPackage(packageFile, flags);
}
}
@Deprecated
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
if (mOnlyCoreApps) {
final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
if (!lite.coreApp) {
throw new PackageParserException(INSTALL\_PARSE\_FAILED\_MANIFEST\_MALFORMED,
"Not a coreApp: " + apkFile);
}
}
// 1
final AssetManager assets = new AssetManager();
try {
final Package pkg = parseBaseApk(apkFile, assets, flags);
pkg.codePath = apkFile.getAbsolutePath();
return pkg;
} finally {
IoUtils.closeQuietly(assets);
}
}
在代码中位置1 ,初始化一个AssetManager对象,并作为参数传入parseBaseApk()函数,最终返回一个package对象
由此可见,parseBaseApk函数也是对这个apk文件的资源进行解析处理
注意:此时new出来的assetManager并不能直接加载apk资源,必须还要去调用addAssetPath方法
parseBaseApk():
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
throws PackageParserException {
final String apkPath = apkFile.getAbsolutePath();
mParseError = PackageManager.INSTALL\_SUCCEEDED;
mArchiveSourcePath = apkFile.getAbsolutePath();
if (DEBUG\_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
// 1
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);
// 2
parser = assets.openXmlResourceParser(cookie, ANDROID\_MANIFEST\_FILENAME);
final String\[\] outError = new String\[1\];
// 3
final Package pkg = parseBaseApk(res, parser, flags, outError);
if (pkg == null) {
throw new PackageParserException(mParseError,
apkPath + " (at " + parser.getPositionDescription() + "): " + outError\[0\]);
}
pkg.baseCodePath = apkPath;
pkg.mSignatures = 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);
}
}
位置1代码为
private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
throws PackageParserException {
if ((flags & PARSE\_MUST\_BE\_APK) != 0 && !isApkPath(apkPath)) {
throw new PackageParserException(INSTALL\_PARSE\_FAILED\_NOT\_APK,
"Invalid package file: " + apkPath);
}
// The AssetManager guarantees uniqueness for asset paths, so if this asset path
// already exists in the AssetManager, addAssetPath will only return the cookie
// assigned to it.
int cookie = assets.addAssetPath(apkPath);
if (cookie == 0) {
throw new PackageParserException(INSTALL\_PARSE\_FAILED\_BAD\_MANIFEST,
"Failed adding asset path: " + apkPath);
}
return cookie;
}
此时,可以通过assetManager加载apk资源,包括res,androidMainfest.xml文件等
位置2 打开androidMainfest文件,也就是解析关键资源入口就找到了
位置3 将解析后的androidMainfest文件返回的parser对象传入parseBaseApk函数
private Package parseBaseApk(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;
}
String tagName = parser.getName();
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;
//1
if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
}
.......
}
.......
}
在这个方法中,解析了AndroidMainfest中的application节点,这是我们需要关心的重点。
直接看位置1
private boolean parseBaseApplication(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String\[\] outError)
throws XmlPullParserException, IOException {
.......
.......
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")) {
// 1
Activity a = parseActivity(owner, res, parser, attrs, 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")) {
// 2
Activity a = parseActivity(owner, res, parser, attrs, 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, attrs, 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, attrs, 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, attrs, 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, attrs, owner.mAppMetaData,
outError)) == null) {
mParseError = PackageManager.INSTALL\_PARSE\_FAILED\_MANIFEST\_MALFORMED;
return false;
}
} else if (tagName.equals("library")) {
sa = res.obtainAttributes(attrs,
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(attrs,
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;
}
}
}
}
可以看到上面就是我们最为熟悉的配置文件中的各种节点配置,包括四大组件,meta-data
等。
其中有一点可以注意下:activity节点和receiver节点处理类型都为Activity对象,这是因为activity和receiver节点结构一样,类似于JavaBean结构。
activity和receiver节点结构:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</receiver>
节点中都有intent-filter,action节点。那么在上面parseBaseApplication()函数代码块中位置1和位置2的函数parseActivity()如下:
private Activity parseActivity(Package owner, Resources res,
XmlPullParser parser, AttributeSet attrs, int flags, String\[\] outError,
boolean receiver, boolean hardwareAccelerated)
throws XmlPullParserException, IOException {
......
// 1
Activity a = new Activity(mParseActivityArgs, new ActivityInfo());
......
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")) {
//2
ActivityIntentInfo intent = new ActivityIntentInfo(a);
if (!parseIntent(res, parser, attrs, 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 (parser.getName().equals("meta-data")) {
if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
outError)) == null) {
return null;
}
}
}
......
}
13行直接匹配解析intent-filter节点,同时将parseIntent()函数返回的intent-filter放入activity对象中的intents集合中。
在第8行中,这个activity对象中会将信息转为ActivityInfo,其中包括各种信息:name,
packageName等等
到这里基本一次解析就结束了,会将得到的信息存储到对应的PackageParser中的对应的集合中,并将这部分信息传递到PMS中
那么一样的道理,在其他文件路径下的处理也类似,比如/data/app-private目录
以上,为PMS原理简单流程,后续可补充。
关注公众号:Android老皮
解锁 《Android十大板块文档》 ,让学习更贴近未来实战。已形成PDF版
内容如下:
1.Android车载应用开发系统学习指南(附项目实战)
2.Android Framework学习指南,助力成为系统级开发高手
3.2023最新Android中高级面试题汇总+解析,告别零offer
4.企业级Android音视频开发学习路线+项目实战(附源码)
5.Android Jetpack从入门到精通,构建高质量UI界面
6.Flutter技术解析与实战,跨平台首要之选
7.Kotlin从入门到实战,全方面提升架构基础
8.高级Android插件化与组件化(含实战教程和源码)
9.Android 性能优化实战+360°全方面性能调优
10.Android零基础入门到精通,高手进阶之路
敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔