PackageManager功能介绍
Package Manager是Android的应用程序安装包(apk)管理器,功能如下:
- 权限处理,对系统和应用定义的Permission和Permission Group的增加、删除、查询、检查。
- 包处理,扫描安装、卸载APK包,查询包的UID、GID、包名、系统默认程序等信息。
- 比较两个包的Signatures是否相同。
- 查询Activity、Provider、Receiver、Services的信息。
- 查询Application、Package、Resource、Shard Library、Feature信息。
- Intent匹配
体系结构图
- 应用层 Market安装Google Market应用、PackageInstaller.apk 是
/packages/apps/PackageInstaller 目录下默认的apk,用于安装SD卡或内部存储设备上的APK安装包。 - 中间层 1.PackageManger和它的子类ApplicationPackageManager ,上层通过调用该API接口实现功能
2.ADB和pm命令,用来安装和卸载apk。最终实现都在PackageManagerService中。 - 服务层 PackageManagerService及相关类,一些具体的功能由Settings、Installer、FileObserver、DefaultContainerService等模块实现。
PackageManager类关系图
PackageManagerService启动
//frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...
startBootstrapServices()
...
}
startBootstrapServices(){
...
//mOnlyCore 系统属性加密状态,
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
//mFactoryTestMode 是否工厂模式,mOnlyCore系统属性是否加密
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
}
//frameworks/base/services/java/com/android/server/pm/PackageManagerService.java
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
return m;
}
在SystemService启动过程中,调用PackageManagerService的Main方法创建一个新对象,同时将该服务注册到ServiceManager中,注册名为package。
PackageManagerService初始化流程
加下来分析PackageManangerService的构造函数
1 创建并初始化Settings对象
分为两个步骤 :
- 创建Settings对象
- 增加默认共享ID
//frameworks/base/services/java/com/android/server/pm/PackageManagerService.java
//初始化Settings对象
mSettings = new Settings(mPackages);
//增加系统默认的6个UID
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);
看下Settings的构造函数
//frameworks/base/services/java/com/android/server/pm/Settings.java
Settings(File dataDir, Object lock) {
mLock = lock;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
mSystemDir = new File(dataDir, "system");
//创建data/system目录
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
//mSttingsFilename 代表 /system/data/packages.xml文件 ,记录系统中已安装apk的运行信息
mSettingsFilename = new File(mSystemDir, "packages.xml");
//mBackupSettingsFilename 代表 /system/data/packages-backup.xml文件,用于安装、卸载apk时,临时备份的文件
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
//mPackageListFilename 代表 /system/data/packages.list文件,用于记录已安装apk的简略信息
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
final File kernelDir = new File("/config/sdcardfs");
mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
}
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
// ArrayMap<String, SharedUserSetting> mSharedUsers,通过name索引
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.userId == uid) {
return s;
}
//只保存第一个Uid
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared user, keeping first: " + name);
return null;
}
//SharedUserSetting 保存的是名字、UID、应用类型
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}
private boolean addUserIdLPw(int uid, Object obj, Object name) {
Last_UID = 19999,表示应该程序最大的UID
if (uid > Process.LAST_APPLICATION_UID) {
return false;
}
FIRST_UID = 10000,表示应用程序最小UID
if (uid >= Process.FIRST_APPLICATION_UID) {
int N = mUserIds.size();
//index 用UID-10000,表示数组中的位置
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;
}
//ArrayList<Object> mUserIds ,存储大于10000的UID,按顺序排列,存储对象是SharedUserSetting
mUserIds.set(index, obj);
} else {
//SparseArray<Object> mOtherUserIds 存储小于10000的UID,按序排列,存储对象是SharedUserSetting
if (mOtherUserIds.get(uid) != null) {
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate shared id: " + uid
+ " name=" + name);
return false;
}
mOtherUserIds.put(uid, obj);
}
return true;
}
Setting初始化类图
在AdroidManifest.xml会声明 android:sharedUserId属性,概属性和UID有关,作用如下
- 声明同一个UID的APK可以共享数据,运行在统一进程内。
- 通过声明指定的UID,如android.uid.system,应用将会运行在制定的system进程内
。
2 获取系统默认配置
- 获得系统属性
ro.build.type 属性表示系统是eng、userdebug、user中哪个版本。如果是eng版本,不对apk文件进行dexopt操作。scanDirLI会根据该属性判断是否对APK进行obex优化。
/**debug.separate_processes 用于标记是否在独立进程中运行某个程序,
*根据该值设置mDefParseFlags、mSeparateProcesses,用于scanDirli扫描安装APK参数配置
*/
String separateProcesses = SystemProperties.get("debug.separate_processes");
- 获得系统默认显示参数
//获得屏幕默认显示参数,在scanDirLi扫描安装APK时使用,主要匹配APK中的asset和resource
mMetrics = new DisplayMetrics();
3 启动PackageHandler
//启动serviceThread去处理安装请求。
mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
//PackageManagerService内部类PakcageHandler
mHandler = new PackageHandler(mHandlerThread.getLooper());
//连接 DefaultContainerService服务
private boolean connectToService() {
//bind DefaultContainerService,PackageHandler中真正处理APK地方
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
if (mContext.bindServiceAsUser(service, mDefContainerConn,
Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
mBound = true;
return true;
}
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
return false;
}
//通过以下消息完成APK的复制、更名
switch (msg.what) {
case INIT_COPY:
case MCS_BOUND:
case MCS_RECONNECT:
case MCS_UNBIND:
case MCS_GIVE_UP:
case SEND_PENDING_BROADCAST:
case START_CLEANING_PACKAGE:
case POST_INSTALL:
....
}
4 创建data目录并初始化UserManagerServices(多用户)
File dataDir = Environment.getDataDirectory();
//表示 /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/app-private目录
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
//frameworks/base/services/java/com/android/server/pm/UserManagerServices.java
private UserManagerService(Context context, PackageManagerService pm,
UserDataPreparer userDataPreparer, Object packagesLock, File dataDir) {
mContext = context;
mPm = pm;
mPackagesLock = packagesLock;
mHandler = new MainHandler();
mUserDataPreparer = userDataPreparer;
synchronized (mPackagesLock) {
//表示 /data/system/user目录
mUsersDir = new File(dataDir, USER_INFO_DIR);
//创建 /data/system/user目录
mUsersDir.mkdirs();
// 表示 /data/system/user/0目录 用户0目录
File userZeroDir = new File(mUsersDir, String.valueOf(UserHandle.USER_SYSTEM));
//创建 /data/system/user/0目录
userZeroDir.mkdirs();
// 表示 /data/system/user/userlist.xml文件 关于所有用户的参数
mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
initDefaultGuestRestrictions();
readUserListLP();
sInstance = this;
}
mLocalService = new LocalService();
LocalServices.addService(UserManagerInternal.class, mLocalService);
mLockPatternUtils = new LockPatternUtils(mContext);
mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
}
private void readUserListLP() {
// /data/system/user/userlist.xml文件是否存在
if (!mUserListFile.exists()) {
//创建userlist.xml文件
fallbackToSingleUserLP();
return;
}
FileInputStream fis = null;
打开/data/system/user/userlist.xml文件,检索信息
AtomicFile userListFile = new AtomicFile(mUserListFile);
//读取用户ID
String id = parser.getAttributeValue(null, ATTR_ID);
//读取用户ID对应的 id.xml 文件,用户ID详细信息
UserData userData = readUserLP(Integer.parseInt(id));
//在mUsers存入对应的ID.xml信息
mUsers.put(userData.info.id, userData);
}
private void fallbackToSingleUserLP() {
int flags = UserInfo.FLAG_INITIALIZED;
//创建系统用户
UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
UserData userData = putUserInfo(system);
mNextSerialNumber = MIN_USER_ID;
mUserVersion = USER_VERSION;
Bundle restrictions = new Bundle();
//创建 /data/system/users/用户id.xml文件,关于该用户相关的参数
writeUserLP(userData);
//创建 /data/system/user/userlist.xml文件 ,所有用户的参数
writeUserListLP();
}
UserData类图
5 解析系统permission和feature信息
解析/system/etc/sysconfig 和 /system/etc/permission中的xml文件,包括platform.xml和系统支持的各种软硬件(feature)配置文件
- platform.xml
该文件用于定义底层进程的UID(User ID) 和GID (Group ID)和Android 定义的权限名之间的映射关系。在该文件中,一共有四种标签。
1.permission 2.group 3.assign-permission 4.library
group是permission 的子标签
assign-permission 位指定的用户ID分配指定的Android权限。
library 指定系统扩展库,也称共享库
<permissions>
<!--给指定的GID分配指定的权限-->
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
<!--给指定UID分配权限-->
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
<!--指定系统扩展库,扩展系统功能-->
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar" />
<!--允许在省电模式下联网应用-->
<allow-in-power-save package="com.android.providers.downloads" />
<!--允许在数据模式下联网应用-->
<allow-in-data-usage-save package="com.android.providers.downloads" />
<!--在后台自由运行的应用-->
<allow-in-power-save package="com.android.shell" />
<!--作为系统用户运行的应用-->
<system-user-whitelisted-app package="com.android.settings" />
<!--不能作为系统用户运行的应用-->
<system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
- feature配置文件
该文件用于设定设备支持的软硬件特性,硬件配置Hardware feature 文件 和 SoftWare feature配置文件。
- Hardware feature
用于配置Audio、Bluetooth、Camera、Location、Microphone、Nfc、Sensors、Screen、Telephony、USB、Wifi,每个配置文件都以android.hardware开头。
camera配置信息
/frameworks/native/data/etc/andorid.hardware.camera.autofocus.xml
<permissions>
<feature name="android.hardware.camera.any" />
<!--设备支持carmea-->
<feature name="android.hardware.camera" />
<!--设备支持自动对焦-->
<feature name="android.hardware.camera.autofocus" />
<!--设备支持闪光灯-->
<feature name="android.hardware.camera.flash" />
</permissions>
核心硬件配置文件以_core_hardware结尾,如handheld_core_hardware.xml和tablet_core_hardware.xml。包含各个硬件的xml文件。
- software feature声明
默认情况下支持SIP和VOIP两种软件特性,
通过该配置文件决定设备使用相应特性功能和API。
/frameworks/native/data/etc/android.software.sip.voip.xml
//该配置表示设备支持SIP和基于SIP的VOIP软件特性
<permissions>
<feature name="android.software.sip" />
<feature name="android.software.sip.voip" />
</permissions>
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
...
}
void readPermissions(File libraryDir, int permissionFlag) {
//解析各种标签
}
}
systemConfig类图
readPermissions具体解析过程
1.解析group标签,将其gid存入SystemConfid.mGlobalGids中,该标签指定所有包共有的全局GID,该标签默认未使用
2.解析permission标签,存入了ArrayMap<String, PermissionEntry> mPermissions,也存入了PackageMangerServices.mSettings.mPermissions中,以name为key值
3.解析assing-permission标签,以UID为key值,permission为value值,存入SystemConfig.mSystemPermissions中
4.解析library标签, 存入ArrayMap<String, String> mSharedLibraries SystemConfig.mSharedLibraries中,以name为key值,file文件位置为value值。
5.解析feature标签, 存入ArrayMap<String, FeatureInfo> SystemConfig.mAvailableFeatures,以name为key值,FeatureInfo(name属性和版本号)为value。
6.解析allow-in-power-save-except-idle,allow-in-power-save,allow-in-power-save…存入对应的数组
6 解析packages.xml文件
主要解析/data/system/packages.xml 文件,记录了系统的permission,已经安装apk的name、CodePath、flags、version、userid等信息。这写信息主要通过ScanDirLi方法解析APK的AndroidManifest.xml文件获取。当有apk安装、卸载时会更新该文件。
系统第一次启动时,packages.xml文件不存在,后续ScanDirLi扫描后才出现。
packages_backup.xml是 packages.xml 备份文件,每次更新packages.xml时,先将packages.xml改名为packages_backup.xml,再创建新的paclages.xml,创建成功后会删除packages_backup.xml。
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
boolean readLPw(@NonNull List<UserInfo> users){
if (tagName.equals("package")) {
//解析package标签
readPackageLPw(parser);
} else if (tagName.equals("permissions")) {
//解析permission标签
readPermissionsLPw(mPermissions, parser);
}.....
}
//解析 package标签。
private void readPackageLPw(XmlPullParser parser){
1.无shareUserId应用读取信息后,加入Settings.mPackages中,以包名为索引,便签内容为value。Uid>10000加入加入Settings.mUserIds中,根据UID排序。小于10000加入Settings.mOtherUserIds中,以UID排序,标签内容为value。
2.有shareUserId应用读取信息后,加入Settings.mPendingPackages中。
readLPw后续会读取mPendingPackages中的信息,将shareUserId应用ID设为shareUserId,,将share应用信息加入该应用,之后重新加入到Settings.mPackages中。
}
//解析permission标签
private void readPermissionsLPw(){
将信息存入Sttings.mPermissions中,以权限名为索引,vlaue包括包名,保护等级
}
}
7 调用scanDirLi扫描安装apk
扫描 Vendor/overlay/、/system/framework、/system/app、/system/priv-app、/vendor/app、/vendor/priv-app目录下的APK
如果是!OnlyCore还会扫描 /data/app 和/data/app-private目录。
- 系统级安装包:Vendor/overlay/、/system/framework、/system/app、/system/priv-app、/vendor/app、/vendor/priv-app都是系统级安装包,parseFlag都包含PackageParser.PARSE_IS_SYSTEM和
PackageParser.PARSE_IS_SYSTEM_DIR标签 - FORWARD_LOCK安装包:/data/app-private,parseFlag包含PackageParser.PARSE_FORWARD_LOCK标签,会做DRM保护处理,apk文件会存于/data/app-private目录,该目录受系统保护,一般apk在data/app下。该安装包会在/data/app目录下生成一个.zip包。zip中只有apk的res目录,AndroidManifest.xml和resources.arsc文件。无其他文件。起到保护apk资源目的
- 普通安装包:在data/app下,不给parseFlags传参数。
同时还会传递scanFlags,其中有SCAN_NO_DEX 即不进行dexopt优化。
后续详细分析 scanDirLi方法过程。
//扫描Vendor/overlay/目录
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);
//扫描/system/framework 目录
scanDirTracedLI(frameworkDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
//扫描/system/priv-app 目录
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);
//扫描 /system/app 目录
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirTracedLI(systemAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
//非只加载核心模块
if (!mOnlyCore) {
//扫描data/app目录
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
//扫描/data/app-private目录
scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
| PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
...
}
8 更新packages.xml文件
将更新信息写入到/data/system/packages.xml ,该文件就是mSettings中存储信息的持久化。
- 将存在的packages.xml改名为packages_backup.xml,将mSettings中信息写入packages.xml,写入完成后删除
packages_backup.xml文件 - 创建packages.list文件,遍历mPackages,写入包名、UID、文件位置,简略版的packages.xml。
mSettings.writeLPr();
mPermission -> <permission>标签
mPackages -> <package>标签
PMS初始化结束…END
重点方法scanDirLi后续分析。
参考资料
转载:https://blog.csdn.net/jinao8004/article/details/104735440