Android7.0 PackageManagerService (1) 通信结构、启动和main函数
来源:互联网 发布:linux 中文字体 编辑:程序博客网 时间:2024/06/05 23:53
一、概述
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);}@VisibleForTestingpublic 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信息,并用相应的数据结构管理解析出来的内容。
- Android7.0 PackageManagerService (1) 通信结构、启动和main函数
- Android7.0 PackageManagerService (2) PKMS构造函数的主要工作
- Android7.0 PackageManagerService (5) installd
- Android7.0 PackageManagerService APK安装
- Android7.0 PackageManagerService (3) APK安装
- main函数和启动例程
- main函数和启动例程
- main函数和启动例程
- main函数和启动例程
- main函数和启动例程
- main函数和启动例程
- main函数和启动例程
- main函数和启动例程
- main函数和启动例程
- Android7.0 PackageManagerService (4) Intent匹配Activity的过程
- Android7.0 Binder通信(1) ServiceManger
- Android7.0 PowerManagerService(1) 启动过程
- Android7.0 PowerManagerService(1) 启动过程
- Windows下faster-rcnn编译
- requestFocus() 与 requestFocusFromTouch() 方法的区别
- 第4周项目1-建立单链表
- springMVC初识,最简单的
- 在ubantu14下使用composer安装laravel的记录
- Android7.0 PackageManagerService (1) 通信结构、启动和main函数
- 第四周项目2—建设“单链表”算法库
- JS—数组深层复制
- 笔试中的static
- 第四周项目3-求集合并集
- Codeforces Beta Round #51 D. Beautiful numbers(数位dp)
- 乘法器——verilog
- Nvidia Caffe User Guide
- sq