Android 包管理(PackageManagerService)

程序包管理主要包含三个部分内容。

  1. 提供一个能够根据intent匹配到具体的Activity、Provider、Service。即当应用程序调用startActivity(intent)时,能够把参数中指定的intent转换成一个具体的包含了程序包名称及具体Componet名称的信息,以便Java类加载具体的Componet。
  2. 进行权限检查。当应用程序调用某个需要一定权限的函数调用时,系统判断调用者是否具备该权限,从而保证系统的安全。
  3. 提供安删除应用程序的接口。
    完成以上代码主要在PackageManagerService类中,大部分代码仅仅是执行一些事务性的处理,比如解析XML文件,进行Hash表的添加、查找等。

一、包管理概述。
Framework中包管理整体框架如下:

应用层  
 ContextImpl.ApplicationManager->Abstract PackageManager

--------------------------------------------------------------- PMS服务层 PackageManagerService /system/etc/permissions/ 加载系统feature,并为核心进程分配默认权限 defaultContainerService /data/system/ 所有对应程序与包管理相关信息 installer ---------------------------------------------------------------
程序文件层
 /system/app /data/secure 加密目录
 /system/priv-app /data/drm/ drm专有目录
 /system/framework/*.apk *.jar /data/app-private/
 /data/app drm专有目录
 /data/dalvik-cache /data/data普通程序专有目录 ---------------------------------------------------------------
 包管理服务程序架构

该框架分为三层,分别是应用程序成、PMS服务层、数据文件层。
1.应用程序层
应用程序需要使用包管理服务时,调用ContextImpl类的getApplicationManager()函数返回一个PackageManager()函数返回一个PackageManager对象,然后条用该对象的各种API接口,它获取的方式和?getSystemService(“package”)类似,都是从ServiceManager获得指定的名称Ibinder对象。
2.PMS服务层
和AMS、WMS等其他服务一样,包管理服务运行于SystemServer进程。PMS服务运行时,使用两个目录的XML文件保存相关的包管理信息。
第一个目录是”/system/etc/permissions”,该目录下的所有XML文件用于permission的管理,包含两件事,第一定义系统中都包含了哪些feature,应用程序可以在AndroidManifest.xml中使用标签声明程序需要哪些feature。该目录还有一个还有一个platform.xml文件,该文件为一些特别uid和gid分配一些默认权限,给uid分配权限使用标签,给gid分配权限使用标签。
第二个目录是”/data/system/package.xml”该文件保存了所有安装的程序基本信息,有点像注册表,比如包名称、路径、权限等等。
PMS在启动的时候会从这两个目录中解析相关的XML文件,从而建立庞大的信息树,应用程序可以可以间接的从这个信息树种查询所需的程序包信息。
除了PMS服务外,还有两个辅助系统服务用于程序的安装。一个是DefaultContainerService,该服务主要用于把安装程序复制到程序目录中,另一个是Installer服务该服务并不是一个Binder,而是一个socket客户端,PMS直接和该socket客户端交互,,socket主要完成程序文件的解压工作及数据目录创建。比如从APK文件中提取dex文件,删除dalvik-cache目录下的dex文件,创建程序专属的数据目录。
3.数据文件层。
第一部分为,程序文件。所有的系统程序保存在system/app目录下,所有的第三方应用程序保存在/data/app下,对于非系统程序,在安装前,程序文件保存在任意地方,但安装后PMS会把APK文件放到/data/app目录下。他与原始APK文件的唯一区别是文件的名称不同,原始文件可以随意命名,而该目录下的文件名称是以包名进行命名,并自动添加一个”-X”后缀。而data/dalvik-cache目录保存着着程序执行代码。一个APK实际上是一个Jar压缩类型的文件,压缩文件包含了各种资源文件、资源索引文件、AndroidManifest文件及程序文件,当程序运行之前,PMS会从APK文件中提取代码文件,也就是dex文件,并将该文件存储在该目录下以便后面能够快速运行。
第二部分,Framework库文件。这些库文件存在于/system/framework目录下面,库文件类型是APK或者Jar,系统开机后,dalvik虚拟机会加载这些库文件,而在PMS启动时,如果这些Jar或者APK文件还没有转换成dex文件,则PMS会将这些库文件转换成dex文件,并保存到/data/dalvik-cache目录下。
第三部分,应用程序的数据文件。应用程序可以使用三种数据保存方式,分别为参数存储、数据库存储、文件存储。这三种文件一般保存到/data/data/xxx目录下。

二、PMS服务启动过程分析
PMS本身是一个Service,它与WMS、AMS等重要服务运行在同一个进程–系统进程中、当SystemServer服务启动时,初始化函数会启动各种具体的服务进程中。
PMS服务是从静态函数main()函数中创建的。

public static final IPackageManager main(Context context,boolean factoryTest){
    PackageManagerService m=new         PackageManagerService(context,factory);
    return m;
}

main()函数中创建了一个PMS实例,然后把该服务添加到ServiceManager中。应用程序可以使用Context类中的getSystemService()获得PMS服务的Binder接口,并调用PMS所提供的相应服务。
PMS的启动过程实际上就是该类的构造函数的包含的各种初始化过程,在介绍构造函数内部执行流程前,首先需要了解一下各主要功能类之间的关系,因为启动过程实际岸上是读取相关XML文件中的信息,并把这些信息存放到相关的类成员变量之中。
各种功能类的关系
包管理相关的主要作用类作为PMS的内部类被定义。关系图如下:
《Android 包管理(PackageManagerService)》
由图可以看出,内部settings类把汗了包管理全部信息。
1.包属性信息

  • File mSettingsFilename:配置文件名称,指的是packages.xml文件。
  • File mBackupSettingFilename:配置文件可以有一个backup文件,该backup文件用于系统意外关机后与原始配置文件进行对比,以检查系统的完整性。
  • File mPackageListFilename:指的就是PackageList文件,保存了所有的应用程序列表,该文件中的每一行对应一个应用程序。比如 com.android.haii.debugger 10032 1 |data/data/com.android.haii.debugger 。该记录中第一项代表应用程序的名称,第二项代表应用程序的Linux用户id,如果应用程序使用的共享id,则指的是共享id对象的用户id,第三个数字1代表是否可以被debug,1代表允许,0代表不允许,第四个代表应用程序数据文件目录。
  • Hashmap< String,PackageSetting >mPackages:PMS启动后,该变量将被填充为包管理信息,这些信息来源于packages.xml。注意该变量和PMS中定义的mPackages变量的区别,前者是从package.xml去读记录信息,而后者则是直接扫描程序目录下所有APK文件而生成的信息,并且前者是PackageSeeting,而后者是PackageParse.Package。
  • Hashmap < String, PackageSetting> mDisableSysPackages:该变量将保存哪些没有通过标准卸载方法删除的程序列表。如果通过标准卸载该方法,PMS在程序卸载之后,会清楚该程序在Packages.xml中对应的记录,而如果通过adb或者其他文件操作删除的APK文件,那么packages.xml中对应的记录不会被自动删除,每次系统启动时PMS会检查packages.xml文件,并检查相应程序目录下的文件,从而判断是否被意外删除,如果删除,则把相应的程序信息放到mDisabledSysPackages列表中。
  • int mInternalSdkPlatform:保存的就是package.xml中last-platform-version标签中的值。
  • int mExterbalSdkPlatform:上同
    2.用户id相关信息

  • HashMap < String,ShareUserSetting >mSharedUsers:该变量保存了所有共享id的信息,来源于packages.xml的标签。

  • ArrayListmUserId:所有用户id。
  • SparseArraymOtherUserIds:暂无使用
  • ArrayListmPedingPackages:当PMS解析packages.xml文件时,如果发现某个package标签中使用的是shareUserId,则暂时把该package添加到mPendingPackage列表中,知道最后解析完毕shared-user标签后,再完善原来的package标签中的信息。
    3.权限管理相关信息

  • ArrayList< Signature >mPastSignatures:保存了所有签名信息

  • HashMap< String,BasePermission>mpermissions:保存了所有权限,该Map是从permission名称到permission的信息映射。
  • HashMap< String,BasePermission>mpermissionTrees:对应的是package.xml文件的permission-tree标签。

4.删除信息
ArrayList< String>mpackagesToBeCleaned:保存的是packages.xml的cleaning-package标签中包含的package列表,该列表来源于那些已经被卸载的应用程序,但所包含的数据目录由于保存在外部存储区没有被删除。因为PMS卸载程序时,如果该程序数据保存在外部存储空间,其数据目录默认不会删除。

在PMS类中,包含以下重要变量。
– HashMap< String,PackageParser.Package>mPackages:保存所有的程序包信息,来源于扫描程序目录下面的所有程序文件。
– final Settings mSettings:该变量是类Settings。
– HashMap< String,FeatureInfo>mAvailableFeatures:一个feature本质上知识一段字符串的描述
– int[ ]mGlobalGids:系统中所有Linux用户id。
– SparseArray< Hashsert<>>mSystemPermissions:系统中所有权限名称。
– HashMap< String packageName,String path>mSharedLibraries:系统所依赖的共享java库,其值来源于platform.xml中的library标签的定义的值。
– ActivityIntentResolver mActivities;
– ActivityIntentResolver mReceviers;
– ServicrIntentResolver mServices;
上面三个变量用于进行Intent-filter,并分别匹配到Activity、Receiver、Service对象,在PMS初始化时,会遍历程序目录下的全部的程序,并从其包含的AndroidManifest.xml文件中提取所有的inten-filter数据,并将其保存到以上三个变量中,系统运行时,应用程序调用PackageManager的queryIntebtXXX()函数时,其内部正是通过以上三个变量查询相关的目标信息的。
PMS主体启动过程
《Android 包管理(PackageManagerService)》
主体启动过程就是指PMS构造函数内部的启动流程,见上图。


    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;

        mPermissionReviewRequired = context.getResources().getBoolean(
                R.bool.config_permissionReviewRequired);

        mFactoryTest = factoryTest;
        mOnlyCore = onlyCore;
        mMetrics = new DisplayMetrics();
        mSettings = new Settings(mPackages);
        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);
        mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
        mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
                ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);

        File setFile = new File(AlarmManager.POWER_OFF_ALARM_SET_FILE);
        File handleFile = new File(AlarmManager.POWER_OFF_ALARM_HANDLE_FILE);
        mIsAlarmBoot = SystemProperties.getBoolean("ro.alarm_boot", false);
        if (mIsAlarmBoot) {
            mOnlyPowerOffAlarm = true;
        } else if (setFile.exists() && handleFile.exists()) {
            // if it is normal boot, check if power off alarm is handled. And set
            // alarm properties for others to check.
            if (!mOnlyCore && AlarmManager
                    .readPowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_HANDLE_FILE)
                    .equals(AlarmManager.POWER_OFF_ALARM_HANDLED)) {
                SystemProperties.set("ro.alarm_handled", "true");
                File instanceFile = new File(AlarmManager.POWER_OFF_ALARM_INSTANCE_FILE);
                String instanceValue = AlarmManager
                        .readPowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_INSTANCE_FILE);
                SystemProperties.set("ro.alarm_instance", instanceValue);

                AlarmManager.writePowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_HANDLE_FILE,
                        AlarmManager.POWER_OFF_ALARM_NOT_HANDLED);
            }
        }

        String separateProcesses = SystemProperties.get("debug.separate_processes");
        if (separateProcesses != null && separateProcesses.length() > 0) {
            if ("*".equals(separateProcesses)) {
                mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
                mSeparateProcesses = null;
                Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
            } else {
                mDefParseFlags = 0;
                mSeparateProcesses = separateProcesses.split(",");
                Slog.w(TAG, "Running with debug.separate_processes: "
                        + separateProcesses);
            }
        } else {
            mDefParseFlags = 0;
            mSeparateProcesses = null;
        }

        mInstaller = installer;
        mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
                "*dexopt*");
        mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

        mOnPermissionChangeListeners = new OnPermissionChangeListeners(
                FgThread.get().getLooper());

        getDefaultDisplayMetrics(context, mMetrics);

        SystemConfig systemConfig = SystemConfig.getInstance();
        mGlobalGids = systemConfig.getGlobalGids();
        mSystemPermissions = systemConfig.getSystemPermissions();
        mAvailableFeatures = systemConfig.getAvailableFeatures();

        mProtectedPackages = new ProtectedPackages(mContext);
        if (ZSFeature.ZEUSIS_FEATURE_PRESETAPP) {
            mPresetApp = new PresetApp("presetapp");
            mPresetApp.readDelApk();
        }

// synchronized (mInstallLock) {
        // writer
// synchronized (mPackages) {
            mHandlerThread = new ServiceThread(TAG,
                    Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
            mHandlerThread.start();
            mHandler = new PackageHandler(mHandlerThread.getLooper());
            mProcessLoggingHandler = new ProcessLoggingHandler();
            Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

            mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);

            File dataDir = Environment.getDataDirectory();
            mAppInstallDir = new File(dataDir, "app");
            mAppLib32InstallDir = new File(dataDir, "app-lib");
            mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
            mRegionalizationAppInstallDir = new File(dataDir, "app-regional");

            sUserManager = new UserManagerService(context, this, mPackages);

            // Propagate permission configuration in to package manager.
            ArrayMap<String, SystemConfig.PermissionEntry> permConfig
                    = systemConfig.getPermissions();
            for (int i=0; i<permConfig.size(); i++) {
                SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
                BasePermission bp = mSettings.mPermissions.get(perm.name);
                if (bp == null) {
                    bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
                    mSettings.mPermissions.put(perm.name, bp);
                }
                if (perm.gids != null) {
                    bp.setGids(perm.gids, perm.perUser);
                }
            }

            ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
            for (int i=0; i<libConfig.size(); i++) {
                mSharedLibraries.put(libConfig.keyAt(i),
                        new SharedLibraryEntry(libConfig.valueAt(i), null));
            }

            mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

            mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));

            // Clean up orphaned packages for which the code path doesn't exist
            // and they are an update to a system app - caused by bug/32321269
            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) {
                requestCopyPreoptedFiles();
            }

            String customResolverActivity = Resources.getSystem().getString(
                    R.string.config_customResolverActivity);
            if (TextUtils.isEmpty(customResolverActivity)) {
                customResolverActivity = null;
            } else {
                mCustomResolverComponentName = ComponentName.unflattenFromString(
                        customResolverActivity);
            }

            long startTime = SystemClock.uptimeMillis();

            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

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

            final String bootClassPath = System.getenv("BOOTCLASSPATH");
            final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

            if (bootClassPath == null) {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            if (systemServerClassPath == null) {
                Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
            }

            final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
            final String[] dexCodeInstructionSets =
                    getDexCodeInstructionSets(
                            allInstructionSets.toArray(new String[allInstructionSets.size()]));

            /** * Ensure all external libraries have had dexopt run on them. */
            if (mSharedLibraries.size() > 0) {
                // NOTE: For now, we're compiling these system "shared libraries"
                // (and framework jars) into all available architectures. It's possible
                // to compile them only when we come across an app that uses them (there's
                // already logic for that in scanPackageLI) but that adds some complexity.
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
                        final String lib = libEntry.path;
                        if (lib == null) {
                            continue;
                        }

                        try {
                            // Shared libraries do not have profiles so we perform a full
                            // AOT compilation (if needed).
                            int dexoptNeeded = DexFile.getDexOptNeeded(
                                    lib, dexCodeInstructionSet,
                                    getCompilerFilterForReason(REASON_SHARED_APK),
                                    false /* newProfile */);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
                                        getCompilerFilterForReason(REASON_SHARED_APK),
                                        StorageManager.UUID_PRIVATE_INTERNAL,
                                        SKIP_SHARED_LIBRARY_CHECK);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Library not found: " + lib);
                        } catch (IOException | InstallerException e) {
                            Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                    + e.getMessage());
                        }
                    }
                }
            }

            File frameworkDir = new File(Environment.getRootDirectory(), "framework");

            final VersionInfo ver = mSettings.getInternalVersion();
            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);

            // when upgrading from pre-M, promote system app permissions from install to runtime
            mPromoteSystemApps =
                    mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

            // When upgrading from pre-N, we need to handle package extraction like first boot,
            // as there is no profiling data available.
            mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

            mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;

            // save off the names of pre-existing system packages prior to scanning; we don't
            // want to automatically grant runtime permissions for new system apps
            if (mPromoteSystemApps) {
                Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
                while (pkgSettingIter.hasNext()) {
                    PackageSetting ps = pkgSettingIter.next();
                    if (isSystemApp(ps)) {
                        mExistingSystemPackages.add(ps.name);
                    }
                }
            }

            // Collect vendor 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.
            String overlayThemeDir = SystemProperties.get(VENDOR_OVERLAY_THEME_PROPERTY);
            if (!overlayThemeDir.isEmpty()) {
                scanDirTracedLI(new File(VENDOR_OVERLAY_DIR, overlayThemeDir), mDefParseFlags
                        | PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR
                        | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
            }
            scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

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

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

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

            // Collect all vendor packages.
            File vendorAppDir = new File("/vendor/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
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

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

            // Collect all Regionalization packages form Carrier's res packages.
            if (RegionalizationEnvironment.isSupported()) {
                Log.d(TAG, "Load Regionalization vendor apks");
                final List<File> RegionalizationDirs =
                        RegionalizationEnvironment.getAllPackageDirectories();
                for (File f : RegionalizationDirs) {
                    File RegionalizationSystemDir = new File(f, "system");
                    // Collect packages in <Package>/system/priv-app
                    scanDirLI(new File(RegionalizationSystemDir, "priv-app"),
                            PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR
                            | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
                    // Collect packages in <Package>/system/app
                    scanDirLI(new File(RegionalizationSystemDir, "app"),
                            PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,
                            scanFlags, 0);
                    // Collect overlay in <Package>/system/vendor
                    scanDirLI(new File(RegionalizationSystemDir, "vendor/overlay"),
                            PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,
                            scanFlags | SCAN_TRUSTED_OVERLAY, 0);
                }
            }

            // Prune any system packages that no longer exist.
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
            if (!mOnlyCore) {
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /* * If this is not a system app, it can't be a * disable system app. */
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }

                    /* * If the package is scanned, it's not erased. */
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) {
                        /* * If the system app is both scanned and in the * disabled packages list, then it must have been * added via OTA. Remove it from the currently * scanned package so the previously user-installed * application can be scanned. */
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            logCriticalInfo(Log.WARN, "Expecting better updated system app for "
                                    + ps.name + "; removing system app. Last known codePath="
                                    + ps.codePathString + ", installStatus=" + ps.installStatus
                                    + ", versionCode=" + ps.versionCode + "; scanned versionCode="
                                    + scannedPkg.mVersionCode);
                            removePackageLI(scannedPkg, true);
                            mExpectingBetter.put(ps.name, ps.codePath);
                        }

                        continue;
                    }

                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        logCriticalInfo(Log.WARN, "System package " + ps.name
                                + " no longer exists; it's data will be wiped");
                        // Actual deletion of code and data will be handled by later
                        // reconciliation step
                    } else {
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }

            //look for any incomplete package installations
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            for (int i = 0; i < deletePkgsList.size(); i++) {
                // Actual deletion of code and data will be handled by later
                // reconciliation step
                final String packageName = deletePkgsList.get(i).name;
                logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
                synchronized (mPackages) {
                    mSettings.removePackageLPw(packageName);
                }
            }

            //delete tmp files
            deleteTempPackageFiles();

            // Remove any shared userIDs that have no associated packages
            mSettings.pruneSharedUsersLPw();

            if (!mOnlyCore) {
                /* add for PresetApp begin */
                if (ZSFeature.ZEUSIS_FEATURE_PRESETAPP) {
                    scanDirLI(mPresetApp.mDir, 0 , scanFlags, 0);
                    scanDirLI(mPresetApp.mDir_cust, 0 , scanFlags, 0);
                    scanDirLI(mPresetApp.mDir_cust_common, 0 , scanFlags, 0);
                }
                /* add for PresetApp end */
                EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                        SystemClock.uptimeMillis());
                scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);

                scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
                        | PackageParser.PARSE_FORWARD_LOCK,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);

                scanDirLI(mEphemeralInstallDir, mDefParseFlags
                        | PackageParser.PARSE_IS_EPHEMERAL,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);

             .............

