1, 基本概念
PackageManagerService(简称PMS), 是android系统中一个核心的服务,
它负责系统中Package的管理,应该程序的安装、卸载等.在SystemServer的startBootstrapServices方法启动。
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
PMS的main方法如下,
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
ServiceManager.addService("package", m); // 注册
return m;
}
看来所有动作都在PMS的构造方法中完成的。
再看看PMS的结构可知,PMS服务也是一个Binder服务,
public class PackageManagerService extends IPackageManager.Stub {
在ActivityThread的getPackageManager方法中,可以获取PMS服务。
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
PMS的构造方法很长很长,主要包括以下逻辑
- 扫描目标文件夹之前的准备工作。
- 扫描目标文件夹。
- 扫描之后的工作。
2, 准备工作
PMS的构造方法关于Settings部分代码如下,
mSettings = new Settings(mPackages);
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);
mPackages是一个ArrayMap变量,
@GuardedBy("mPackages")
final ArrayMap<String, PackageParser.Package> mPackages =
new ArrayMap<String, PackageParser.Package>();
流程图如下,
2.1 Settings
Settings的构造方法如下,
Settings(Object lock) {
this(Environment.getDataDirectory(), lock);
}
Settings(File dataDir, Object lock) {
mLock = lock;
mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
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");
}
新建了5个文件夹,
private final File mSettingsFilename;
private final File mBackupSettingsFilename;
private final File mPackageListFilename;
private final File mStoppedPackagesFilename;
private final File mBackupStoppedPackagesFilename;
Environment.getDataDirectory()返回/data目录,然后创建/data/system/目录,并设置它的权限,
并 在/data/system目录中创建5个文件。packages.xml就是保存了系统所有的Package信息,
packages-backup.xml是packages.xml的备份,防止在写packages.xml突然断电等问题。
2.2 addSharedUserLPw
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
调用addSharedUserLPw将几种SharedUserId的名字和它对应的UID对应写到Settings当中。
关于 SharedUserId的使用,在后面介绍APK的安装过程中再来分析. Process中提供的UID列表如下,
public static final int ROOT_UID = 0;
public static final int SYSTEM_UID = 1000; // system
public static final int PHONE_UID = 1001;// telephony
public static final int SHELL_UID = 2000;// user shell
public static final int LOG_UID = 1007;// log group
public static final int WIFI_UID = 1010;// WIFI
•••
Settings中的addSharedUserLPw方法如下,
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
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, pkgPrivateFlags);
s.userId = uid;
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}
首先根据name, pkgFlags, pkgPrivateFlags等信息构造SharedUserSetting,然后添加到mSharedUsers的ArrayMap中。
final ArrayMap<String, SharedUserSetting> mSharedUsers =
new ArrayMap<String, SharedUserSetting>();
例如在SystemUI.apk的AndroidManifest.xml文件中,有关键代码:
<mainfest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.systemui"
coreApp="true"
android:sharedUserId="android.uid.system"
android:process="system">
在该标签中,声明了一个android:sharedUserId的属性,其值为“android.uid.system”。sharedUserId和UID有关,它的作用是
1,两个或者多个声明了同一种sharedUserid的APK可共享彼此的数据,并且可运行在同一进程中。
2,通过声明特定的sharedUserId,该APK所在的进程将被赋予指定UID。
例如SystemUI声明了system的uid,运行SystemUI的进程就可享有system用户所对应的权限了,实际上就是将该进程的UID设置为system的uid了
2.3 XML文件扫描
接下来是扫描系统目录下与系统权限相关的xml文件,新建文件,处理线程和Handler等。
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;
mPackageDexOptimizer = new PackageDexOptimizer(this);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());
getDefaultDisplayMetrics(context, mMetrics);
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
新建文件
File dataDir = Environment.getDataDirectory();
mAppDataDir = new File(dataDir, "data");
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mUserAppDataDir = new File(dataDir, "user");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
mRegionalizationAppInstallDir = new File(dataDir, "app-regional");
解析系统权限文件, 主要是解析系统目录下xml文件,获得设备相关的权限.
例如该设备是否支持蓝牙,wifi等
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.setGids(perm.gids, perm.perUser);
}
}