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信息,并用相应的数据结构管理解析出来的内容。

0 0
原创粉丝点击