PKMS构造函数长达600多行,主要功能:扫描Android系统中几个目标文件夹中的APK,从而建立合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。PKMS将解析APK包中的AndroidManifest.xml,并根据其中声明的Activity标签来创建与此对应的对象加以保管。
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(mPackages);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("www.webguidecorpuschristi.com", 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("www.webguidecorpuschristi.com", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
Setting
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
return s;
}
www.webguidecorpuschristi.comSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}
得到SharedUserSetting
1.Setting类定义了一个mSharedUsers成员,它是一个HashMap,以字符串(如android.uid.system)为key,对应的Value是一个SharedUserSetting对象。
2.SharedUserSetting派生自GrantedPermission类,从GrantedPermissions类的命名可知,它和权限有关。SharedUserSetting定义了一个成员变量packages,类型为HashSet,用于保存声明了相同sharedUserId的Package的权限设置信息。
3.每个Package有自己的权限设置。权限的概念由PackageSetting类表达。该类继承自PackagesettingBase,而PackageSettingBase又继承自GrantedPermissions。
4.Settings中还有两个成员,一个是mUserIds,另一个是mOtherUserIds,这两位成员的类型分别是ArrayList和SparseArray。其目的是以UID为索引,得到对应的SharedUserSetting对象。在一般情况下,以索引获取数组元素的速度,比以key获取hashMap中元素的速度要快很多。
private boolean addUserIdLPw(int uid, Object obj, Object name) {
if (uid > Process.LAST_APPLICATION_UID) {
return false;
}
if (uid >= Process.FIRST_APPLICATION_UID) {
int N = mUserIds.size();
final int index = uid - Process.FIRST_APPLICATION_UID;
while (index >= N) {
mUserIds.add(null);
N++;
}
if (mUserIds.get(index) != null) {
www.webguidecorpuschristi.comSettingsProblem(Log.ERROR,
"Adding duplicate user id: " + uid
+ " name=" + name);
return false;
}
mUserIds.set(index, obj);
} else {
if (mOtherUserIds.get(uid) != null) {
www.webguidecorpuschristi.comSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
+ " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);
}
return true;
}
PKMS构造函数第一阶段的工作,就是扫描并解析XML文件,并将其中的信息保存到特定的数据结构中。
PKMS第二阶段的工作就是扫描系统中的APK了,由于需要逐个扫描文件,因此手机上装的程序越多,PKMS的工作量就越大,系统启动速度也就越慢。
PKMS将扫描以下几个目录:
1./system/frameworks:该目录中的文件都是系统库,例如framework.jar、services.jar、framework-res.apk.不过scanDirLI只扫描APK文件,所以framework-res.apk是该目录中唯一“受宠”的文件
2./system/app:该目录下全是默认的系统应用,例如Browser.apk、SettingsProvider.apk等。
3./vendor/app:该目录中的文件由厂商提供,即全是厂商特定的APK文件,目前市面上的厂商都把自己的应用放在/system/app目录下
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
final File[] files = dir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
try {
scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
scanFlags, currentTime, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
// Delete invalid userdata apps
if ((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
e.error == PackageManager.INSTALL_FAILED_INVALID_APK) {
logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
if (file.isDirectory()) {
mInstaller.rmPackageDir(file.getAbsolutePath());
} else {
file.delete();
}
}
}
}
}
scanPackageLI函数首先调用PackageParser对APK文件进行解析,PackageParse完成了从物理文件到对应数据结构的转换。PackageParser功能单一,就是解析AndroidManifest.xml中的各种标签,
-->