a.创建一个PMS.Settings对象,在该对象的构造函数中,将给成员静态赋值,这些变量包括:

  • mSettingFilename,赋值为/data/system/packages.xml.
  • mBackupSettingFilename,赋值为/data/system/package-backup.xml.
  • mPackageListFilename,赋值为/data/system/package.list

    b.调用mSettings.addShared UserLP()添加四个共享用户id。

    c.创建一个Installer对象,该对象辅助程序的安装,比如完成从APK文件提取出dex文件,删除dex文件等操作。installer对象内部其实包含LocalSocket对象,所有Installer提供的API接口,内部其实会通过改LocalSocket发送一系列参数值给远程的SocketServer对象。创建好Installer对象之后,调用ping()函数,确保Socket的服务端准备就绪。

d.给一下几个数据文件路径静态赋值,包括:
– mAppDataDir:代表程序的数据目录,其值为/data/data/.
– msecureAppDataDir:所谓的数据解密区,并没有被使用,其值为/data/secure/data/

e.调用readPermission()函数,从、system/etc/permissions目录下读取全部的XML文件,这些文件主要定义了两部分系统属性。第一是系统中所有的feature,第二是为一些native系统进程分配一些特定的权限,读出的属性值保存到mSetting.mPermissions变量中,该函数是PMS的一个重要的功能函数。

