Android 进阶——系统启动之SystemServer创建并启动PackageManagerService服务

Posted CrazyMo_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 进阶——系统启动之SystemServer创建并启动PackageManagerService服务相关的知识,希望对你有一定的参考价值。

文章大纲

引言

SystemServer首先启动,创建一个ServerThread线程来启动所有android核心服务,在创建和启动InstallerActivityManagerServicePowerManagerService、RecoverySystemService、LightsService、DisplayManagerService系统服务启动之后,PackageManagerService就会接着被创建和启动。

基于Android 28,为了阅读,本文约定方法表示Java的,而函数表示Native层概念,仅供参考

一、PackageManagerService概述

PackageManagerService(PKMS)作为管理APK包的系统服务,负责APK包的安装、卸载、优化和查询,

Android 系统在启动过程中会通过PKMS(PackageManagerService)服务自动去扫描系统中指定的目录寻找APK文件、JAR包和SO库,并逐一解析封装为对应的对象再保存到内存中,系统运行时就迅速找到对应的信息并自动安装。

PKMS在扫描时遇到需要优化的文件还会额外执行转换工作,将APK的dex格式优化为oat格式(Linux 的ELF格式的一种私有形式)。

在PKMS 在准备安装APK时主要做了两大工作:

  • 解析APK的清单文件(AndroidManifest.xml)获取其对应的包信息供后面封装为对应的JavaBean 对象(即APK的内存描述对象)
  • App 分配Linux的用户Id 和Linux 用户组Id ,要不然可能在系统里运行时因为安全机制无法得到对应的权限。所以Android 中么一个App 都有一个对应的Linux 用户ID,在PMS 安装该App 时检测发现它没有和其他应用共享同一个用户ID时,就会自动给其分配一个用户ID,除了用户ID之外,当PMS安装时还发现该App 申请了一个特殊的资源访问权限,还会给其分配对应的Linux 用户组ID

当所有App都安装完毕之后,Android Framework 还会启动Home Launcher 应用程序在Launcher 启动。

二、PackageManagerService 体系结构概述

\\frameworks\\base\\core\\java\\android\\content\\pm\\IPackageManager.aidl

\\out\\target\\common\\obj\\JAVA_LIBRARIES\\framework_intermediates\\src\\core\\java\\android\\content\\pm\\IPackageManager.java

作为Android 系统的核心服务,PackageManagerService自然也是采用Binder 服务的架构,当某个进程需要访问某个系统服务时首先得通过ServiceManager 获取其对应的Binder对象,从而调用对应的方法,至于中间的通信细节全部由Binder 通信去完成,PackageManagerService 只是负责包管理的相关工作,解析完成之后再传到Installer服务里。

在应用进程里通过调用Context#getPackageManager() 得到ApplicationPackageManager 对象后,通过Binder 机制与PackageManagerService 服务通信,再由PackageManagerService 调用Installer服务,最终Installer服务通过socket 与installd 守护进程通信。

三、SystemServer进程启动PKMS服务

在前面文章中介绍System进程(SystemServer.java)启动过程中,在AMS、PowerManagerService、DisplayManagerService核心服务启动后,会通过调用PackageManagerService#main方法将PMS 启动

  • 启动Installer服务
  • 启动AMS、PowerManagerService、DisplayManagerService系统服务
  • 调用PackageManagerService#main方法将PKMS 启动
  • 启动MountService
  • dex 优化
  • 调用PackageManagerService#systemReady 回调方法

当然启动PMS 只是System进程启动后干的很小一部分工作,还有其他很多系统服务也会被启动,而且很多启动流程都大同小异。

1、com.android.server.SystemServer#startBootstrapServices 触发PKMS 服务启动

private void startBootstrapServices() 
    //启动Installer服务
    Installer installer = mSystemServiceManager.startService(Installer.class);
    ...
        // Activity manager runs the show.
        mActivityManagerService = mSystemServiceManager.startService(
        ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    mActivityManagerService.setInstaller(installer);		
    //创建 PKMS 对象
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    //PKMS是否首次启动
    mFirstBoot = mPackageManagerService.isFirstBoot();
    mPackageManager = mSystemContext.getPackageManager();
    //...

2、com.android.server.pm.PackageManagerService#main触发PMKS对象创建并注册到ServiceManager

    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();
        ServiceManager.addService("package", m);
        final PackageManagerNative pmn = m.new PackageManagerNative();
        ServiceManager.addService("package_native", pmn);
        return m;
    

3、PackageManagerService构造对象时完成Apk和Jar包的格式转化和扫描解析已安装的系统应用并提取信息

PackageManagerService 在自己构造方法里主要完成两件事:

  • 把系统中指定目录的Apk文件和Jar包从dex格式转为oat格式
  • 扫描系统已安装的应用,并提取对应的信息
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) 
        //true 表示PMKS此次只处理系统应用, SystemProperties.get("vold.decrypt")得到值为trigger_restart_min_framework或者1时SystemServer传过来的参数为true
        mOnlyCore = onlyCore;
        //创建屏幕显示对象
        mMetrics = new DisplayMetrics();
        //mInstallLock 用来保护所有安装apk的访问权限,此操作通常涉及繁重的磁盘数据读写等操作,并且是单线程操作,故有时候会处理很慢
       	        synchronized (mInstallLock) 
                    //mpackages 用来解析内存中所有apk的package信息及相关状态
        synchronized (mPackages) 
            ...
            //多用户管理机制,这是google想模拟windows多用户管理系统,为未来的设计
            sUserManager = new UserManagerService(context, this,
                    new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
            mPermissionManager = PermissionManagerService.create(context,
                    new DefaultPermissionGrantedCallback() 
                        @Override
                        public void onDefaultRuntimePermissionsGranted(int userId) 
                            synchronized(mPackages) 
                                mSettings.onDefaultRuntimePermissionsGrantedLPr(userId);
                            
                        
                    , mPackages /*externalLock*/);
            mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
            ///创建Settings对象
            mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
        
        
         //创建 SharedUserSetting 对象并把system, phone, log, nfc, bluetooth, shell,se,networkstack 这8种shareUserId到mSettings,把这些系统应用的uid 保存起来,添加共享用户组的信息
        mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
			...
         //dex优化工具类
        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
                "*dexopt*");
        //Dex 管理类
        mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock,
                dexManagerListener);
        // ART虚拟机管理服务
        mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
        getDefaultDisplayMetrics(context, mMetrics);//用系统属性设置DisplayMetrics
        //获取SystemConfig()的对象,在其构造方法中会调用readPermissions()完成权限的读取
        SystemConfig systemConfig = SystemConfig.getInstance();
        ...

        synchronized (mInstallLock) 
        // writer
        synchronized (mPackages) 
            //创建消息处理线程处理APK的安装和卸载请求
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            //用于处理安装、卸载应用请求的Handler
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            mProcessLoggingHandler = new ProcessLoggingHandler();//创建进程运行信息记录Handler
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);//绑定到SystemServer 的Watchdog服务
           	...
            //com.android.server.pm.Settings mSettings 读取并解析/data/system下的XML文件
            mFirstBoot = !mSettingsreadLPw(sUserManager.getUsers(false));

            // 清理代码路径不存在的孤立软件包
            final int packageSettingCount = mSettings.mPackages.size();
            for (int i = packageSettingCount - 1; i >= 0; i--) 
                PackageSetting ps = mSettings.mPackages.valueAt(i);
                if (!isExternal(ps) && (ps.codePath == null || !ps.codePath.exists())
                        && mSettings.getDisabledSystemPkgLPr(ps.name) != null) 
                    mSettings.mPackages.removeAt(i);
                    mSettings.enableSystemPackageLPw(ps.name);
                
            

            if (mFirstBoot) 
                //拷贝预编译的DEX文件
                requestCopyPreoptedFiles();
            
            ...
                ///获取环境变量 在init.rc里配置的
            final String bootClassPath = System.getenv("BOOTCLASSPATH");
            final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
            File frameworkDir = new File(Environment.getRootDirectory(), "framework");           				...
            mCacheDir = preparePackageParserCache(mIsUpgrade);

            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            int scanFlags = SCAN_BOOTING | SCAN_INITIAL;

            if (mIsUpgrade || mFirstBoot) 
                scanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
            

            // Collect vendor/product overlay packages. (Do this before scanning any apps.)
            // For security and version matching reason, only consider
            // overlay packages if they reside in the right directory.
            scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR,
                    0);
            scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT,
                    0);

            mParallelPackageParserCallback.findStaticOverlayPackages();

            // Find base frameworks (resource packages without code).
            scanDirTracedLI(frameworkDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_NO_DEX
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect privileged system packages.
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            scanDirTracedLI(privilegedAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary system packages.
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirTracedLI(systemAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM,
                    0);

            // Collect privileged vendor packages.
            File privilegedVendorAppDir = new File(Environment.getVendorDirectory(), "priv-app");
            try 
                privilegedVendorAppDir = privilegedVendorAppDir.getCanonicalFile();
             catch (IOException e) 
                // failed to look up canonical path, continue with original one
            
            scanDirTracedLI(privilegedVendorAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary vendor packages.
            File vendorAppDir = new File(Environment.getVendorDirectory(), "app");
            try 
                vendorAppDir = vendorAppDir.getCanonicalFile();
             catch (IOException e) 
                // failed to look up canonical path, continue with original one
            
            scanDirTracedLI(vendorAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR,
                    0);

            // Collect privileged odm packages. /odm is another vendor partition
            // other than /vendor.
            File privilegedOdmAppDir = new File(Environment.getOdmDirectory(),
                        "priv-app");
            try 
                privilegedOdmAppDir = privilegedOdmAppDir.getCanonicalFile();
             catch (IOException e) 
                // failed to look up canonical path, continue with original one
            
            scanDirTracedLI(privilegedOdmAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary odm packages. /odm is another vendor partition
            // other than /vendor.
            File odmAppDir = new File(Environment.getOdmDirectory(), "app");
            try 
                odmAppDir = odmAppDir.getCanonicalFile();
             catch (IOException e) 
                // failed to look up canonical path, continue with original one
            
            scanDirTracedLI(odmAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_VENDOR,
                    0);

            // Collect all OEM packages.
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirTracedLI(oemAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_OEM,
                    0);

            // Collected privileged product packages.
            File privilegedProductAppDir = new File(Environment.getProductDirectory(), "priv-app");
            try 
                privilegedProductAppDir = privilegedProductAppDir.getCanonicalFile();
             catch (IOException e) 
                // failed to look up canonical path, continue with original one
            
            scanDirTracedLI(privilegedProductAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT
                    | SCAN_AS_PRIVILEGED,
                    0);

            // Collect ordinary product packages.
            File productAppDir = new File(Environment.getProductDirectory(), "app");
            try 
                productAppDir = productAppDir.getCanonicalFile();
             catch (IOException e) 
                // failed to look up canonical path, continue with original one
            
            scanDirTracedLI(productAppDir,
                    mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM_DIR,
                    scanFlags
                    | SCAN_AS_SYSTEM
                    | SCAN_AS_PRODUCT,
                    0);

            // 裁剪不在存在的系统应用的包package
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
            final List<String> stubSystemApps = new ArrayList<>();
            if (!mOnlyCore) 
                final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) 
                    PackageSetting ps = psit.next();
                    /**
                     *如果得到的ps代表的package信息不是系统应用的则不能禁用
                     */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) 
                        continue;
                    
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) 
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) 
                            removePackageLI(scannedPkg, true);
                            mExpectingBetter.put(ps.name, ps.codePath);
                        
                        continue;
                    
                    ...
                
            

            //删除临时文件
            deleteTempPackageFiles();
            final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get();
            //裁剪多余没有关联应用的uid
            mSettings.pruneSharedUsersLPw();
            if (!mOnlyCore) 
                scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);

                scanDirTracedLI(sDrmAppPrivateInstallDir, mDefParseFlags
                        | PackageParser.PARSE_FORWARD_LOCK,
    

以上是关于Android 进阶——系统启动之SystemServer创建并启动PackageManagerService服务的主要内容,如果未能解决你的问题,请参考以下文章

Android 进阶——系统启动之SystemServer创建并启动Installer服务

Android 进阶——系统启动之SystemServer创建并启动Installer服务

Android 进阶——系统启动之Framework 核心ActivitityManagerService服务启动

Android 进阶——系统启动之Framework 核心ActivitityManagerService服务启动

Android 进阶——系统启动之Framework 核心ActivitityManagerService服务启动

Android 进阶——系统启动之核心SystemServer进程启动详解