PackageManagerService比较长,我们挑主要的内容讲,这是这个系列的第一篇博客,我们主要介绍下构造函数以及一些对象。
一、SystemServer创建PackageManagerService
先来看下其在SystemServer的创建:
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
......
mPackageManagerService.performBootDexOpt();
......
try {
mPackageManagerService.systemReady();
} catch (Throwable e) {
reportWtf("making Package Manager Service ready", e);
}
我们来看下PackageManagerService的main函数:
public static final PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
ServiceManager.addService("package", m);
return m;
}
main函数就是new了一个PackageManagerService然后把它加入ServiceManager中。
二、PackageManagerService构造函数
2.1 Settings
下面我们主要分析PackageManagerService的构造函数:
mSettings = new Settings(context);//新建Settings
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,//往Settings中添加SharedUserSetting
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
我们还是挑主要的讲,在构造函数中新建了Setting类,然后又调用了addSharedUserLPw函数。
我们先看Settings类:
Settings(Context context) {
this(context, Environment.getDataDirectory());
}
Settings(Context context, File dataDir) {
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
mSettingsFilename = new File(mSystemDir, "packages.xml");
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
Settings类在data目录下创建了system目录,然后分别保存了下面文件。
1.packages.xml:记录系统中所有安装的应用的信息, 我们来看下这个文件关于一个package
<package name="com.android.providers.media" codePath="/system/priv-app/MediaProvider" nativeLibraryPath="/system/priv-app/MediaProvider/lib" publicFlags="944291397" privateFlags="8" ft="15659d595e8" it="15659d595e8" ut="15659d595e8" version="800" sharedUserId="10006">
<sigs count="1">
<cert index="2" key="308204a830820390a003020102020900f2b98e6123572c4e300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f6964311
</sigs>
<perms>
<item name="android.permission.ACCESS_CACHE_FILESYSTEM" granted="true" flags="0" />
<item name="android.permission.WRITE_SETTINGS" granted="true" flags="0" />
<item name="android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS" granted="true" flags="0" />
<item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
<item name="android.permission.WRITE_MEDIA_STORAGE" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
<item name="android.permission.UPDATE_DEVICE_STATS" granted="true" flags="0" />
<item name="android.permission.ACCESS_ALL_DOWNLOADS" granted="true" flags="0" />
<item name="android.permission.ACCESS_DOWNLOAD_MANAGER" granted="true" flags="0" />
<item name="android.permission.MANAGE_USERS" granted="true" flags="0" />
<item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.ACCESS_MTP" granted="true" flags="0" />
<item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />
<item name="android.permission.CLEAR_APP_CACHE" granted="true" flags="0" />
<item name="android.permission.CONNECTIVITY_INTERNAL" granted="true" flags="0" />
<item name="android.permission.MODIFY_NETWORK_ACCOUNTING" granted="true" flags="0" />
<item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
<item name="android.permission.UPDATE_APP_OPS_STATS" granted="true" flags="0" />
</perms>
<proper-signing-keyset identifier="4" />
</package>
2.packages-backup.xml:上面文件的备份
3.packages-stopped.xml:被强制停止运行的应用信息
4.packages-stopped-backup.xml:上面文件的备份
5.packages.list:保存普通应用的数据目录和uid信息等
......
com.android.managedprovisioning 10009 0 /data/data/com.android.managedprovisioning platform 3003
com.android.gifviewer 10042 0 /data/data/com.android.gifviewer default none
com.android.dreams.phototable 10054 0 /data/data/com.android.dreams.phototable default none
com.leadcore.telassistant 1000 0 /data/data/com.leadcore.telassistant platform 3002,1023,1015,3003,3001
com.android.noisefield 10049 0 /data/data/com.android.noisefield default none
com.android.smspush 10064 0 /data/data/com.android.smspush default none
com.leadcore.codescan 10029 0 /data/data/com.leadcore.codescan platform 3003
com.android.wallpaper.livepicker 10046 0 /data/data/com.android.wallpaper.livepicker platform none
jp.co.omronsoft.openwnn 10051 0 /data/data/jp.co.omronsoft.openwnn default none
com.android.settings 1000 0 /data/data/com.android.settings platform 3002,1023,1015,3003,3001
com.leadcore.logservice 1000 0 /data/data/com.leadcore.logservice platform 3002,1023,1015,3003,3001
com.android.calculator2 10032 0 /data/data/com.android.calculator2 default none
com.leadcore.userfeedback 10062 0 /data/data/com.leadcore.userfeedback platform 3003
com.leadcore.filesearch 10035 0 /data/data/com.leadcore.filesearch default none
com.iflytek.inputmethod 10041 0 /data/data/com.iflytek.inputmethod default 3002,3003,3001
org.simalliance.openmobileapi.uiccterminal 10061 0 /data/data/org.simalliance.openmobileapi.uiccterminal platform none
com.android.wallpaper 10045 0 /data/data/com.android.wallpaper default none
com.android.vpndialogs 10018 0 /data/data/com.android.vpndialogs platform none
com.android.email 10031 0 /data/data/com.android.email default 3003
com.android.music 10048 0 /data/data/com.android.music platform 3002,1023,1015,3003
com.android.phone 1001 0 /data/data/com.android.phone platform 3002,3003,3001
com.android.shell 2000 0 /data/data/com.android.shell platform 3002,1023,1015,3008
com.android.video 10063 0 /data/data/com.android.video platform 1023,1015,3003
com.android.providers.userdictionary 10000 0 /data/data/com.android.providers.userdictionary default 3003
com.android.location.fused 1000 0 /data/data/com.android.location.fused platform 3002,1023,1015,3003,3001
com.android.deskclock 1000 0 /data/data/com.android.deskclock platform 3002,1023,1015,3003,3001
com.android.systemui 10017 0 /data/data/com.android.systemui platform 3002,1023,1015,3001,3006
......
当Android对文件packages.xml和packages-stopped.xml写之前,会先把它们备份,如果写文件成功了,再把备份文件删除掉。如果写的时候,系统出问题重启了,重启后会读取这两个文件时,发现有备份文件,会使用备份文件的内容,因为这个时候原文件已经损坏了。
每个应用的信息会保存在PackageSetting中,而所有的PackageSetting对象会保存在Settings的成员变量mPackages中。
回到构造函数,在Settings添加了SharedUserSetting,6种系统的uid:system radio log nfc bluetooth shell。相同shareUserId的包可以运行在一个进程中。
2.2 SystemConfig
继续分析构造函数:
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
SystemConfig构造函数中会去读取etc下面的各个文件分析
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), false);
// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), false);
// Only read features from OEM config
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), true);
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), true);
}
分析完了后,会保存在各个成员变量中。
我们看下system/etc/permissions/platform.xml的一部分内容
......
<permission name="android.permission.MANAGE_VOICE_KEYPHRASES">
<group gid="audio" />
</permission>
<permission name="android.permission.ACCESS_FM_RADIO" >
<group gid="media" />
</permission>
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- The following tags are assigning high-level permissions to specific
user IDs. These are used to allow specific core system users to
perform the given operations with the higher-level framework. For
example, we give a wide variety of permissions to the shell user
since that is the user the adb shell runs under and developers and
others should have a fairly open environment in which to
interact with the system. -->
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
......
继续分析,会创建一个消息线程,会创建一些目录
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
File dataDir = Environment.getDataDirectory();//存放应用数据目录
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");//放应用
mAppLib32InstallDir = new File(dataDir, "app-lib");//native库
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");//存放用户数据
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
前面systemconfig解析etc下的文件,然后将Permissions放在mSettings的mPermission,以及共享库放在mSharedLibraries中
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.gids = appendInts(bp.gids, perm.gids);
}
}
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));
}
2.3 readLPw函数
继续分析,调用了Settings的readLPw函数。
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
我们来详细分析,先会去看packages-backup.xml有没有,有这个文件说明在写packages.xml的时候系统出问题了,所以在系统启动的时候就要读备份的想xml文件内容。如果没有这个备份文件再去看packages.xml, 然后再去解析xml文件,把解析出来的内容封装在各个对象中保存在mSettings中各个变量中。
boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,
boolean onlyCore) {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {//是否有备份文件
try {
str = new FileInputStream(mBackupSettingsFilename);
mReadMessages.append("Reading from backup settings file\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"Need to read from backup settings file");
if (mSettingsFilename.exists()) {
// If both the backup and settings file exist, we
// ignore the settings since it might have been
// corrupted.
Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
+ mSettingsFilename);
mSettingsFilename.delete();
}
} catch (java.io.IOException e) {
// We'll try for the normal settings file.
}
}
mPendingPackages.clear();
mPastSignatures.clear();
try {
if (str == null) {//这里为空,代表没有备份文件,就看packages.xml文件
if (!mSettingsFilename.exists()) {
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
mFingerprint = Build.FINGERPRINT;
return false;
}
str = new FileInputStream(mSettingsFilename);
}
XmlPullParser parser = Xml.newPullParser();
parser.setInput(str, null);
int type;
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}
if (type != XmlPullParser.START_TAG) {
mReadMessages.append("No start tag found in settings file\n");
PackageManagerService.reportSettingsProblem(Log.WARN,
"No start tag found in package manager settings");
Slog.wtf(PackageManagerService.TAG,
"No start tag found in package manager settings");
return false;
}
int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals("package")) {
readPackageLPw(parser);//解析packages.xml中的各内容
} else if (tagName.equals("permissions")) {
readPermissionsLPw(mPermissions, parser);
} else if (tagName.equals("permission-trees")) {
readPermissionsLPw(mPermissionTrees, parser);
} else if (tagName.equals("shared-user")) {
readSharedUserLPw(parser);
} else if (tagName.equals("preferred-packages")) {
// no longer used.
} else if (tagName.equals("preferred-activities")) {
// Upgrading from old single-user implementation;
// these are the preferred activities for user 0.
readPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals(TAG_PERSISTENT_PREFERRED_ACTIVITIES)) {
// TODO: check whether this is okay! as it is very
// similar to how preferred-activities are treated
readPersistentPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals(TAG_CROSS_PROFILE_INTENT_FILTERS)) {
// TODO: check whether this is okay! as it is very
// similar to how preferred-activities are treated
readCrossProfileIntentFiltersLPw(parser, 0);
} else if (tagName.equals("updated-package")) {
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {
String name = parser.getAttributeValue(null, ATTR_NAME);
String userStr = parser.getAttributeValue(null, ATTR_USER);
String codeStr = parser.getAttributeValue(null, ATTR_CODE);
if (name != null) {
int userId = 0;
boolean andCode = true;
try {
if (userStr != null) {
userId = Integer.parseInt(userStr);
}
} catch (NumberFormatException e) {
}
if (codeStr != null) {
andCode = Boolean.parseBoolean(codeStr);
}
addPackageToCleanLPw(new PackageCleanItem(userId, name, andCode));
}
} else if (tagName.equals("renamed-package")) {
String nname = parser.getAttributeValue(null, "new");
String oname = parser.getAttributeValue(null, "old");
if (nname != null && oname != null) {
mRenamedPackages.put(nname, oname);
}
} else if (tagName.equals("last-platform-version")) {
mInternalSdkPlatform = mExternalSdkPlatform = 0;
try {
String internal = parser.getAttributeValue(null, "internal");
if (internal != null) {
mInternalSdkPlatform = Integer.parseInt(internal);
}
String external = parser.getAttributeValue(null, "external");
if (external != null) {
mExternalSdkPlatform = Integer.parseInt(external);
}
} catch (NumberFormatException e) {
}
mFingerprint = parser.getAttributeValue(null, "fingerprint");
} else if (tagName.equals("database-version")) {
mInternalDatabaseVersion = mExternalDatabaseVersion = 0;
try {
String internalDbVersionString = parser.getAttributeValue(null, "internal");
if (internalDbVersionString != null) {
mInternalDatabaseVersion = Integer.parseInt(internalDbVersionString);
}
String externalDbVersionString = parser.getAttributeValue(null, "external");
if (externalDbVersionString != null) {
mExternalDatabaseVersion = Integer.parseInt(externalDbVersionString);
}
} catch (NumberFormatException ignored) {
}
} else if (tagName.equals("verifier")) {
final String deviceIdentity = parser.getAttributeValue(null, "device");
try {
mVerifierDeviceIdentity = VerifierDev
......
2.4 扫描文件(转化格式,获取文件信息)
下面开始优化dex文件变成oat文件,记录开始扫描系统的时间。
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;
final ArraySet<String> alreadyDexOpted = new ArraySet<String>();//已经优化的文件集合
/**
* Add everything in the in the boot class path to the
* list of process files because dexopt will have been run
* if necessary during zygote startup.
*/
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
if (bootClassPath != null) {
String[] bootClassPathElements = splitString(bootClassPath, ':');
for (String element : bootClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
if (systemServerClassPath != null) {
String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
for (String element : systemServerClassPathElements) {
alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
}
下面扫描动态库和framework下的文件执行dex到odex的转换
*/
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 {
byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
dexCodeInstructionSet,
false);
if (dexoptRequired != DexFile.UP_TO_DATE) {
alreadyDexOpted.add(lib);
// The list of "shared libraries" we have at this point is
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);//到intalld执行
} else {
mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);//art虚拟机执行oat
}
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
} catch (IOException e) {
Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
+ e.getMessage());
}
}
}
}
File frameworkDir = new File(Environment.getRootDirectory(), "framework");//framework目录
// Gross hack for now: we know this file doesn't contain any
// code, so don't dexopt it to avoid the resulting log spew.
alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");
// Gross hack for now: we know this file is only part of
// the boot class path for art, so don't dexopt it to
// avoid the resulting log spew.
alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");
/**
* And there are a number of commands implemented in Java, which
* we currently need to do the dexopt on so that they can be
* run from a non-root shell.
*/
String[] frameworkFiles = frameworkDir.list();
if (frameworkFiles != null) {
// TODO: We could compile these only for the most preferred ABI. We should
// first double check that the dex files for these commands are not referenced
// by other system apps.
for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
// Skip the file if we already did it.
if (alreadyDexOpted.contains(path)) {
continue;
}
// Skip the file if it is not a type we want to dexopt.
if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
continue;
}
try {
byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
dexCodeInstructionSet,
false);
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
} else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
} catch (IOException e) {
Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
}
扫描各个目录下的文件信息,保存在PMS中。
scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
// Find base frameworks (resource packages without code).
scanDirLI(frameworkDir, 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");
scanDirLI(privilegedAppDir, 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");
scanDirLI(systemAppDir, 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
}
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
// Collect all OEM packages.
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
还有一些,扫描并删除未成功安装的apk包,删除临时文件,升级应用的一些处理,更新应用动态库路径。
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
for(int i = 0; i < deletePkgsList.size(); i++) {
//clean up here
cleanupInstallFailedPackage(deletePkgsList.get(i));//删除未成功安装的apk包
}
//delete tmp files
deleteTempPackageFiles();//删除临时文件
// Remove any shared userIDs that have no associated packages
mSettings.pruneSharedUsersLPw();
if (!mOnlyCore) {//开始处理非系统应用
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
.....
最后有一个扫描时间结束的log。
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
2.5 赋予权限,写packages.xml
继续分析
final boolean regrantPermissions = mSettings.mInternalSdkPlatform
!= mSdkVersion;//因为sdk版本变化,permission的定义也改变了,需要重新赋予应用权限
if (regrantPermissions) Slog.i(TAG, "Platform changed from "
+ mSettings.mInternalSdkPlatform + " to " + mSdkVersion
+ "; regranting permissions for internal storage");
mSettings.mInternalSdkPlatform = mSdkVersion;
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
| (regrantPermissions//是否要重新赋权限
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
// If this is the first boot, and it is a normal boot, then
// we need to initialize the default preferred apps.
if (!mRestoredSettings && !onlyCore) {
mSettings.readDefaultPreferredAppsLPw(this, 0);
}
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
mIsUpgrade = !Build.FINGERPRINT.equals(mSettings.mFingerprint);
if (mIsUpgrade && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (String pkgName : mSettings.mPackages.keySet()) {
deleteCodeCacheDirsLI(pkgName);//如果是执行OTA后第一次启动,清除cache
}
mSettings.mFingerprint = Build.FINGERPRINT;
}
// All the changes are done during package scanning.
mSettings.updateInternalDatabaseVersion();//更新数据库
// can downgrade to reader
mSettings.writeLPr();//把mSettings写入packages.xml
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
mRequiredVerifierPackage = getRequiredVerifierLPr();
} // synchronized (mPackages)
} // synchronized (mInstallLock)
mInstallerService = new PackageInstallerService(context, this, mAppInstallDir);
// Now after opening every single application zip, make sure they
// are all flushed. Not really needed, but keeps things nice and
// tidy.
Runtime.getRuntime().gc();//启动垃圾回收
updatePermissionsLPw函数
private void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, int flags) {
// Make sure there are no dangling permission trees.
Iterator<BasePermission> it = mSettings.mPermissionTrees.values().iterator();
while (it.hasNext()) {
final BasePermission bp = it.next();
if (bp.packageSetting == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
}
if (bp.packageSetting == null) {
Slog.w(TAG, "Removing dangling permission tree: " + bp.name
+ " from package " + bp.sourcePackage);
it.remove();
} else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
Slog.i(TAG, "Removing old permission tree: " + bp.name
+ " from package " + bp.sourcePackage);
flags |= UPDATE_PERMISSIONS_ALL;
it.remove();
}
}
}
// Make sure all dynamic permissions have been assigned to a package,
// and make sure there are no dangling permissions.
it = mSettings.mPermissions.values().iterator();
while (it.hasNext()) {
final BasePermission bp = it.next();
if (bp.type == BasePermission.TYPE_DYNAMIC) {
if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name="
+ bp.name + " pkg=" + bp.sourcePackage
+ " info=" + bp.pendingInfo);
if (bp.packageSetting == null && bp.pendingInfo != null) {
final BasePermission tree = findPermissionTreeLP(bp.name);
if (tree != null && tree.perm != null) {
bp.packageSetting = tree.packageSetting;
bp.perm = new PackageParser.Permission(tree.perm.owner,
new PermissionInfo(bp.pendingInfo));
bp.perm.info.packageName = tree.perm.info.packageName;
bp.perm.info.name = bp.name;
bp.uid = tree.uid;
}
}
}
if (bp.packageSetting == null) {
// We may not yet have parsed the package, so just see if
// we still know about its settings.
bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage);
}
if (bp.packageSetting == null) {
Slog.w(TAG, "Removing dangling permission: " + bp.name
+ " from package " + bp.sourcePackage);
it.remove();
} else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) {
if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) {
Slog.i(TAG, "Removing old permission: " + bp.name
+ " from package " + bp.sourcePackage);
flags |= UPDATE_PERMISSIONS_ALL;
it.remove();
}
}
}
// Now update the permissions for all packages, in particular
// replace the granted permissions of the system packages.
if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {//flags为UPDATE_PERMISSIONS_ALL
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0,
changingPkg);
}
}
}
if (pkgInfo != null) {//传进来的pkgInfo为null
grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0, changingPkg);
}
}
我们再来看看grantPermissionsLPw函数
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace,
String packageOfInterest) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
ArraySet<String> origPermissions = gp.grantedPermissions;
boolean changedPermission = false;
if (replace) {
ps.permissionsFixed = false;
if (gp == ps) {
origPermissions = new ArraySet<String>(gp.grantedPermissions);
gp.grantedPermissions.clear();
gp.gids = mGlobalGids;
}
}
if (gp.gids == null) {
gp.gids = mGlobalGids;//把gid的群组赋值
}
final int N = pkg.requestedPermissions.size();
for (int i=0; i<N; i++) {
final String name = pkg.requestedPermissions.get(i);
final boolean required = pkg.requestedPermissionsRequired.get(i);
final BasePermission bp = mSettings.mPermissions.get(name);
if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp);
}
}
if (bp == null || bp.packageSetting == null) {
if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
Slog.w(TAG, "Unknown permission " + name
+ " in package " + pkg.packageName);
}
continue;
}
final String perm = bp.name;
boolean allowed;
boolean allowedSig = false;
if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {
// Keep track of app op permissions.
ArraySet<String> pkgs = mAppOpPermissionPackages.get(bp.name);
if (pkgs == null) {
pkgs = new ArraySet<>();
mAppOpPermissionPackages.put(bp.name, pkgs);
}
pkgs.add(pkg.packageName);
}
final int level = bp.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
if (level == PermissionInfo.PROTECTION_NORMAL
|| level == PermissionInfo.PROTECTION_DANGEROUS) {
// We grant a normal or dangerous permission if any of the following
// are true:
// 1) The permission is required
// 2) The permission is optional, but was granted in the past
// 3) The permission is optional, but was requested by an
// app in /system (not /data)
//
// Otherwise, reject the permission.
allowed = (required || origPermissions.contains(perm)
|| (isSystemApp(ps) && !isUpdatedSystemApp(ps)));
} else if (bp.packageSetting == null) {
// This permission is invalid; skip it.
allowed = false;
} else if (level == PermissionInfo.PROTECTION_SIGNATURE) {
allowed = grantSignaturePermission(perm, pkg, bp, origPermissions);
if (allowed) {
allowedSig = true;
}
} else {
allowed = false;
}
if (DEBUG_INSTALL) {
if (gp != ps) {
Log.i(TAG, "Package " + pkg.packageName + " granting " + perm);
}
}
if (allowed) {
if (!isSystemApp(ps) && ps.permissionsFixed) {
// If this is an existing, non-system package, then
// we can't add any new permissions to it.
if (!allowedSig && !gp.grantedPermissions.contains(perm)) {
// Except... if this is a permission that was added
// to the platform (note: need to only do this when
// updating the platform).
allowed = isNewPlatformPermissionForPackage(perm, pkg);
}
}
if (allowed) {
if (!gp.grantedPermissions.contains(perm)) {
changedPermission = true;
gp.grantedPermissions.add(perm);
gp.gids = appendInts(gp.gids, bp.gids);
} else if (!ps.haveGids) {
gp.gids = appendInts(gp.gids, bp.gids);
}
} else {
if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " because it was previously installed without");
}
}
} else {
if (gp.grantedPermissions.remove(perm)) {
changedPermission = true;
gp.gids = removeInts(gp.gids, bp.gids);
Slog.i(TAG, "Un-granting permission " + perm
+ " from package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
} else if ((bp.protectionLevel&PermissionInfo.PROTECTION_FLAG_APPOP) == 0) {
// Don't print warning for app op permissions, since it is fine for them
// not to be granted, there is a UI for the user to decide.
if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) {
Slog.w(TAG, "Not granting permission " + perm
+ " to package " + pkg.packageName
+ " (protectionLevel=" + bp.protectionLevel
+ " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags)
+ ")");
}
}
}
}
if ((changedPermission || replace) && !ps.permissionsFixed &&
!isSystemApp(ps) || isUpdatedSystemApp(ps)){
// This is the first that we have heard about this package, so the
// permissions we have now selected are fixed until explicitly
// changed.
ps.permissionsFixed = true;
}
ps.haveGids = true;
}
PMS的构造函数先读取保存在packages.xml中的内容保存在mSettings中,然后扫描设备中几个应用目录下的应用文件,并把扫描结果保存在PMS的mPackages成员变量中,通过对比上一次扫描的结果就是mSettings内容是否有被升级包覆盖的系统应用,如果有从mPackages去除。这样mPackages和mSettings的记录一致了,最后将本次扫描内容写到packages.xml文件中。
这样我们这节就讲完了,后面我们会详细讲解下每个函数,读取权限,扫描文件等。这里只是讲个大概框架。