一、概述
PackageManagerService是Android中比较重要的服务,它负责系统中Package的管理,应用程序的安装、卸载、信息查询等。
上图主要展示了PackageManagerService及客户端的通信方式,以及相关类的继承关系。为了简化描述,下文中我们将PackageMangerService称为”PKMS”。
1、
PKMS的客户端,必须通过PackageManager才能发送请求给PKMS,即可以认为PackageManger是PKMS的代理对象。
PackageManager是一个抽象类,实际的实现类是ApplicationPackageManager。当客户端利用Context的getPacakgeManager函数获取PackageManger时,获取的就是ApplicationPacakgeManager。
2、
ApplicationPackageManager与PKMS的交互实际上是基于Binder通信的,只不过利用AIDL文件封装了实现细节。
我们看看ApplicationManager的构造函数:
ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; mPM = pm; }
容易看出,ApplicationPackageManger中持有了IPackageManger对象。
IPacakgeManager对象是怎么得到的?
我们以ActivityThread.java中handleBindApplication函数中的一小段代码为例:
.......
try {
//getPackageManager函数将获取到IPackageManager对象
ii = new ApplicationPackageManager(null, getPackageManager())
.getInstrumentationInfo(data.instrumentationName, 0);
} catch (PackageManager.NameNotFoundException e) {
.......
}
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
//在之前的博客介绍Java层的Binder通信时,我们知道这里最终将会返回BinderProxy对象
IBinder b = ServiceManager.getService("package");
//将BinderProxy对象,转换成实际的业务代理对象
sPackageManager = IPackageManager.Stub.asInterface(b);
}
现在我们知道了,IPackageManager是PKMS的业务代理,其中服务端和客户端通信的业务函数由
framework/base/core/java/android/content/pm/IPackageManager.aidl文件来定义。
如上图所示,PKMS继承自IPackageManager.Stub,其实上也是基于Binder的服务端。
二、PKMS的启动
PKMS由SystemService在开机的时候启动,在SystemServer.java的run方法中:
private void run() {
.......
try {
.....
startBootstrapServices();
.....
startOtherServices();
.....
} ......
}
private void startBootstrapServices() {
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
Installer installer = mSystemServiceManager.startService(Installer.class);
.........
//根据系统属性,决定是否为加密设备加密
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;
}
//调用PKMS的main函数
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
//判断是否为初次启动
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
..........
// Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
// A/B artifacts after boot, before anything else might touch/need them.
// Note: this isn't needed during decryption (we don't have /data anyways).
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
try {
//启动OtaDexoptService也需要PackageMangerService的参与
OtaDexoptService.main(mSystemContext, mPackageManagerService);
}......
}
}
}
从上面的代码,大致可以看出SystemServer在startBootstrapServices函数中启动PKMS,在非加密机器中PKMS还将参与到OtaDexoptService中。
在SystemServer的startOtherService中:
private void startOtherServices() {
......
if (!mOnlyCore) {
........
try {
//将调用performDexOpt:Performs dexopt on the set of packages
mPackageManagerService.updatePackagesIfNeeded();
}.......
........
try {
//执行Fstrim,执行磁盘维护操作,未看到详细的资料
//可能类似于TRIM技术,将标记为删除的文件,彻底从硬盘上移除
//而不是等到写入时再移除,目的是提高写入时效率
mPackageManagerService.performFstrimIfNeeded();
}.........
.......
try {
mPackageManagerService.systemReady();
}........
.......
}
}
从上面的代码可以看出,PKMS启动后将参与一些系统优化的工作,然后调用SystemReady函数通知系统进入就绪状态。
三、PKMS的main函数分析
现在我们重点看看PKMS的main函数。
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
//此处主要检查系统属性
PackageManagerServiceCompilerMapping.checkProperties();
//调用构造函数,其中factoryTest决定是否是测试版本,onlyCore决定是否只解析系统目录,我们先假定均为false
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
//根据条件,enable一些app,针对多用户场景
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);
//利用Binder通信,将自己注册到ServiceManager进程中
ServiceManager.addService("package", m);
return m;
}
1、检查系统属性
我们先看看检查系统属性进行了哪些操作。
........ PackageManagerServiceCompilerMapping.checkProperties(); ........
// Check that the properties are set and valid.
static void checkProperties() {
// We're gonna check all properties and collect the exceptions, so we can give a general
// overview. Store the exceptions here.
RuntimeException toThrow = null;
//reason包括REASON_FIRST_BOOT、REASON_BOOT等
for (int reason = 0; reason <= PackageManagerService.REASON_LAST; reason++) {
try {
// Check that the system property name is legal.
//将reason转化为"pm.dexopt.first-boot"等,定义于PackageManagerServiceCompilerMapping.java中
String sysPropName = getSystemPropertyName(reason);
if (sysPropName == null ||
sysPropName.isEmpty() ||
sysPropName.length() > SystemProperties.PROP_NAME_MAX) {
throw.......
}
// Check validity, ignore result.
getAndCheckValidity(reason);
} catch (Exception exc) {
if (toThrow == null) {
toThrow = new IllegalStateException("PMS compiler filter settings are bad.");
}
//搜集每一个异常
toThrow.addSuppressed(exc);
}
}
if (toThrow != null) {
throw toThrow;
}
}
我们跟进getAndCheckValidity:
// Load the property for the given reason and check for validity. This will throw an
// exception in case the reason or value are invalid.
private static String getAndCheckValidity(int reason) {
//读取对应的系统属性,native函数从系统属性空间中读取
String sysPropValue = SystemProperties.get(getSystemPropertyName(reason));
if (sysPropValue == null || sysPropValue.isEmpty() ||
!DexFile.isValidCompilerFilter(sysPropValue)) {
throw......
}
// Ensure that some reasons are not mapped to profile-guided filters.
switch (reason) {
case PackageManagerService.REASON_SHARED_APK:
case PackageManagerService.REASON_FORCED_DEXOPT:
if (DexFile.isProfileGuidedCompilerFilter(sysPropValue)) {
throw......
}
break;
}
return sysPropValue;
}
从上面的代码可以看出,这些属性可能和编译器有关,实际的用途目前还需要进一步了解。
2、调用PKMS的构造函数
PKMS的构造函数很长,主要功能是:扫描Android系统中几个目标文件夹中的APK,从而建立合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。
我们将在之后的博客再深入分析。
3、针对系统用户,enable一些App
/** * @hide * @return Whether the device is running with split system user. It means the system user and * primary user are two separate users. Previously system user and primary user are combined as * a single owner user. see @link {android.os.UserHandle#USER_OWNER} */
//这里仅作了解即可,我看目前的手机好像还没有配置这个属性
public static boolean isSplitSystemUser() {
return SystemProperties.getBoolean("ro.fw.system_user_split", false);
}
private void enableSystemUserPackages() {
//system和primary未分离,则退出
//当前手机应该都会退出
if (!UserManager.isSplitSystemUser()) {
return;
}
// For system user, enable apps based on the following conditions:
// - app is whitelisted or belong to one of these groups:
// -- system app which has no launcher icons
// -- system app which has INTERACT_ACROSS_USERS permission
// -- system IME app
// - app is not in the blacklist
AppsQueryHelper queryHelper = new AppsQueryHelper(this);
Set<String> enableApps = new ArraySet<>();
//按照条件,增加可用的app
enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
| AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
| AppsQueryHelper.GET_IMES, /* systemAppsOnly */ true, UserHandle.SYSTEM));
//增加白名单里的应用,移除黑名单里的应用
ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
enableApps.addAll(wlApps);
enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_REQUIRED_FOR_SYSTEM_USER,
/* systemAppsOnly */ false, UserHandle.SYSTEM));
ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
enableApps.removeAll(blApps);
//得到system user已安装的应用
Log.i(TAG, "Applications installed for system user: " + enableApps);
List<String> allAps = queryHelper.queryApps(0, /* systemAppsOnly */ false,
UserHandle.SYSTEM);
synchronized (mPackages) {
for (int i = 0; i < allAppsSize; i++) {
String pName = allAps.get(i);
PackageSetting pkgSetting = mSettings.mPackages.get(pName);
// Should not happen, but we shouldn't be failing if it does
if (pkgSetting == null) {
continue;
}
//从已安装中筛选出可使用的
boolean install = enableApps.contains(pName);
if (pkgSetting.getInstalled(UserHandle.USER_SYSTEM) != install) {
Log.i(TAG, (install ? "Installing " : "Uninstalling ") + pName
+ " for system user");
pkgSetting.setInstalled(install, UserHandle.USER_SYSTEM);
}
}
}
}
从上面的代码可以看出,enableSystemUserPackages针对的是system user和primary user分离的特殊场景,按条件为system user安装一些应用。
4、禁止运营商应用
/** * This prevents a potential race condition on first boot - since the app's default state is * enabled, we will initially disable it when the telephony stack is first initialized as it has * not yet read the carrier privilege rules. However, since telephony is initialized later on * late in boot, the app being disabled may have already been started in response to certain * broadcasts. The app will continue to run (briefly) after being disabled, before the Package * Manager can kill it, and this can lead to crashes as the app is in an unexpected state. */
public synchronized static void disableCarrierAppsUntilPrivileged(String callingPackage,
IPackageManager packageManager, int userId) {
//读取将被禁用的App名称
String[] systemCarrierAppsDisabledUntilUsed = Resources.getSystem().getStringArray(
com.android.internal.R.array.config_disabledUntilUsedPreinstalledCarrierApps);
disableCarrierAppsUntilPrivileged(callingPackage, packageManager,
null /* telephonyManager */, userId, systemCarrierAppsDisabledUntilUsed);
}
@VisibleForTesting
public static void disableCarrierAppsUntilPrivileged(String callingPackage,
IPackageManager packageManager, @Nullable TelephonyManager telephonyManager, int userId,
String[] systemCarrierAppsDisabledUntilUsed) {
//根据被禁用的App的名称,取出对应的ApplicationInfo
List<ApplicationInfo> candidates = getDefaultCarrierAppCandidatesHelper(packageManager,
userId, systemCarrierAppsDisabledUntilUsed);
.........
List<String> enabledCarrierPackages = new ArrayList<>();
try {
for (ApplicationInfo ai : candidates) {
String packageName = ai.packageName;
//PKMS中传入的telephonyManager变量为null,因此不检查被禁用的app是否有特权
boolean hasPrivileges = telephonyManager != null &&
telephonyManager.checkCarrierPrivilegesForPackageAnyPhone(packageName) ==
TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
// Only update enabled state for the app on /system. Once it has been updated we
// shouldn't touch it.
if (!ai.isUpdatedSystemApp()) {
//根据是否有特权及application中的信息,修改PKMS对被禁用app的管理策略
//PKMS禁用运营商应用时,不进入该分支
if (hasPrivileges
&& (ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| ai.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
packageManager.setApplicationEnabledSetting(packageName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP, userId, callingPackage);
} else if (!hasPrivileges
&& ai.enabledSetting ==
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT){
//被禁用App的管理策略变为COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
packageManager.setApplicationEnabledSetting(packageName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0,
userId, callingPackage);
}
}
// Always re-grant default permissions to carrier apps w/ privileges.
//PKMS禁用的App无privileges
if (hasPrivileges) {
enabledCarrierPackages.add(ai.packageName);
}
}
//PKMS禁用运营商App时不会进入该分支
if (!enabledCarrierPackages.isEmpty()) {
// Since we enabled at least one app, ensure we grant default permissions to those
// apps.
String[] packageNames = new String[enabledCarrierPackages.size()];
enabledCarrierPackages.toArray(packageNames);
packageManager.grantDefaultPermissionsToEnabledCarrierApps(packageNames, userId);
}
} catch(RemoteException e) {
......
}
}
以上就是PKMS中main函数的主要内容,代码比较简单,但执行时间较长,主要是PKMS的构造函数比较耗时。
虽然没有分析PKMS的构造函数,但我们大致上可以知道PKMS其实就是管理手机中APK信息的,因此它的主要工作就是解析这些APK信息,并用相应的数据结构管理解析出来的内容。