首语
PackageManagerService(以下简称PMS)是Android最核心的系统服务之一,它是应用程序包管理服务,管理手机上所有的应用程序,包括应用程序的安装、卸载、更新、应用信息的查询、应用程序的禁用和启用等。
职责
- 在Android系统启动过程中扫描特定目录下的APK文件解析。
- 负责三方应用的安装、卸载及各个应用的更新升级。
- 对外提供接口查询应用包信息或管理应用。
安装目录
系统应用安装目录
- system/app。这里存放的是系统自带的应用。
- system/priv-app。同上,但这里的应用会被授予特权权限,属于特权应用。
- vendor/app。存放的是odm或oem厂商定制的预制应用。
- vendor/app。同上,存放的也是特权应用。
这些应用不仅存放APK,还存放了APK运行需要的lib文件。这些路径下的应用不可卸载,会被授予系统级别的权限,调用系统级别的接口。
普通应用安装目录
- data/app。存放普通应用,即常说的三方应用。可以卸载。只能获得normal和dangerous级别的权限,这里的应用可以内置,也可以后续安装,安装时APK会被拷贝到此目录下,包括APK运行需要依赖的lib文件。
可执行文件保存目录
- data/dalvik-cache。应用程序安装的时候会将APK中的可执行文件拷贝到此目录下(dex文件是dalvik虚拟机的可执行文件,当然ART-Android Runtime的可执行文件格式是oat,启用ART时,系统会执行dex文件转换至oat文件)。
应用数据目录
- data/data。存放应用程序的相关数据,不论是三方应用还是系统应用。
应用注册表目录
- data/system。该目录下有两个重要的文件,一个是packages.xml,一个是packages.list,类似Windows的注册表。packages.xml记录了应用的各种信息,如应用包名、版本、安装路径、声明的各项权限等。packages.list记录了应用包名、userId、用户数据所在路径、SEInfo(应用程序安全上下文)、安装该应用的安装者等信息。当记录的应用信息有变化时将更新这些文件。下次开机时直接从里面读取相关信息添加到内存相关列表中,优化开机启动时间。
应用安装步骤
- PMS先扫描特定目录下的APK文件或拷贝APK文件至/data/app下,再对APK文件进行解析并生成对应的数据结构。
- PMS再将包名以及应用相关的四大组件等解析到的应用信息注册到PMS的记录文件中。
应用安装目的
PMS安装目的为了获取APK信息,然后进行缓存,PMS共有两级缓存:
- 一级缓存是在内存,是一个WatchedArrayMap,安装、卸载应用及开机会更新里面的数据。
//frameworks/base/services/core/java/com/android/server/pm/Settings.java
final WatchedArrayMap<String, PackageSetting> mPackages;
- 二级缓存是作为文件存储在/data/system/中,主要信息存储在packages.xml中。
PMS扫描安装
系统应用和预置应用的安装,是Android开机启动后,PMS通过扫描系统中的特定目录,寻找里面的APK文件,对这些APK文件进行解析,得到应用的相关信息,再将其添加到各种数据结构中并注册到PMS的记录文件中,完成应用安装。
启动
PMS和其它系统服务一样,都是SystemServer进程启动的。SystemServer的startBootstrapServices
方法用于启动引导服务,在启动PMS之前还启动了相关的两个服务,Installer和DomainVerificationService(系统服务,用于访问域验证API)。
public final class SystemServer implements Dumpable {
...
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
Installer installer = mSystemServiceManager.startService(Installer.class);
DomainVerificationService domainVerificationService = new DomainVerificationService(
mSystemContext, SystemConfig.getInstance(), platformCompat);
mSystemServiceManager.startService(domainVerificationService);
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
mPackageManagerService = PackageManagerService.main(
mSystemContext, installer, domainVerificationService,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
try {
Watchdog.getInstance().pauseWatchingCurrentThread("dexopt");
//处理dex优化
mPackageManagerService.updatePackagesIfNeeded();
} catch (Throwable e) {
reportWtf("update packages", e);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("dexopt");
}
...
try {
//完成磁盘维护
mPackageManagerService.performFstrimIfNeeded();
} catch (Throwable e) {
reportWtf("performing fstrim", e);
}
//PMS准备就绪
mPackageManagerService.systemReady();
...
//等待APP数据
mPackageManagerService.waitForAppDataPrepared();
}
}
Installd服务启动
Installer服务是SystemServiceManager的startService
方法启动的,分析其它服务时我们清楚,最终调用的是Service的onStart
方法。connect
方法去连接installd服务,installd服务是Android Native层的服务进程,由init进程孵化,拥有root权限,主要是对系统中的文件进行读写执行管理。我们知道PMS运行在SystemServer进程,它是以system用户身份运行,system用户并没有访问应用程序目录的权限,而在文件系统中创建和删除文件需要root权限,而installd服务是具有的,因此创建和删除文件、dex优化等操作委托给installd处理。那么installd是如何启动的呢?它和init进程一样,通过installd.rc脚本文件启动,init.rc解析并创建一个名为installd的可执行文件,存储路径位于/system/bin/installd。
//frameworks/base/services/core/java/com/android/server/pm/Installer.java
public class Installer extends SystemService {
@Override
public void onStart() {
if (mIsolated) {
mInstalld = null;
mInstalldLatch.countDown();
} else {
connect();
}
}
private void connect() {
//installd的binder接口
IBinder binder = ServiceManager.getService("installd");
if (binder != null) {
try {
//注册Binder的死亡回调
binder.linkToDeath(() -> {
Slog.w(TAG, "installd died; reconnecting");
mInstalldLatch = new CountDownLatch(1);
//重连
connect();
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
//获取installd的binder对象
IInstalld installd = IInstalld.Stub.asInterface(binder);
mInstalld = installd;
mInstalldLatch.countDown();
try {
invalidateMounts();
executeDeferredActions();
} catch (InstallerException ignored) {
}
} else {
//如果installd还没有ready,则不停的等待1s直到Binder不为空
Slog.w(TAG, "installd not found; trying again");
BackgroundThread.getHandler().postDelayed(this::connect, CONNECT_RETRY_DELAY_MS);
}
}
}
它从class名为main,同一个class的所有的service必须同时启动或停止,installd的入口函数在installd.cpp中。
installd的入口函数指向了installd_main,它主要完成一些系统目录的初始化工作,比如初始化保存data和system分区的一些目录,像存放用户安装应用的/data/app/,存放系统应用的/system/app/,存放系统特权应用的/system/pri-app等,也会创建系统主用户/data/misc/user/0文件夹,除主用户外(data/user/0)外,其余用户都会在/data/user/目录下创建一个属于自己的文件夹,据此创建/data/misc/user/user_id目录。
最重要的是启动InstalldNativeService,启动InstalldNativeService继承BinderService,start方法中BinderService<InstalldNativeService>::publish()
将InstalldNativeService添加到native层的ServiceManager中。InstalldNativeService.h中可以看出其服务名为installd。因此可执行文件installd启动了InstalldNativeService作为Binder的服务端,其它进程就可以通过ServiceManager获取到名为installd的服务,实现跨进程调用。SystemServer启动Installer就是为了连接installd服务.
//frameworks/native/cmds/installd/installd.cpp
namespace android {
namespace installd {
static int installd_main(const int argc ATTRIBUTE_UNUSED, char *argv[]) {
int ret;
int selinux_enabled = (is_selinux_enabled() > 0);
setenv("ANDROID_LOG_TAGS", "*:v", 1);
android::base::InitLogging(argv);
SLOGI("installd firing up");
union selinux_callback cb;
cb.func_log = log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
if (!initialize_globals()) {
SLOGE("Could not initialize globals; exiting.\n");
exit(1);
}
if (initialize_directories() < 0) {
SLOGE("Could not create directories; exiting.\n");
exit(1);
}
if (selinux_enabled && selinux_status_open(true) < 0) {
SLOGE("Could not open selinux status; exiting.\n");
exit(1);
}
//启动InstalldNativeService
if ((ret = InstalldNativeService::start()) != android::OK) {
SLOGE("Unable to start InstalldNativeService: %d", ret);
exit(1);
}
IPCThreadState::self()->joinThreadPool();
LOG(INFO) << "installd shutting down";
return 0;
}
} // namespace installd
} // namespace android
int main(const int argc, char *argv[]) {
return android::installd::installd_main(argc, argv);
}
//frameworks/native/cmds/installd/InstalldNativeService.cpp
status_t InstalldNativeService::start() {
IPCThreadState::self()->disableBackgroundScheduling(true);
status_t ret = BinderService<InstalldNativeService>::publish();
if (ret != android::OK) {
return ret;
}
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
sAppDataIsolationEnabled = android::base::GetBoolProperty(
kAppDataIsolationEnabledProperty, true);
return android::OK;
}
//frameworks/native/cmds/installd/InstalldNativeService.h
class InstalldNativeService : public BinderService<InstalldNativeService>, public os::BnInstalld {
static status_t start();
//服务名
static char const* getServiceName() { return "installd"; }
PMS启动
Installd服务启动完成后,PMS开始调用main
方法启动PMS,首先实例化PackageManagerServiceInjector,其中初始化各种实例化对象,例如PermissionManagerService、Settings、SystemConfig等,也创建了处理应用安装卸载的工作线程。
//frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public class PackageManagerService implements PackageSender, TestUtilityService {
public static PackageManagerService main(Context context,
Installer installer, @NonNull DomainVerificationService domainVerificationService,
boolean factoryTest) {
PackageManagerServiceInjector injector = new PackageManagerServiceInjector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
backgroundHandler,
SYSTEM_PARTITIONS,
(i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mUserNeedsBadging),
(i, pm) -> PermissionManagerService.create(context,
i.getSystemConfig().getAvailableFeatures()),
(i, pm) -> new UserManagerService(context, pm,
new UserDataPreparer(installer, installLock, context), lock),
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, backgroundHandler,
lock),
(i, pm) -> AppsFilterImpl.create(i,
i.getLocalService(PackageManagerInternal.class)),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
(i, pm) -> SystemConfig.getInstance(),
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
i.getContext(), "*dexopt*"),
(i, pm) -> new DexManager(i.getContext(), i.getPackageDexOptimizer(),
i.getInstaller(), i.getInstallLock(), i.getDynamicCodeLogger()),
(i, pm) -> new DynamicCodeLogger(i.getInstaller()),
(i, pm) -> new ArtManagerService(i.getContext(), i.getInstaller(),
i.getInstallLock()),
(i, pm) -> ApexManager.getInstance(),
(i, pm) -> (IncrementalManager)
i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),
(i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),
() -> LocalServices.getService(UserManagerInternal.class)),
(i, pm) -> new DisplayMetrics(),
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(),
new PackageCacher(pm.mCacheDir, pm.mPackageParserCallback),
pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
pm.mPackageParserCallback) /* scanningPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, i.getDisplayMetrics(), null,
pm.mPackageParserCallback) /* preparingPackageParserProducer */,
(i, pm) -> new PackageInstallerService(
i.getContext(), pm, i::getScanningPackageParser),
(i, pm, cn) -> new InstantAppResolverConnection(
i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
(i, pm) -> new ModuleInfoProvider(i.getContext()),
(i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
(i, pm) -> domainVerificationService,
(i, pm) -> {
HandlerThread thread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
thread.start();
return new PackageHandler(thread.getLooper(), pm);
},
new DefaultSystemWrapper(),
LocalServices::getService,
context::getSystemService,
(i, pm) -> {
if (useArtService()) {
return null;
}
try {
return new BackgroundDexOptService(i.getContext(), i.getDexManager(), pm);
} catch (LegacyDexoptDisabledException e) {
throw new RuntimeException(e);
}
},
(i, pm) -> IBackupManager.Stub.asInterface(ServiceManager.getService(
Context.BACKUP_SERVICE)),
(i, pm) -> new SharedLibrariesImpl(pm, i),
(i, pm) -> new CrossProfileIntentFilterHelper(i.getSettings(),
i.getUserManagerService(), i.getLock(), i.getUserManagerInternal(),
context),
(i, pm) -> new UpdateOwnershipHelper(),
(i, pm) -> new PackageMonitorCallbackHelper());
//创建PMS
PackageManagerService m = new PackageManagerService(injector, factoryTest,
PackagePartitions.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG,
Build.VERSION.SDK_INT, Build.VERSION.INCREMENTAL);
...
m.installAllowlistedSystemPackages();
IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();
//package service注册到ServiceManager
ServiceManager.addService("package", iPackageManager);
final PackageManagerNative pmn = new PackageManagerNative(m);
ServiceManager.addService("package_native", pmn);
return m;
}
}
Settings
Settings的构造方法中首先创建了data/system 目录及该目录下的package相关文件。
- package.xml。记录所有应用的安装信息。当系统进行安装、卸载和更新操作时,均会更新此文件。该文件保存了系统中与package相关的一些信息。
将该文件pull到本地进行查看,如果乱码请使用如下命令:
adb shell setprop persist.sys.binary_xml false
文件部分内容如下:这个文件非常庞大,包含许多标签,如permission标签,包含了系统所有定义的权限信息,package标签包含所有安装的应用信息,shared-user标签描述共享用户ID的信息。domain-verifications标签包含域验证信息。
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<packages>
<version sdkVersion="35" databaseVersion="3" buildFingerprint="" fingerprint="" />
<version volumeUuid="primary_physical" sdkVersion="35" databaseVersion="3" buildFingerprint="" fingerprint="" />
<permission-trees></permission-trees>
<permissions>
<item name="android.permission.INTERNET" package="android" protection="4096" />
...
</permissions>
<package name="com.android.settings" codePath="/system_ext/priv-app/Settings" nativeLibraryPath="/system_ext/priv-app/Settings/lib" primaryCpuAbi="arm64-v8a" publicFlags="944488005" privateFlags="-1938812568" ft="" ut="" version="35" targetSdkVersion="35" scannedAsStoppedSystemApp="false" sharedUserId="1000" packageSource="0" isOrphaned="true" loadingProgress="1.0" loadingCompletedTime="0" domainSetId="" appMetadataSource="0">
<sigs count="1" schemeVersion="3">
<cert index="7" />
</sigs>
<proper-signing-keyset identifier="1" />
</package>
<shared-user name="android.uid.system" userId="1000">
<sigs count="1" schemeVersion="3">
<cert index="7" />
</sigs>
</shared-user>
<domain-verifications>
<active>
<package-state packageName="com.android.settings" id="bded5a7a-00c4-4dfc-a944-7992e8831784" />
</active>
</domain-verifications>
- package-backup.xml。package.xml的备份文件。开机完成读取后,会删除该文件。
- package.list。记录应用数据信息。当应用信息有变动时,PMS就会更新此文件。
将该文件pull到本地进行查看,Settings类的writePackageListLPrInternal
方法对各项进行了说明。
第一项是包名,第二个是安装应用的userid,一般是在AndroidManifest.xml中通过android:sharedUserId="android.uid.system"
,第三项是安装应用是否处于调试模式,也是通过AndroidManifest.xml中通过android:debuggable
指定,默认为0,非调试模式,第四项是应用数据存放路径,第五项是Selinux信息,Platform app,第六项是应用所属user group,不属于任何group,则为0。第七项是安装应用是否可以由shell配置,由AndroidManifest.xml中的Profileable指定。第八项是安装应用的版本号,android:versionCode
指定,第九项表示安装该应用的包,@System表示赋予FLAG_SYSTEM标志,赋予系统权限,@Product表示赋予PRIVATE_FLAG_PRODUCT标志,有安装源会被打印。
com.android.settings 1000 0 /data/user_de/0/com.android.settings platform:privapp:targetSdkVersion=28:partition=system_ext 1065,3002,3003,3001,3007,2901,1007 0 35 1 @system
//frameworks/base/services/core/java/com/android/server/pm/Settings.java
public final class Settings implements Watchable, Snappable, ResilientAtomicFile.ReadEventLogger {
Settings(File dataDir, RuntimePermissionsPersistence runtimePermissionsPersistence,
LegacyPermissionDataProvider permissionDataProvider,
@NonNull DomainVerificationManagerInternal domainVerificationManager,
@NonNull Handler handler,
@NonNull PackageManagerTracedLock lock) {
...
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");
mSettingsReserveCopyFilename = new File(mSystemDir, "packages.xml.reservecopy");
mPreviousSettingsFilename = new File(mSystemDir, "packages-backup.xml");
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;
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
mDomainVerificationManager = domainVerificationManager;
registerObservers();
Watchable.verifyWatchedAttributes(this, mObserver);
mSnapshot = makeCache();
}
private void writePackageListLPrInternal(int creatingUserId) {
// 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
// seinfo - seinfo label for the app (assigned at install time)
// gids - supplementary gids this app launches with
// profileableFromShellFlag - 0 or 1 if the package is profileable from shell.
// longVersionCode - integer version of the package.
// profileable - 0 or 1 if the package is profileable by the platform.
// packageInstaller - the package that installed this app, or @system, @product or
// @null.
//
// 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/libpackagelistparser
...
}
}
SystemConfig
SystemConfig的初始化是通过单例形式获取实例,其构造方法中主要通过readAllPermissions
方法将/system、/vendor、/odm、/oem、/product、/system_ext的/etc/sysconfig和/etc/permissions的xml定义的各个节点读取出来保存到SystemConfig的成员变量中,其中xml涉及到的标签有feature、library、permission、assign-permission等,这些标签的内容都将被解析出来保存到SystemConfig对应数据结构的全局变量中以方便查询管理,如系统支持的feature。feature标签用来描述设备是否支持的硬件特性,library标签用来指定系统库,应用程序运行时,系统会为进程加载一些必要库,permission标签用于将permission与gid(用户组id)关联,assign-permission标签将system中描述的permission与uid(用户id)关联等等。SystemConfig提供了大量方法供我们查询系统配置。如getAvailableFeatures
、getPermissionAllowlist
等方法。
//frameworks/base/services/core/java/com/android/server/SystemConfig.java
public class SystemConfig {
public static SystemConfig getInstance() {
if (!isSystemProcess()) {
Slog.wtf(TAG, "SystemConfig is being accessed by a process other than "
+ "system_server.");
}
synchronized (SystemConfig.class) {
if (sInstance == null) {
sInstance = new SystemConfig();
}
return sInstance;
}
}
SystemConfig() {
TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
log.traceBegin("readAllPermissions");
try {
readAllPermissions();
readPublicNativeLibrariesList();
} finally {
log.traceEnd();
}
}
private void readAllPermissions() {
final XmlPullParser parser = Xml.newPullParser();
// Read configuration from system
readPermissions(parser, Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
// Read configuration from the old permissions dir
readPermissions(parser, Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
// Vendors are only allowed to customize these
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
| ALLOW_SIGNATURE_PERMISSIONS | ALLOW_ASSOCIATIONS | ALLOW_VENDOR_APEX;
if (Build.VERSION.DEVICE_INITIAL_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
}
readPermissions(parser, Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(parser, Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
if (!vendorSkuProperty.isEmpty()) {
String vendorSkuDir = "sku_" + vendorSkuProperty;
readPermissions(parser, Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
vendorPermissionFlag);
readPermissions(parser, Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
vendorPermissionFlag);
....
}
}
public PermissionAllowlist getPermissionAllowlist() {
return mPermissionAllowlist;
}
public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
return mAvailableFeatures;
}
}
HandlerThread
PackageManagerServiceInjector还启动了一个PackageManager的HandlerThread,该线程是PMS的工作线程。PMS的各种操作都将利用返回的PackageHandler分发至该HandlerThread进行处理,以执行系统中所有包的管理及所有组件的查询工作。Message what定义在PMS中。
//frameworks/base/services/core/java/com/android/server/pm/PackageHandler.java
final class PackageHandler extends Handler {
@Override
public void handleMessage(Message msg) {
try {
doHandleMessage(msg);
} finally {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
}
}
void doHandleMessage(Message msg) {
switch (msg.what) {
case SEND_PENDING_BROADCAST: {
mPm.sendPendingBroadcasts();
break;
}
....
case WRITE_PACKAGE_LIST: {
int userId = msg.arg1;
if (!mPm.tryWritePackageList(userId)) {
// Failed to write.
this.removeMessages(WRITE_PACKAGE_LIST);
mPm.scheduleWritePackageList(userId);
}
} break;
}
}
public class PackageManagerService implements PackageSender, TestUtilityService {
static final int POST_INSTALL = 9;
static final int WRITE_SETTINGS = 13;
static final int WRITE_DIRTY_PACKAGE_RESTRICTIONS = 14;
static final int PACKAGE_VERIFIED = 15;
static final int CHECK_PENDING_VERIFICATION = 16;
// public static final int UNUSED = 17;
// public static final int UNUSED = 18;
static final int WRITE_PACKAGE_LIST = 19;
static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
static final int ENABLE_ROLLBACK_STATUS = 21;
static final int ENABLE_ROLLBACK_TIMEOUT = 22;
static final int DEFERRED_NO_KILL_POST_DELETE = 23;
static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24;
static final int INTEGRITY_VERIFICATION_COMPLETE = 25;
static final int CHECK_PENDING_INTEGRITY_VERIFICATION = 26;
static final int DOMAIN_VERIFICATION = 27;
static final int PRUNE_UNUSED_STATIC_SHARED_LIBRARIES = 28;
static final int DEFERRED_PENDING_KILL_INSTALL_OBSERVER = 29;
static final int WRITE_USER_PACKAGE_RESTRICTIONS = 30;
}
初始化
开始阶段
开始阶段首先初始化了一些组件以便交互,接着添加系统UID,共9种系统UID,addSharedUserLPw
方法将系统shareUserId的属性值和Process中UID对应起来。
关联的目的是:
- 两个或多个进程或进程声明同一种shareUserId的APK可以共享彼此数据,并且可以运行在同一进程。
- 声明特定的shareUserId,该应用赋予特定的UID,同时被赋予UID对应的权限。
接着读取System Config,获取支持的功能。mSettings的readLPw
方法解析/data/system目录下的记录文件,获取已经安装的应用信息,存储在Settings对应的成员变量中,当packages.xml和packages-backup.xml都不存在时返回false,由此判定为系统首次开机,赋值给mFirstBoot,通过此值判定是否为首次开机,同时在Installd中设置首次启动。
//frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(PackageManagerServiceInjector injector, boolean factoryTest,
final String partitionsFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
...
//初始化组件以便交互
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
//添加系统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);
mSettings.addSharedUserLPw("android.uid.se", SE_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
...
mPackageDexOptimizer = injector.getPackageDexOptimizer();
mDexManager = injector.getDexManager();
SystemConfig systemConfig = injector.getSystemConfig();
mAvailableFeatures = systemConfig.getAvailableFeatures();
FallbackCategoryProvider.loadFallbacks();
//解析data/system下记录文件
mFirstBoot = !mSettings.readLPw(computer,
mInjector.getUserManagerInternal().getUsers(
/* excludePartial= */ true,
/* excludeDying= */ false,
/* excludePreCreated= */ false));
if (mFirstBoot) {
t.traceBegin("setFirstBoot: ");
try {
mInstaller.setFirstBoot();
} catch (InstallerException e) {
Slog.w(TAG, "Could not set First Boot: ", e);
}
t.traceEnd();
}
//设置自定义的启动意图组件
String customResolverActivityName = Resources.getSystem().getString(
R.string.config_customResolverActivity);
if (!TextUtils.isEmpty(customResolverActivityName)) {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivityName);
}
}
//frameworks/base/core/java/android/os/Process.java
public class Process {
public static final int INVALID_UID = -1;
public static final int ROOT_UID = 0;
public static final int SYSTEM_UID = 1000;
public static final int PHONE_UID = 1001;
public static final int SHELL_UID = 2000;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int LOG_UID = 1007;
public static final int WIFI_UID = 1010;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int MEDIA_UID = 1013;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@TestApi
@SystemApi(client = MODULE_LIBRARIES)
public static final int NFC_UID = 1027;
...
}
扫描阶段
扫描阶段根据系统分区不同分为两部分扫描,系统分区和用户分区。系统分区扫描的路径包含/system,/vendor,/odm,/oem,/product,/system_ext等路径,用户分区扫描的是/data/app路径,即内置三方应用路径。
通过InitAppsHelper类的initSystemApps
、initNonSystemApps
方法进行扫描。
//frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private final InitAppsHelper mInitAppsHelper;
public PackageManagerService(PackageManagerServiceInjector injector, boolean factoryTest,
final String partitionsFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
...
final int[] userIds = mUserManager.getUserIds();
PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,
startTime);
mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime);
packageParser.close();
mRequiredVerifierPackages = getRequiredButNotReallyRequiredVerifiersLPr(computer);
mRequiredInstallerPackage = getRequiredInstallerLPr(computer);
mRequiredUninstallerPackage = getRequiredUninstallerLPr(computer);
....
}
从源码可以发现,两部分扫描都调用了scanDirTracedLI
方法,最终通过InitAppsHelper类的installPackagesFromDir
方法。扫描逻辑都通过PMS的辅助类去处理。
//frameworks/base/services/core/java/com/android/server/pm/InitAppsHelper.java
private final InstallPackageHelper mInstallPackageHelper;
public OverlayConfig initSystemApps(PackageParser2 packageParser,
WatchedArrayMap<String, PackageSetting> packageSettings,
int[] userIds, long startTime) {
...
scanSystemDirs(packageParser, mExecutorService);
...
}
private void scanSystemDirs(PackageParser2 packageParser, ExecutorService executorService) {
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getOverlayFolder() == null) {
continue;
}
scanDirTracedLI(partition.getOverlayFolder(),
mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService, partition.apexInfo);
}
scanDirTracedLI(frameworkDir,
mSystemParseFlags, mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
packageParser, executorService, null);
if (!mPm.mPackages.containsKey("android")) {
throw new IllegalStateException(
"Failed to load frameworks package; check log for warnings");
}
for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(),
mSystemParseFlags,
mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
packageParser, executorService, partition.apexInfo);
}
scanDirTracedLI(partition.getAppFolder(),
mSystemParseFlags, mSystemScanFlags | partition.scanFlag,
packageParser, executorService, partition.apexInfo);
}
}
public void initNonSystemApps(PackageParser2 packageParser, @NonNull int[] userIds,
long startTime) {
...
scanDirTracedLI(mPm.getAppInstallDir(), 0,
mScanFlags | SCAN_REQUIRE_KNOWN, packageParser, mExecutorService, null);
...
}
private void scanDirTracedLI(File scanDir, int parseFlags, int scanFlags,
PackageParser2 packageParser, ExecutorService executorService,
@Nullable ApexManager.ActiveApexInfo apexInfo) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
// when scanning apk in apexes, we want to check the maxSdkVersion
parseFlags |= PARSE_APK_IN_APEX;
}
mInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags,
scanFlags, packageParser, executorService, apexInfo);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
PackageParser2对象和线程池封装为ParallelPackageParser对象,ParallelPackageParser是一个应用解析辅助类,调用它的submit
方法解析。解析完成后,通过addForInitLI
方法将Package中的内容加入到PMS中。
//frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
public void installPackagesFromDir(File scanDir, int parseFlags,
int scanFlags, PackageParser2 packageParser, ExecutorService executorService,
@Nullable ApexManager.ActiveApexInfo apexInfo) {
inal File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + scanDir);
return;
}
if (DEBUG_PACKAGE_SCANNING) {
Log.d(TAG, "Scanning app dir " + scanDir + " scanFlags=" + scanFlags
+ " flags=0x" + Integer.toHexString(parseFlags));
}
ParallelPackageParser parallelPackageParser =
new ParallelPackageParser(packageParser, executorService);
// Submit files for parsing in parallel
int fileCount = 0;
for (File file : files) {
final boolean isPackage = (isApkFile(file) || file.isDirectory())
&& !PackageInstallerService.isStageName(file.getName());
if (!isPackage) {
// Ignore entries which are not packages
continue;
}
if ((scanFlags & SCAN_DROP_CACHE) != 0) {
final PackageCacher cacher = new PackageCacher(mPm.getCacheDir(),
mPm.mPackageParserCallback);
Log.w(TAG, "Dropping cache of " + file.getAbsolutePath());
cacher.cleanCachedResult(file);
}
//解析包
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// Process results one by one
for (; fileCount > 0; fileCount--) {
//通过mQueue取出的解析结果
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
int errorCode = PackageManager.INSTALL_SUCCEEDED;
String errorMsg = null;
if (throwable == null) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "addForInitLI");
//解析的应用内容添加到内部数据结构中
addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
new UserHandle(UserHandle.USER_SYSTEM), apexInfo);
} catch (PackageManagerException e) {
errorCode = e.error;
errorMsg = "Failed to scan " + parseResult.scanFile + ": " + e.getMessage();
Slog.w(TAG, errorMsg);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
...
}
解析阶段
submit
方法完成了解析应用包的任务并将结果返回,该方法通过parsePackage
方法解析了应用包,然后将扫描路径的APK文件和结果赋值给ParseResult,再将扫描路径的APK文件和结果赋值给ParseResult,再将ParseResult方法队列的mQueue中,方便后续调用。
parsePackage
方法调用了PackageParser2类的parsePackage
方法进行应用包的解析,最终调用到ParsingPackageUtils类的parsePackage
方法。
//frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java
private final PackageParser2 mPackageParser;
public void submit(File scanFile, int parseFlags) {
mExecutorService.submit(() -> {
ParseResult pr = new ParseResult();
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parallel parsePackage [" + scanFile + "]");
try {
pr.scanFile = scanFile;
pr.parsedPackage = parsePackage(scanFile, parseFlags);
} catch (Throwable e) {
pr.throwable = e;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
mQueue.put(pr);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageManagerException {
try {
return mPackageParser.parsePackage(scanFile, parseFlags, true);
} catch (PackageParserException e) {
throw new PackageManagerException(e.error, e.getMessage(), e);
}
}
这里需要说下APK的拆分机制,Android 5.0以后,支持APK拆分,即一个APK可以拆分成很多部分,位于相同的目录下,每一个部分都是一个单独的APK文件,所有的APK具有相同的签名,在APK解析过程中,会将拆分的APK重新组合成内存中的一个Package。对于一个完整APK,Android称其为Monolithic,对于拆分后的APK,Android称其为Cluster。Android为支持APK拆分,应用目录多出一级,比如Settings 应用目录是System/app/Settings/Settings.apk,如果拆分,拆出的APK都位于这个目录下即可,这样在包解析时,变成以Cluster方式解析。因此Android 5.0之前,都是使用parseMonolithicPackage
方法,之后默认都是使用目录的形式,调用parseClusterPackage
方法进行解析。
parseBaseApk
方法主要对AndroidManifest.xml进行解析,接着调用重载parseBaseApk
方法,通过parseBaseApkTags
方法解析XML文件。如果是Application标签,调用parseBaseApplication
方法进一步解析,否则解析应用的所有tag。
parseBaseApplication
方法会解析子标签的内容,如activity、service、receiver、provider标签等,到这里AndroidManifest.xml解析完成,解析结果传回给ParallelPackageParser类的静态内部类ParseResult的成员变量parsePackage,并将该实例放入mQueue中。
//frameworks/base/core/java/com/android/internal/pm/pkg/parsing/ParsingPackageUtils.java
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags);
} else {
return parseMonolithicPackage(input, packageFile, flags);
}
}
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
...
try {
//对base.apk进行解析
final File baseApk = new File(lite.getBaseApkPath());
boolean shouldSkipComponents = lite.isIsSdkLibrary() && disallowSdkLibsToBeApps();
final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
lite.getPath(), assetLoader, flags, shouldSkipComponents);
if (result.isError()) {
return input.error(result);
}
ParsingPackage pkg = result.getResult();
if (!ArrayUtils.isEmpty(lite.getSplitNames())) {
pkg.asSplit(
lite.getSplitNames(),
lite.getSplitApkPaths(),
lite.getSplitRevisionCodes(),
splitDependencies
);
//获取split apk数量
final int num = lite.getSplitNames().length;
for (int i = 0; i < num; i++) {
final AssetManager splitAssets = assetLoader.getSplitAssetManager(i);
//对split apk解析
final ParseResult<ParsingPackage> split =
parseSplitApk(input, pkg, i, splitAssets, flags);
if (split.isError()) {
return input.error(split);
}
}
}
pkg.set32BitAbiPreferred(lite.isUse32bitAbi());
return input.success(pkg);
...
}
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, SplitAssetLoader assetLoader, int flags,
boolean shouldSkipComponents) {
...
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags, shouldSkipComponents);
...
}
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags,
boolean shouldSkipComponents)
throws XmlPullParserException, IOException {
....
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
try {
final boolean isCoreApp = parser.getAttributeBooleanValue(null /*namespace*/,
"coreApp", false);
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags,
shouldSkipComponents);
if (result.isError()) {
return result;
}
....
}
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags,
boolean shouldSkipComponents) throws XmlPullParserException, IOException {
...
//application标签
if (TAG_APPLICATION.equals(tagName)) {
if (foundApp) {
if (RIGID_PARSER) {
result = input.error("<manifest> has more than one <application>");
} else {
Slog.w(TAG, "<manifest> has more than one <application>");
result = input.success(null);
}
} else {
foundApp = true;
result = parseBaseApplication(input, pkg, res, parser, flags,
shouldSkipComponents);
}
} else {
result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
}
}
private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags,
boolean shouldSkipComponents) throws XmlPullParserException, IOException {
...
//解析子标签,四大组件等。
switch (tagName) {
case "activity":
isActivity = true;
// fall-through
case "receiver":
if (shouldSkipComponents) {
continue;
}
ParseResult<ParsedActivity> activityResult =
ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/,
input);
if (activityResult.isSuccess()) {
ParsedActivity activity = activityResult.getResult();
if (isActivity) {
hasActivityOrder |= (activity.getOrder() != 0);
pkg.addActivity(activity);
} else {
hasReceiverOrder |= (activity.getOrder() != 0);
pkg.addReceiver(activity);
}
}
result = activityResult;
break;
case "service":
if (shouldSkipComponents) {
continue;
}
ParseResult<ParsedService> serviceResult =
ParsedServiceUtils.parseService(mSeparateProcesses, pkg, res, parser,
flags, sUseRoundIcon, null /*defaultSplitName*/,
input);
if (serviceResult.isSuccess()) {
ParsedService service = serviceResult.getResult();
hasServiceOrder |= (service.getOrder() != 0);
pkg.addService(service);
}
result = serviceResult;
break;
case "provider":
if (shouldSkipComponents) {
continue;
}
ParseResult<ParsedProvider> providerResult =
ParsedProviderUtils.parseProvider(mSeparateProcesses, pkg, res, parser,
flags, sUseRoundIcon, null /*defaultSplitName*/,
input);
if (providerResult.isSuccess()) {
pkg.addProvider(providerResult.getResult());
}
result = providerResult;
break;
case "activity-alias":
if (shouldSkipComponents) {
continue;
}
activityResult = ParsedActivityUtils.parseActivityAlias(pkg, res,
parser, sUseRoundIcon, null /*defaultSplitName*/,
input);
if (activityResult.isSuccess()) {
ParsedActivity activity = activityResult.getResult();
hasActivityOrder |= (activity.getOrder() != 0);
pkg.addActivity(activity);
}
result = activityResult;
break;
case "apex-system-service":
ParseResult<ParsedApexSystemService> systemServiceResult =
ParsedApexSystemServiceUtils.parseApexSystemService(res,
parser, input);
if (systemServiceResult.isSuccess()) {
ParsedApexSystemService systemService =
systemServiceResult.getResult();
pkg.addApexSystemService(systemService);
}
result = systemServiceResult;
break;
default:
result = parseBaseAppChildTag(input, tagName, pkg, res, parser, flags);
break;
}
}
应用信息保存
addForInitLI
方法将解析后的Package信息保存到内部数据结构中,同时在此方法中,也进行了安装包的校验、签名检查、apk更新等操作。reconcilePackages
方法主要是为了校验签名(verifySignatures
),最终生成ReconciledPackage并返回。
commitReconciledScanResultLocked
方法调用commitPackageSettings
方法,将解析出的相关package组件信息添加到PMS中,相当于将package信息从私有转换到共有,完成此方法后,Package可用于查询、解析等。
//frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
@PackageManagerService.ScanFlags int scanFlags,
@Nullable UserHandle user, @Nullable ApexManager.ActiveApexInfo activeApexInfo)
throws PackageManagerException {
...
try {
final String pkgName = scanResult.mPkgSetting.getPackageName();
//一致化处理
final List<ReconciledPackage> reconcileResult =
ReconcilePackageUtils.reconcilePackages(
Collections.singletonList(installRequest),
mPm.mPackages, Collections.singletonMap(pkgName,
mPm.getSettingsVersionForPackage(parsedPackage)),
mSharedLibraries, mPm.mSettings.getKeySetManagerService(),
mPm.mSettings, mPm.mInjector.getSystemConfig());
if ((scanFlags & SCAN_AS_APEX) == 0) {
appIdCreated = optimisticallyRegisterAppId(installRequest);
} else {
installRequest.setScannedPackageSettingAppId(Process.INVALID_UID);
}
//提交扫描和解析结果
commitReconciledScanResultLocked(reconcileResult.get(0),
mPm.mUserManager.getUserIds());
...
}
private AndroidPackage commitReconciledScanResultLocked(
@NonNull ReconciledPackage reconciledPkg, int[] allUsers) {
...
commitPackageSettings(pkg, pkgSetting, oldPkgSetting, reconciledPkg);
...
}
private void commitPackageSettings(@NonNull AndroidPackage pkg,
@NonNull PackageSetting pkgSetting, @Nullable PackageSetting oldPkgSetting,
ReconciledPackage reconciledPkg) {
mPm.mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPm.mPackages.put(pkg.getPackageName(), pkg);
mPm.mComponentResolver.addAllComponents(pkg, chatty, mPm.mSetupWizardPackage, snapshot);
mPm.mAppsFilter.addPackage(snapshot, pkgSetting, isReplace,
(scanFlags & SCAN_DONT_KILL_APP) != 0 /* retainImplicitGrantOnReplace */);
mPm.addAllPackageProperties(pkg);
...
}
扫描结束
扫描结束后的任务是读取和更新应用权限授予状态,生成package的应用数据,更新package.xml等文件的信息,完成应用安装。
介绍下生成数据目录的过程,首先SystemServerInitThreadPool线程池提交了一个task,这个方法中首先调用fixupAppData
方法,创建/data/user/用户id和/data/data目录,这个目录由StoreManagerService进行管理。每一个App的安装实际路径是/data/user/用户 id/包名。而我们常见到的/data/data/包名的目录的其实是它的软链接。主用户的目录就是/data/user/0。
调用prepareAppDataAndMigrate
方法,准备应用数据,最终调用到prepareAppData
方法。调用createAppData
方法,为每一个应用创建一个cache及code_cache的目录,用于缓存编译优化后的结果。调用prepareAppProfiles
方法会调用installd的prepareAppProfile方法,并且调用保存在/system/bin/profman这个程序,在程序目录下生成一个.prof文件,这个文件可以加速dex2oat编译优化的速度。调用prepareAppDataContentsLeafLIF
方法,核心就是调用installd的linkNativeLibraryDirectory
方法,把应用安装so库的目录/data/data/包名/lib和/data/user/用户id/包名/lib链接上。
//frameworks/base/services/core/java/com/android/server/pm/AppDataHelper.java
public Future<?> fixAppsDataOnBoot() {
Future<?> prepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
TimingsTraceLog traceLog = new TimingsTraceLog("SystemServerTimingAsync",
Trace.TRACE_TAG_PACKAGE_MANAGER);
traceLog.traceBegin("AppDataFixup");
try {
mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
} catch (Installer.InstallerException e) {
Slog.w(TAG, "Trouble fixing GIDs", e);
}
...
for (String pkgName : deferPackages) {
final Computer snapshot = mPm.snapshotComputer();
final PackageStateInternal packageStateInternal = snapshot.getPackageStateInternal(
pkgName);
if (packageStateInternal != null
&& packageStateInternal.getUserStateOrDefault(
UserHandle.USER_SYSTEM).isInstalled()) {
AndroidPackage pkg = packageStateInternal.getPkg();
prepareAppDataAndMigrate(batch, pkg,
UserHandle.USER_SYSTEM, storageFlags, true /* maybeMigrateAppData */);
count++;
}
}
}
private @NonNull CompletableFuture<?> prepareAppData(@NonNull Installer.Batch batch,
@NonNull PackageSetting ps, int previousAppId, int userId, int flags) {
...
try {
createAppDataResult = mInstaller.createAppData(args);
...
if (pkg != null && (mPm.isDeviceUpgrading() || mPm.isFirstBoot()
|| (userId != UserHandle.USER_SYSTEM))) {
try {
mArtManagerService.prepareAppProfiles(pkg, userId,
/* updateReferenceProfileContent= */ false);
if (pkg != null) {
prepareAppDataContentsLeafLIF(pkg, ps, userId, flags);
}
}
就绪阶段
PMS的最后阶段就是获取PackageInstallerService对象,GC回收内存。
使用场景
获取PMS代理对象
平常使用的getPackageManager
方法是如何调用到PMS对象呢?首先getPackageManager
方法的实现在ContextImpl中,通过ActivityThread的getPackageManager
获取IPackageManager代理,然后创建ApplicationPackageManager对象并返回。
//frameworks/base/core/java/android/app/ContextImpl.java
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
final IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
//frameworks/base/core/java/android/app/ActivityThread.java
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
final IBinder b = ServiceManager.getService("package");
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
系统预制应用配置
在源码目录下找个位置放入要预置的APK文件,同时新建一个Android.mk文件,一般系统应用在package/app目录下。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional
LOCAL_PACKAGE_NAME := Test
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_SRC_FILES := apk/Test.apk
LOCAL_MODULE_CLASS := APPS
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_PROGUARD_ENABLED := disabled
#内置为可卸载应用
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
#内置为核心应用
LOCAL_PRIVILEGED_MODULE := true
LOCAL_MULTILIB := 32
include $(BUILD_PREBUILT)
在MK文件中,用PRODUCT_PACKAGES变量追加项目名,这样这个应用就预置到系统了。
PRODUCT_PACKAGES += Test
从Android 8.0开始,预置应用时需要在/etc/permissions目录下系统配置文件中授予特许权限,从Android 9.0开始,需要明确授予需要的特许权限,否则设备无法启动。预置到pri-app的应用,如需申请signature|privileged的权限,可在frameworks/base/data/etc/privapp-permissions-platform.xml中授予。
调试命令
adb shell pm list features
adb shell pm list package
adb shell pm list permissions
adb shell pm list libraries
adb shell pm list users
adb shell pm path 包名
adb shell pm dump 包名
adb install apk名
adb uninstall 包名
adb shell dumpsys package 包名
架构
PMS和其它系统服务一样,也是采用Binder进行通信。IPackageManager.aidl由工具转换自动生成binder的服务端IPackageManager.Stub和客户端IPackageManager.Stub.Proxy。
Binder服务端:PMS中提供实现。IPackageManagerBase 继承IPackageManager.Stub,PMS内部IPackageManagerImpl继承IPackageManagerBase。
Binder客户端:ApplicationPackageManager(简称APM)并没有直接参与Binder通信,而是通过IPackageManager成员变量mPM,mPM指向的是一个IPackageManager.Stub.Proxy对象,当调用到mPM的方法时,将会调用到IPackageManager的Proxy代理方法,然后通过Binder机制的mRemote与服务端PMS通信,APM继承PackageManager类,PackageManager是一个抽象类,对IpackageManager接口类中的业务方法进行了封装并对外公开。而APM对PackageManager的抽象方法进行具体实现。