程序包管理主要包含三个部分内容。
一、包管理概述。
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的内部类被定义。关系图如下:
由图可以看出,内部settings类把汗了包管理全部信息。
1.包属性信息
int mExterbalSdkPlatform:上同
2.用户id相关信息
HashMap < String,ShareUserSetting >mSharedUsers:该变量保存了所有共享id的信息,来源于packages.xml的标签。
ArrayListmPedingPackages:当PMS解析packages.xml文件时,如果发现某个package标签中使用的是shareUserId,则暂时把该package添加到mPendingPackage列表中,知道最后解析完毕shared-user标签后,再完善原来的package标签中的信息。
3.权限管理相关信息
ArrayList< Signature >mPastSignatures:保存了所有签名信息
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主体启动过程
主体启动过程就是指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 permConfig
= systemConfig.getPermissions();
for (int i=0; iif (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 libConfig = systemConfig.getSharedLibraries();
for (int i=0; inew 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 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 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 RegionalizationDirs =
RegionalizationEnvironment.getAllPackageDirectories();
for (File f : RegionalizationDirs) {
File RegionalizationSystemDir = new File(f, "system");
// Collect packages in /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 /system/app
scanDirLI(new File(RegionalizationSystemDir, "app"),
PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR,
scanFlags, 0);
// Collect overlay in /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 possiblyDeletedUpdatedSystemApps = new ArrayList();
if (!mOnlyCore) {
Iterator 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 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对象,在该对象的构造函数中,将给成员静态赋值,这些变量包括:
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类型。
这三个目录如下:
/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变量中,以下两个目录: