PackageManagerService也是有ServerThread启动的,运行在system_process进程。
我们先来看下PackageManagerService是怎么启动的:
PackageManagerService的启动需要四个参数,context上下文环境信息由ActivityManagerService获取,installer是一个安装器,是对install程序的一个封装,在new一个Installer之后会调用ping命令测试是否能连接的上install的服务端。
再来看一下PackageManagerService的初始化流程:
相关代码:
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;
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(context);//新建一个Settings结构
mSettings.addSharedUserLPw("android.uid.system", //添加一些用户id
Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM);
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;//在ServerThread中创建,调用了其中的ping测试是否连上
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);//获取WINDOW_SERVICE
Display d = wm.getDefaultDisplay();//获取显示参数
d.getMetrics(mMetrics);
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
mHandlerThread.start();//启动消息处理循环
mHandler = new PackageHandler(mHandlerThread.getLooper());//PackageHandler封装了对消息的处理
File dataDir = Environment.getDataDirectory();///data
mAppDataDir = new File(dataDir, "data");//待检测目录/data/data
mAppInstallDir = new File(dataDir, "app");///data/app
mAppLibInstallDir = new File(dataDir, "app-lib");///data/app-lib
mAsecInternalPath = new File(dataDir, "app-asec").getPath();///data/app-asec
mUserAppDataDir = new File(dataDir, "user");///data/user
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");///data/app-private
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);//创建一个UserManagerService
readPermissions();//读取权限配置文件中的信息,保存到全局变量
mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));
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.
int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;//设置扫描模式
if (mNoDexOpt) {
Slog.w(TAG, "Running ENG build: no pre-dexopt!");
scanMode |= SCAN_NO_DEX;
}
final HashSet libFiles = new HashSet();
mFrameworkDir = new File(Environment.getRootDirectory(), "framework");///system/framework
mDalvikCacheDir = new File(dataDir, "dalvik-cache");///data/dalvik-cache
boolean didDexOpt = false;
/**
* Out of paranoia, ensure that everything in the boot class
* path has been dexed.
*/
String bootClassPath = System.getProperty("java.boot.class.path");//所有在bootClassPath目录的类已经优化了
if (bootClassPath != null) {//确保 boot路径的class都被优化了
String[] paths = splitString(bootClassPath, ':');
for (int i=0; i 0) {//确保 外部库也被 优化
Iterator libs = mSharedLibraries.values().iterator();
while (libs.hasNext()) {
String lib = libs.next();
try {
if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
libFiles.add(lib);
mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
didDexOpt = true;
}
} 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());
}
}
}
// Gross hack for now: we know this file doesn't contain any
// code, so don't dexopt it to avoid the resulting log spew.
libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");//framework-res.apk没有包含代码,不需要优化
/**
* 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 = mFrameworkDir.list();
if (frameworkFiles != null) {
for (int i=0; i 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) {//系统app
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.
*///如果系统app刚被扫描并且在disabled列表,则它肯定是通过ota添加的,从当前扫描的package中移除它,所以以前用户安装的可以被扫描到
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
Slog.i(TAG, "Expecting better updatd system app for " + ps.name
+ "; removing system app");
removePackageLI(ps, true);
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
psit.remove();
String msg = "System package " + ps.name
+ " no longer exists; wiping its data";
reportSettingsProblem(Log.WARN, msg);
removeDataDirsLI(ps.name);
} 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未安装完全的package
ArrayList deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
for(int i = 0; i < deletePkgsList.size(); i++) {
//clean up here
cleanupInstallFailedPackage(deletePkgsList.get(i));//移除安装失败的package
}
//delete tmp files
deleteTempPackageFiles();//移除临时文件
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
mAppInstallObserver = new AppDirObserver(
mAppInstallDir.getPath(), OBSERVER_EVENTS, false);
mAppInstallObserver.startWatching();//监控/data/app目录
scanDirLI(mAppInstallDir, 0, scanMode, 0);//扫描该目录下的package
mDrmAppInstallObserver = new AppDirObserver( //DRM,英文全称Digital Rights Management, 可以翻译为:内容数字版权加密保护技术
mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
mDrmAppInstallObserver.startWatching();//监控/data/app-private目录
scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,//扫描该目录下的package
scanMode, 0);
/**
* Remove disable package settings for any updated system
* apps that were removed via an OTA. If they're not a
* previously-updated app, remove them completely.
* Otherwise, just revoke their system-level permissions.
*/
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
String msg;
if (deletedPkg == null) {
msg = "Updated system package " + deletedAppName
+ " no longer exists; wiping its data";
removeDataDirsLI(deletedAppName);
} else {
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
+ deletedAppName;
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
reportSettingsProblem(Log.WARN, msg);
}
} else {
mAppInstallObserver = null;
mDrmAppInstallObserver = null;
}
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
// If the platform SDK has changed since the last time we booted,
// we need to re-grant app permission to catch any new ones that
// appear. This is really a hack, and means that apps can in some
// cases get permissions that the user didn't initially explicitly
// allow... it would be nice to have some better way to handle
// this situation.
final boolean regrantPermissions = mSettings.mInternalSdkPlatform
!= mSdkVersion;
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 //赋予package相应请求的权限
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
// can downgrade to reader
mSettings.writeLPr();//写/data/system/packages.xml
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
// 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();
mRequiredVerifierPackage = getRequiredVerifierLPr();
} // synchronized (mPackages)
} // synchronized (mInstallLock)
}
PackageManagerService的初始化工作都是在它的构造函数中完成的,主要完成一下任务:
1、 添加一些用户id,如system、phone等;
2、 建立并启动PackageHandler消息循环,用于处理apk安装请求如adbinstall packageinstaller安装apk时就会发送消息;
3、 解析/system/etc/permission下的xml文件,主要是platform.xml,建立permission和gid之间的关系,可以指定一个权限与几个组对应,当一个apk被授予这个权限时它也同时属于这几个组,readPermission(parser, perm);给一些底层用户分配一些权限,如shell授予各种permission,把一个权限赋予一个uid,当apk使用这个uid运行时,就具备了这个权限系统增加的一些应用需要link的扩展的jar库,系统每增加一个硬件,都要添加相应的featrue,将解析结果放入mAvailableFeatures;
4、 检查/data/system/packages.xml是否存在,里面记录了系统的ppermission,以及每个apk的name,codePath,flags,ts,version,userid等,这些信息主要是通过apk安装的时候解析AndroidManifest.xml获取到的,解析完apk后将更新信息写入这个文件并保存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中,当有apk安装,升级,删除时会更新这个文件;
5、 检查BootClassPath,mSharedLibraries及/system/framework下的jar是否需要dexopt,需要则通过dexopt进行优化,这里面主要是调用mInstaller.dexopt进行相应的优化;
6、 建立 java 层的 installer 与 c 层的 installd 的 socket 联接,使得在上层的 install,remove,dexopt等功能最终由installd在底层实现;
7、 启动AppDirObserver线程往中监测/system/framework,/system/app,/data/app/data/app-private目录的事件,主要监听add和remove事件,对于目录监听底层通过innotify机制实现,inotify是一种文件系统的变化通知机制如文件增加、删除等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持,当有add event时调用scanPackageLI(File,int,int)处理,当有remove event时调用removePackageLI处理;
8、 调用scanDirLI启动apk解析,解析目录包括:/system/framework、/system/app、/vendor/app、/data/app、/data/app-private;
9、 移除临时文件;
10、 赋予package相应请求的权限;
11、 将解析出的Package的相关信息保存到相关全局变量,还有文件。
下面来分析前面每一步大概都做了些什么:
一、添加用户:
添加用户调用的是Settings的addSharedUserLPw
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
return s;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
s = new SharedUserSetting(name, pkgFlags);//新建一个SharedUserSetting结构
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {//保存到mUserIds或mOtherUserIds
mSharedUsers.put(name, s);//添加到mSharedUsers
return s;
}
return null;
}
首先检查mSharedUsers中是否有这个用户,没有的话则新建一个SharedUserSetting,调用addUserIdLPw保存到mUserIds或mOtherUserIds,并添加到mSharedUsers。
private boolean addUserIdLPw(int uid, Object obj, Object name) {
if (uid > Process.LAST_APPLICATION_UID) {//大于应用程序最大pid
return false;
}
if (uid >= Process.FIRST_APPLICATION_UID) {//uid大于应用程序id的起始值
int N = mUserIds.size();
final int index = uid - Process.FIRST_APPLICATION_UID;
while (index >= N) {//先添加元素,后面设置值
mUserIds.add(null);
N++;
}
if (mUserIds.get(index) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate user id: " + uid
+ " name=" + name);
return false;
}
mUserIds.set(index, obj);//把该uid和对应的PackageSetting保存
} else {//系统用户
if (mOtherUserIds.get(uid) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
+ " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);//添加到mOtherUserIds
}
return true;
}
二、建立并启动PackageHandler消息循环
PackageHandler用来处理安装apk等过程中的各种消息,后面降到apk安装的时候会涉及到。
这个比较简单,主要就新建一个PackageHandler,用来处理消息。
三、解析/system/etc/permission下的xml文件
主要是读取并解析/etc/permissions的xml文件,如我的平板上面:
看一下读取的流程:
相关代码:
void readPermissions() {//从/etc/permission读取权限配置信息
// Read permissions from .../etc/permission directory.
File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
Slog.w(TAG, "No directory " + libraryDir + ", skipping");
return;
}
if (!libraryDir.canRead()) {
Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
return;
}
// Iterate over the files in the directory and scan .xml files
for (File f : libraryDir.listFiles()) {
// We'll read platform.xml last
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
continue;
}
if (!f.getPath().endsWith(".xml")) {
Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
continue;
}
if (!f.canRead()) {
Slog.w(TAG, "Permissions library file " + f + " cannot be read");
continue;
}
readPermissionsFromXml(f);
}
// Read permissions from .../etc/permissions/platform.xml last so it will take precedence
final File permFile = new File(Environment.getRootDirectory(),
"etc/permissions/platform.xml");//最后读取
readPermissionsFromXml(permFile);
}
readPermissions先读取除platform.xml的其他文件,并调用readPermissionsFromXml进行解析,继续看一下readPermissionsFromXml
private void readPermissionsFromXml(File permFile) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
} catch (FileNotFoundException e) {
Slog.w(TAG, "Couldn't find or open permissions file " + permFile);
return;
}
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(permReader);
XmlUtils.beginDocument(parser, "permissions");
while (true) {
XmlUtils.nextElement(parser);
if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
break;
}
String name = parser.getName();
if ("group".equals(name)) {
String gidStr = parser.getAttributeValue(null, "gid");
if (gidStr != null) {
int gid = Integer.parseInt(gidStr);
mGlobalGids = appendInt(mGlobalGids, gid);//保存到mGlobalGids
} else {
Slog.w(TAG, " without gid at "
+ parser.getPositionDescription());
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("permission".equals(name)) {//定义了权限和组id(gid)的关系,该组拥有什么权限
String perm = parser.getAttributeValue(null, "name");//权限地名字
if (perm == null) {
Slog.w(TAG, " without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
readPermission(parser, perm);//进一步解析,解析结果保存到 mSettings.mPermissions
} else if ("assign-permission".equals(name)) {//那一个uid都拥有什么权限(把什么权限赋予哪个uid)
String perm = parser.getAttributeValue(null, "name");//获取权限名
if (perm == null) {
Slog.w(TAG, " without name at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
String uidStr = parser.getAttributeValue(null, "uid");//获取用户名
if (uidStr == null) {
Slog.w(TAG, " without uid at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
int uid = Process.getUidForName(uidStr);//该用户名对应的uid
if (uid < 0) {
Slog.w(TAG, " with unknown uid \""
+ uidStr + "\" at "
+ parser.getPositionDescription());
XmlUtils.skipCurrentTag(parser);
continue;
}
perm = perm.intern();
HashSet perms = mSystemPermissions.get(uid);//从mSystemPermissions查找是否已为该uid分配权限
if (perms == null) {
perms = new HashSet();
mSystemPermissions.put(uid, perms);//添加到mSystemPermissions
}
perms.add(perm);//添加 该权限
XmlUtils.skipCurrentTag(parser);
} else if ("library".equals(name)) {//系统共享库
String lname = parser.getAttributeValue(null, "name");
String lfile = parser.getAttributeValue(null, "file");
if (lname == null) {
Slog.w(TAG, " without name at "
+ parser.getPositionDescription());
} else if (lfile == null) {
Slog.w(TAG, " without file at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got library " + lname + " in " + lfile);
mSharedLibraries.put(lname, lfile);//添加到mSharedLibraries
}
XmlUtils.skipCurrentTag(parser);
continue;
} else if ("feature".equals(name)) {//系统特征 (壁纸等)
String fname = parser.getAttributeValue(null, "name");
if (fname == null) {
Slog.w(TAG, " without name at "
+ parser.getPositionDescription());
} else {
//Log.i(TAG, "Got feature " + fname);
FeatureInfo fi = new FeatureInfo();
fi.name = fname;
mAvailableFeatures.put(fname, fi);//添加到mAvailableFeatures
}
XmlUtils.skipCurrentTag(parser);
continue;
} else {
XmlUtils.skipCurrentTag(parser);
continue;
}
}
permReader.close();
} catch (XmlPullParserException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
} catch (IOException e) {
Slog.w(TAG, "Got execption parsing permissions.", e);
}
}
readPermissionsFromXml主要是:
1、读取permission name添加到mSettings.mPermissions
2、读取gid添加到mSettings.mPermissions
readPermissionsFromXml:
permission
a、读取permission name添加到mSettings.mPermissions
b、读取gid添加到mSettings.mPermissions
assign-permission
a、设置相应uid所具有的权限,保存到mSystemPermissions
library
a、.jar包保存到mSharedLibraries
feature
a、 硬件相关信息保存到mAvailableFeatures
我们来看一下platform.xml:
这个文件是模拟器上的,/etc/permissions下的其他文件还有定义该硬件的特性等。
四、解析系统已经安装的包
检查/data/system/packages.xml是否存在,第一次开机的时候该文件不存在,而以后每次系统如果有apk变动如新apk安装、删除、更新等,都会将相关信息记录到该文件。这个会一定程度加快系统的启动速度,但影响不大,先看一下流程图:
这里把有关setting相关的流程都画出来的,apk信息的读取是通过readLPw来完成的。
boolean readLPw(List users) {//packages-backup.xml存在则从它读取,不存在在从packages.xml读取
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {///data/system/packages-backup.xml存在
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()) {///data/system/packages.xml也存在 则删除它
// If both the backup and setutings 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) {///data/system/packages-backup.xml不存在
if (!mSettingsFilename.exists()) {//packages.xml不存在则返回
mReadMessages.append("No settings file found\n");
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
readDefaultPreferredAppsLPw(0);
return false;
}
str = new FileInputStream(mSettingsFilename);//获取一个输入流/data/system/packages.xml
}
XmlPullParser parser = Xml.newPullParser();//新建一个xml解析器
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");
Log.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")) {//解析系统中存在的package,以及该包的一些相关信息
readPackageLPw(parser);
} else if (tagName.equals("permissions")) {//解析系统定义了哪些权限,由那个包定义的,构建BasePermission结构都添加到mPermissions
readPermissionsLPw(mPermissions, parser);
} else if (tagName.equals("permission-trees")) {
readPermissionsLPw(mPermissionTrees, parser);
} else if (tagName.equals("shared-user")) {//解析系统中可被用户共享的一些uid所拥有的权限
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("updated-package")) {//更新的apk
readDisabledSysPackageLPw(parser);
} else if (tagName.equals("cleaning-package")) {//删除的apk
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")) {//重命名的apk
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) {
}
} else if (tagName.equals("verifier")) {
final String deviceIdentity = parser.getAttributeValue(null, "device");
try {
mVerifierDeviceIdentity = VerifierDeviceIdentity.parse(deviceIdentity);
} catch (IllegalArgumentException e) {
Slog.w(PackageManagerService.TAG, "Discard invalid verifier device id: "
+ e.getMessage());
}
} else if (TAG_READ_EXTERNAL_STORAGE.equals(tagName)) {
final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
mReadExternalStorageEnforced = "1".equals(enforcement);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under : "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
str.close();
} catch (XmlPullParserException e) {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
} catch (java.io.IOException e) {
mReadMessages.append("Error reading: " + e.toString());
PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e);
Log.wtf(PackageManagerService.TAG, "Error reading package manager settings", e);
}
final int N = mPendingPackages.size();//共享了uid的package
for (int i = 0; i < N; i++) {
final PendingPackage pp = mPendingPackages.get(i);//获取PendingPackage结构
Object idObj = getUserIdLPr(pp.sharedId);//获取被共享的uid的SharedUserSetting结构
if (idObj != null && idObj instanceof SharedUserSetting) {
PackageSetting p = getPackageLPw(pp.name, null, pp.realName, //新建一个PackageSetting结构
(SharedUserSetting) idObj, pp.codePath, pp.resourcePath,
pp.nativeLibraryPathString, pp.versionCode, pp.pkgFlags,
null, true /* add */, false /* allowInstall */); //add标志为true,需要添加到mPackages
if (p == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unable to create application package for " + pp.name);
continue;
}
p.copyFrom(pp);//重新赋值该package的一些信息(在前面解析的)
} else if (idObj != null) {
String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ pp.sharedId + " that is not a shared uid\n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
} else {
String msg = "Bad package setting: package " + pp.name + " has shared uid "
+ pp.sharedId + " that is not defined\n";
mReadMessages.append(msg);
PackageManagerService.reportSettingsProblem(Log.ERROR, msg);
}
}
mPendingPackages.clear();//所以的都处理完了,清空
if (mBackupStoppedPackagesFilename.exists()///data/system/packages-stopped-backup.xml
|| mStoppedPackagesFilename.exists()) { ///data/system/packages-stopped.xml
// Read old file
readStoppedLPw();
mBackupStoppedPackagesFilename.delete();
mStoppedPackagesFilename.delete();
// Migrate to new file format
writePackageRestrictionsLPr(0);
} else {
if (users == null) {
readPackageRestrictionsLPr(0);
} else {
for (UserInfo user : users) {
readPackageRestrictionsLPr(user.id);//读取该user的限制
}
}
}
/*
* Make sure all the updated system packages have their shared users
* associated with them.
*///确保所有已更新的系统packages有他们的共享用户关联他们
final Iterator disabledIt = mDisabledSysPackages.values().iterator();
while (disabledIt.hasNext()) {
final PackageSetting disabledPs = disabledIt.next();
final Object id = getUserIdLPr(disabledPs.appId);
if (id != null && id instanceof SharedUserSetting) {
disabledPs.sharedUser = (SharedUserSetting) id;
}
}
mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
+ mSharedUsers.size() + " shared uids\n");
return true;
}
解析/data/system/packages.xml,看一下模拟器的已经启动一次后的这个文件
主要是一些permissions、package、shared-user的解析,具体的解析过程就不分析,主要是:
permissions:构造权限结构BasePermission添加到mPermissions
package:解析每个已经安装apk的name,codePath,sharedUserId,userId,version等,调用addPackageLP构建PackageSetting并添加到mPackages
shared-user:readSharedUserLP通过addSharedUserLP添加一个SharedUserSetting结构,再通过readGrantedPermissionsLP读取给这个userId赋予的权限
五、建立 java 层的 installer 与 c 层的 installd 的 socket 连接。
Apk的安装是通过mInstaller来完成的,主要是一些目录的创建等。
我们看一下相关的流程图
Install 是一个后台进程:
在启动他的时候会创建一个"installd"的套接字,并等待客户端的连接
而但客户端的install要执行一个命令时,以dexopt为例:
public int dexopt(String apkPath, int uid, boolean isPublic) {
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
builder.append(' ');
builder.append(uid);
builder.append(isPublic ? " 1" : " 0");
return execute(builder.toString());
}
调用execute,execute会调用connect连接服务端,这里也不多讲了,比较简单。
六、检查相关需要优化的目录
主要是mSharedLibraries、/system/framework、外部库等
String bootClassPath =System.getProperty("java.boot.class.path");//所有在bootClassPath目录的类已经优化了
if (bootClassPath != null) {//确保 boot路径的class都被优化了
String[] paths = splitString(bootClassPath, ':');
for (int i=0; i 0) {//确保 外部库也被 优化
Iterator libs = mSharedLibraries.values().iterator();
while (libs.hasNext()) {
String lib = libs.next();
try {
if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
libFiles.add(lib);
mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
didDexOpt = true;
}
} 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());
}
}
}
// Gross hack for now: we know this file doesn't contain any
// code, so don't dexopt it to avoid the resulting log spew.
libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");//framework-res.apk没有包含代码,不需要优化
/**
* 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 = mFrameworkDir.list();
if (frameworkFiles != null) {
for (int i=0; i
七、启动AppDirObserver线程往中监测
这些检测的目录包括/system/framework,/system/app,/data/app/data/app-private等,这里的,相关知识参考AppDirObserver介绍
八、调用scanDirLI启动apk解析
Apk安装的流程比较复杂,后面会专门讲解,这里看一下scanDirLI的流程
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
String[] files = dir.list();//获取该目录下的文件
if (files == null) {
Log.d(TAG, "No files in app dir " + dir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + dir);
}
int i;
for (i=0; i
主要是对该目录下面的所有文件,首先判断其是否是apk文件,是则调用scanPackageLI进行安装,安装失败的话则还要删除文件
九、移除临时文件
通过调用deleteTempPackageFiles来完成
private void deleteTempPackageFiles() {
final FilenameFilter filter = new FilenameFilter() {//创建一个过滤器,以vmdl开始,tmp结束的文件
public boolean accept(File dir, String name) {
return name.startsWith("vmdl") && name.endsWith(".tmp");
}
};
deleteTempPackageFilesInDirectory(mAppInstallDir, filter);//删除/data/app满足条件的文件
deleteTempPackageFilesInDirectory(mDrmAppPrivateInstallDir, filter);//删除/data/app-private下满足条件的文件
删除/data/app目录下以vmdl开始,tmp结束的文件
十、赋予package相应请求的权限
updatePermissionsLPw用来给apk赋权限
updatePermissionsLPw(null,null,UPDATE_PERMISSIONS_ALL | (regrantPermissions ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
: 0));
注意这里有一个UPDATE_PERMISSIONS_ALL
private void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, int flags) {
// Make sure there are no dangling permission trees.
Iterator 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) {//还未解析该package
// 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) {//还是为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)) {//检查其他package是否使用了这个包的权限
Slog.i(TAG, "Removing old permission: " + bp.name//一般的权限定义都属于android这个包
+ " 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) {//更新所有package的权限
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0);//赋予package要求的权限
}
}
}
if (pkgInfo != null) {
grantPermissionsLPw(pkgInfo, (flags&UPDATE_PERMISSIONS_REPLACE_PKG) != 0);//更新某个package权限
}
}
调用grantPermissionsLPw赋予某个apk请求的权限
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) {
final PackageSetting ps = (PackageSetting) pkg.mExtras;
if (ps == null) {
return;
}
final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
HashSet origPermissions = gp.grantedPermissions;
boolean changedPermission = false;
if (replace) {
ps.permissionsFixed = false;
if (gp == ps) {
origPermissions = new HashSet(gp.grantedPermissions);
gp.grantedPermissions.clear();
gp.gids = mGlobalGids;
}
}
if (gp.gids == null) {
gp.gids = mGlobalGids;
}
final int N = pkg.requestedPermissions.size();//请求哪些权限
for (int i=0; i
如果允许授予相应的权限,则添加到grantedPermissions
十一、 将解析出的Package的相关信息保存到文件
主要是把已经安装的apk信息写回文件
相关代码:
void writeLPr() {
//Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024);
// Keep the old settings around until we know the new ones have
// been successfully written.
if (mSettingsFilename.exists()) {///data/system/packages.xml存在
// Presence of backup settings file indicates that we failed
// to persist settings earlier. So preserve the older
// backup for future reference since the current settings
// might have been corrupted.
if (!mBackupSettingsFilename.exists()) {///data/system/packages-backup.xml不存在
if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {//packages.xml重命名为packages-backup.xml
Log.wtf(PackageManagerService.TAG, "Unable to backup package manager settings, "
+ " current changes will be lost at reboot");
return;
}
} else {
mSettingsFilename.delete();
Slog.w(PackageManagerService.TAG, "Preserving older settings backup");
}
}
mPastSignatures.clear();
try {
FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
BufferedOutputStream str = new BufferedOutputStream(fstr);
//XmlSerializer serializer = XmlUtils.serializerInstance();
XmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, "utf-8");
serializer.startDocument(null, true);
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "packages");//写packages标签
serializer.startTag(null, "last-platform-version");//写版本信息
serializer.attribute(null, "internal", Integer.toString(mInternalSdkPlatform));
serializer.attribute(null, "external", Integer.toString(mExternalSdkPlatform));
serializer.endTag(null, "last-platform-version");
if (mVerifierDeviceIdentity != null) {
serializer.startTag(null, "verifier");
serializer.attribute(null, "device", mVerifierDeviceIdentity.toString());
serializer.endTag(null, "verifier");
}
if (mReadExternalStorageEnforced != null) {
serializer.startTag(null, TAG_READ_EXTERNAL_STORAGE);
serializer.attribute(
null, ATTR_ENFORCEMENT, mReadExternalStorageEnforced ? "1" : "0");
serializer.endTag(null, TAG_READ_EXTERNAL_STORAGE);
}
serializer.startTag(null, "permission-trees");
for (BasePermission bp : mPermissionTrees.values()) {
writePermissionLPr(serializer, bp);//写permissonTree
}
serializer.endTag(null, "permission-trees");
serializer.startTag(null, "permissions");
for (BasePermission bp : mPermissions.values()) {
writePermissionLPr(serializer, bp);//写permisson
}
serializer.endTag(null, "permissions");
for (final PackageSetting pkg : mPackages.values()) {
writePackageLPr(serializer, pkg);//写Packages
}
for (final PackageSetting pkg : mDisabledSysPackages.values()) {
writeDisabledSysPackageLPr(serializer, pkg);//写DisabledSysPackages
}
for (final SharedUserSetting usr : mSharedUsers.values()) {//写shared-user
serializer.startTag(null, "shared-user");
serializer.attribute(null, ATTR_NAME, usr.name);
serializer.attribute(null, "userId",
Integer.toString(usr.userId));
usr.signatures.writeXml(serializer, "sigs", mPastSignatures);
serializer.startTag(null, "perms");
for (String name : usr.grantedPermissions) {
serializer.startTag(null, TAG_ITEM);
serializer.attribute(null, ATTR_NAME, name);
serializer.endTag(null, TAG_ITEM);
}
serializer.endTag(null, "perms");
serializer.endTag(null, "shared-user");
}
if (mPackagesToBeCleaned.size() > 0) {//要被清除的package
for (PackageCleanItem item : mPackagesToBeCleaned) {
final String userStr = Integer.toString(item.userId);
serializer.startTag(null, "cleaning-package");
serializer.attribute(null, ATTR_NAME, item.packageName);
serializer.attribute(null, ATTR_CODE, item.andCode ? "true" : "false");
serializer.attribute(null, ATTR_USER, userStr);
serializer.endTag(null, "cleaning-package");
}
}
if (mRenamedPackages.size() > 0) {//重命名的package
for (Map.Entry e : mRenamedPackages.entrySet()) {
serializer.startTag(null, "renamed-package");
serializer.attribute(null, "new", e.getKey());
serializer.attribute(null, "old", e.getValue());
serializer.endTag(null, "renamed-package");
}
}
serializer.endTag(null, "packages");
serializer.endDocument();
str.flush();
FileUtils.sync(fstr);
str.close();
// New settings successfully written, old ones are no longer
// needed.
mBackupSettingsFilename.delete();
FileUtils.setPermissions(mSettingsFilename.toString(),
FileUtils.S_IRUSR|FileUtils.S_IWUSR
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
// Write package list file now, use a JournaledFile.
//
File tempFile = new File(mPackageListFilename.toString() + ".tmp");//写/data/system/packages.list
JournaledFile journal = new JournaledFile(mPackageListFilename, tempFile);
fstr = new FileOutputStream(journal.chooseForWrite());
str = new BufferedOutputStream(fstr);
try {
StringBuilder sb = new StringBuilder();
for (final PackageSetting pkg : mPackages.values()) {//所有的package信息
ApplicationInfo ai = pkg.pkg.applicationInfo;
String dataPath = ai.dataDir;
boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
// Avoid any application that has a space in its path
// or that is handled by the system.
if (dataPath.indexOf(" ") >= 0 || ai.uid < Process.FIRST_APPLICATION_UID)
continue;
// we store on each line the following information for now:
//
// pkgName - package name
// userId - application-specific user id
// debugFlag - 0 or 1 if the package is debuggable.
// dataPath - path to package's data path
//
// NOTE: We prefer not to expose all ApplicationInfo flags for now.
//
// DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
// FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
// system/core/run-as/run-as.c
//
sb.setLength(0);
sb.append(ai.packageName);
sb.append(" ");
sb.append((int)ai.uid);
sb.append(isDebug ? " 1 " : " 0 ");
sb.append(dataPath);
sb.append("\n");
str.write(sb.toString().getBytes());
}
str.flush();
FileUtils.sync(fstr);
str.close();
journal.commit();
} catch (Exception e) {
IoUtils.closeQuietly(str);
journal.rollback();
}
FileUtils.setPermissions(mPackageListFilename.toString(),
FileUtils.S_IRUSR|FileUtils.S_IWUSR
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
writeAllUsersPackageRestrictionsLPr();//将一些限制 写回文件
return;
} catch(XmlPullParserException e) {
Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ "current changes will be lost at reboot", e);
} catch(java.io.IOException e) {
Log.wtf(PackageManagerService.TAG, "Unable to write package manager settings, "
+ "current changes will be lost at reboot", e);
}
// Clean up partially written files
if (mSettingsFilename.exists()) {
if (!mSettingsFilename.delete()) {
Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: "
+ mSettingsFilename);
}
}
//Debug.stopMethodTracing();
}
这个函数也比较简单,主要是把前面解析出来的信息重新保存到文件,因为这时的信息可能跟开始packages.xml不一样了。
到这里,PackageManagerService就已经初始化完成了,以后有Package的变动都会在PackageManagerService中反应出来,我们也可以查询Activity、Service、Provider等的信息。