f.调用mSettings对象的readLP()函数从/data/packages.xml文件读取所有应用程序中和包管理相关的信息,这些信息保存到mSettings.mPackages变量中。

g.对Java系统中的文件进行dex提取(转换)。在Android系统中,Java源码变异后的Class文件不能直接执行,Android中的编译器会将程序中的Class文件转换成一个dex文件。转换后的文件和原始的Class文件有几点优势,比如节省了字节码,优化了内存分配,重新组织了函数映射表。
Java系统中的库文件包含三部分。
Java Boot路径下的所有文件,Boot路径是指在调用getProp(“java.boot.class.path”),获取的路径,获取的路径以冒号为分隔符。
共享库路径:该路径是指在platform.xml中使用的library标签定义的jar文件。
Framework目录下的所有APK和Jar文件,不过要除去framework-res.apk
h.为三个程序目录分别创建一个FileObserver,FileObserver对象内部会检测目录的添加、删除文件的事件,并当事件发生时,执行相应的操作。比如,当目录中添加文件时,就会调用scanPackageLI(file,…)函数扫描添加的文件,注意该函数的参数,PMS中存在另一个同名函数,其第一个参数是Package类型,而次参数为File类型。
这三个目录如下:

  • /system/framework Framework相关程序
  • /system/app Android自带的程序
  • /vender/app 第三方程序

    i.调用scanDirLI()扫描(解析程序中的AndroidManifest.xml)以上三个目录中多余的程序文件,冰枪扫描结果保存到PMS中的mPackages变量中。
    j.删除已经不存在的程序对应的数据记录,mPackages保存着以上三个文件目录列表,mSettings.mPackages中保存着 安装后的数据记录,因此如果mPackages.contain()函数返回false,则意味着以上三个目录的某个程序被删除,于是调用mInstaller.remove()删除对应的目录。
    k.清除没有安装成功的数据记录。调用mSetting.getListOFIncompleteInstallPackages()函数获取没有成功安装的包列表,然后使用for循环,盗用cleanupInstallFailedPackages()逐个清楚这些记录。
    l.为以下两个目录分别添加FoleObserver,并调用scanDirLI(),解析目录下的所有程序,解析结果将保存在mPackage变量中,以下两个目录:

  • /data/app
  • /data/data-private
    m.调用deletetempPackageFiles删除/data/app、目录下的以vmdl开头以及以.tmp结尾的文件。
    n.如果系统版本升级,调用updatePermissionLP()重新赋予权限。
    p.调用mSettings.writeLP()将mSettings.mPackages中的数据值重新写入packages.xml文件中。
    原文作者:一抹夕阳815
    原文地址: https://blog.csdn.net/linliang815/article/details/76640262
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