PakageManagerService是android系统中一个核心的服务,它负责系统中Package的管理,应该程序的安装、卸载等。后面PakageManagerService简称PMS。
2.SystemServer启动PackageManagerService我之前的ATA文章有说到,SystemServer进程是Zygote孵化出的第一个进程,该进程主要的工作是启动android系统服务进程,其中包括PackageManagerService服务,SystemServer启动PMS关键源码如下:
private void startBootstrapServices() {
//...
//调用PMS的main函数
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
//判断本次是否为初次启动,当Zygote或者SystemServer退出时,init会再次启动它们,所以这里
//的firstBoot指的是开机后的第一次启动
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
//...
}
关键点
- PMS的main函数,该函数是PKM的核心。
PackageManagerService的主要功能是,扫描Android系统中几个目标文件夹的APK,建立对应的数据结构来管理Package信息、四大组件信息、权限信息等各种信息。例如PKMS解析APK包中的AndroidMainfest.xml,并根据其中声明的Activity标签来创建对应的对象并加以保管。PMS的main方法的代码如下:
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
//new 一个PackageManagerService对象
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
//PKM注册到ServiceManager上。ServiceManager相当于安卓系统服务的DNS服务器
ServiceManager.addService("package", m);
return m;
}
该方法看似很简单,只有几行代码,然而执行事件却比较长,这是因为PMS在其构造函数中做了很多的“重体力活”,这也是android启动速度慢的主要因素之一。安装的应用越多,系统启动开机时间越长。PMS构造函数的主要工作流程
- 扫描目标文件夹之前的准备工作。
- 扫描目标文件夹。
- 扫描之后的工作。
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
if (mSdkVersion Process.LAST_APPLICATION_UID) {
return false;
}
//FIRST_APPLICATION_UID = 10000,属于应用APK
if (uid >= Process.FIRST_APPLICATION_UID) {
int N = mUserIds.size();
//计算索引,其值是uid和FIRST_APPLICATION_UID的差
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保存应用Package的uid,obj是SharedUserSettings
mUserIds.set(index, obj);
} else {
if (mOtherUserIds.get(uid) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
+ " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);
}
return true;
}
4.2 XML文件扫描
接下来是扫描系统目录下与系统权限相关的xml文件,将其存放到PKM中,关键源码如下:
// 获取系统相关的权限,它主要是解析系统目录下xml文件,获得设备相关的权限
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
//创建一个ThreadHandler对象,实际就是创建一个带消息队列循环处理的线程,
//该线程的工作是:程序的安装和卸载等。
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
//以ThreadHandler线程的消息循环(Looper对象)作为参数new一个
//PackageHandler,因此该Handler的handlemessage方法将运行在此线程上
mHandler = new PackageHandler(mHandlerThread.getLooper());
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
// /data目录
File dataDir = Environment.getDataDirectory();
// /data/data目录
mAppDataDir = new File(dataDir, "data");
// /data/app目录
mAppInstallDir = new File(dataDir, "app");
// /data/app-lib目录
mAppLib32InstallDir = new File(dataDir, "app-lib");
// /data/app-asec目录
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
// /data/user目录
mUserAppDataDir = new File(dataDir, "user");
// /data/app-private目录
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
//new一个UserManager对象,目前没有什么作用,但其前途不可限量。
//google设想,未来手机将支持多个User,每个User安装自己的应用
//该功能为android智能手机推向企业用户打下基础
sUserManager = new UserManagerService(context, this,
mInstallLock, mPackages);
// 获取系统相关的权限,它主要是解析系统目录下xml文件,获得设备相关的权限
ArrayMap permConfig
= systemConfig.getPermissions();
for (int i=0; i innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
//activity标签
if (tagName.equals("activity")) {
//解析activity标签
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, false,
owner.baseHardwareAccelerated);
//添加activity到owner.activities中
owner.activities.add(a);
//receiver标签
} else if (tagName.equals("receiver")) {
//解析receiver标签,receiver其实被当成Activity来解析了。
Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false);
if (a == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
//添加activity到owner.activities中
owner.receivers.add(a);
//service标签
} else if (tagName.equals("service")) {
//解析service标签
Service s = parseService(owner, res, parser, attrs, flags, outError);
if (s == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
//添加service到owner.services中
owner.services.add(s);
//provider标签
} else if (tagName.equals("provider")) {
Provider p = parseProvider(owner, res, parser, attrs, flags, outError);
if (p == null) {
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
return false;
}
owner.providers.add(p);
} else if (tagName.equals("activity-alias")) {
} else if (parser.getName().equals("meta-data")) {
} else if (tagName.equals("uses-library")) {
} else if (tagName.equals("uses-package")) {
}
}
}
在PackageParser扫描完一个APK后,此时系统已经根据APK中的AndroidMainifest.xml,创建了一个Package对象,下一步是将该Package加入到系统中。此时调用scanPackageDirtyLI方法,scanPackageDirtyLI首先会对packageName为“android”的apk做单独的处理,该apk其实就是framework-res.apk,它包含了几个常见的activity
- ChooserActivity:当startActivity有多个Acitvity符合时,系统会弹出此Acitivity,由用户选择合适的应用来处理
- ShutDownActivity:关机前弹出的选择对话框
- RingtonePickerAcitivity:铃声选择Activity
scanPackageDirtyLI关键代码如下:
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
final File scanFile = new File(pkg.codePath);
if (pkg.applicationInfo.getCodePath() == null ||
pkg.applicationInfo.getResourcePath() == null) {
// Bail out. The resource and code paths haven't been set.
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Code and resource paths haven't been set correctly");
}
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
} else {
// Only allow system apps to be flagged as core apps.
pkg.coreApp = false;
}
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
setUpCustomResolverActivity(pkg);
}
if (pkg.packageName.equals("android")) {
synchronized (mPackages) {
if (mAndroidApplication != null) {
//...
}
//保存该package信息
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
//保存该package的ApplicationInfo
mAndroidApplication = pkg.applicationInfo;
if (!mResolverReplaced) {
//mResolveActivity为ChooserActivity信息的ActivityInfo
mResolveActivity.applicationInfo = mAndroidApplication;
mResolveActivity.name = ResolverActivity.class.getName();
mResolveActivity.packageName = mAndroidApplication.packageName;
mResolveActivity.processName = "system:ui";
mResolveActivity.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
mResolveActivity.documentLaunchMode = ActivityInfo.DOCUMENT_LAUNCH_NEVER;
mResolveActivity.flags = ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
mResolveActivity.theme = R.style.Theme_Holo_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
//mResolveInfo用于存储系统解析Intent后得到的结果信息,在从PKM查询满足某个Intent的
//Activity时,返回的就是ResolveInfo,再根据ResolveInfo的activityInfo的信息得到 //Activity
mResolveInfo.activityInfo = mResolveActivity;
mResolveInfo.priority = 0;
mResolveInfo.preferredOrder = 0;
mResolveInfo.match = 0;
mResolveComponentName = new ComponentName(
mAndroidApplication.packageName, mResolveActivity.name);
}
}
}
}
“android“该Package与系统有非常重要的作用,这里保存特殊处理保存该Package的信息,主要是为了提高运行过程中的效率,例如ChooserActivity使用的地方非常多。接下里scanPackageDirtyLI方法会对系统其它的Package做处理,关键源码如下:
//mPackages用于保存系统内的所有Package,以packageName为key
if (mPackages.containsKey(pkg.packageName)
|| mSharedLibraries.containsKey(pkg.packageName)) {
//...
}
if ((scanFlags & SCAN_REQUIRE_KNOWN) != 0) {
if (mExpectingBetter.containsKey(pkg.packageName)) {
logCriticalInfo(Log.WARN,
"Relax SCAN_REQUIRE_KNOWN requirement for package " + pkg.packageName);
} else {
PackageSetting known = mSettings.peekPackageLPr(pkg.packageName);
if (known != null) {
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Examining " + pkg.codePath
+ " and requiring known paths " + known.codePathString
+ " & " + known.resourcePathString);
}
if (!pkg.applicationInfo.getCodePath().equals(known.codePathString)
|| !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,
"Application package " + pkg.packageName
+ " found at " + pkg.applicationInfo.getCodePath()
+ " but expected at " + known.codePathString + "; ignoring.");
}
}
}
}
// Initialize package source and resource directories
File destCodeFile = new File(pkg.applicationInfo.getCodePath());
File destResourceFile = new File(pkg.applicationInfo.getResourcePath());
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
if (!isSystemApp(pkg)) {
// Only system apps can use these features.
pkg.mOriginalPackages = null;
pkg.mRealPackage = null;
pkg.mAdoptPermissions = null;
}
//...
final String pkgName = pkg.packageName;
final long scanFileTime = scanFile.lastModified();
final boolean forceDex = (scanFlags & SCAN_FORCE_DEX) != 0;
//确定运行该package的进程名,一般用package作为进程名
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);
File dataPath;
if (mPlatformPackage == pkg) {
// The system package is special.
dataPath = new File(Environment.getDataDirectory(), "system");
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
// This is a normal package, need to make its data directory.
//该函数返回data/data/packageName
dataPath = Environment.getDataUserPackageDirectory(pkg.volumeUuid,
UserHandle.USER_OWNER, pkg.packageName);
boolean uidError = false;
if (dataPath.exists()) {
//..
} else {
if (DEBUG_PACKAGE_SCANNING) {
if ((parseFlags & PackageParser.PARSE_CHATTY) != 0)
Log.v(TAG, "Want this data dir: " + dataPath);
}
//该方法调用installer发送install命令,其实就是在/data/data/目录下建立packageName目录
//然后为系统所有的user安装此apk
int ret = createDataDirsLI(pkg.volumeUuid, pkgName, pkg.applicationInfo.uid,
pkg.applicationInfo.seinfo);
//安装错误
if (ret < 0) {
// Error from installer
throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
"Unable to create data dirs [errorCode=" + ret + "]");
}
}
pkgSetting.uidError = uidError;
}
final String path = scanFile.getPath();
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
//在/data/data/pageName/lib下建立和CPU类型对应的目录,例如ARM平台的事arm/,MIP平台的事mips/
if ((scanFlags & SCAN_NEW_INSTALL) == 0) {
derivePackageAbi(pkg, scanFile, cpuAbiOverride, true /* extract libs */);
//系统package的native库统一放在/system/lib下,
//所以系统不会提取系统package目录apk包中的native库
if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
pkg.applicationInfo.primaryCpuAbi == null) {
setBundledAppAbisAndRoots(pkg, pkgSetting);
setNativeLibraryPaths(pkg);
}
} else {
if ((scanFlags & SCAN_MOVE) != 0) {
//
setNativeLibraryPaths(pkg);
}
//...
if ((scanFlags & SCAN_NO_DEX) == 0) {
//对该APK做dex优化
int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */);
//如果该apk已经存在,要先杀掉该APK的进程
if ((scanFlags & SCAN_REPLACING) != 0) {
killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid, "replace pkg");
}
//在此之前,四大组件信息都是Package对象的私有的,在这里把它们注册到PKM内部的财产管理对象中。
//这样,PKMS就可对外提供统一的组件信息。
synchronized (mPackages) {
...
//注册该Package中的provider到PKM的mProviders上
int N = pkg.providers.size();
StringBuilder r = null;
int i;
for (i=0; i
关注
打赏