PackageManagerService是Android核心服务之一,负责系统中Package的管理,应用程序的安装、卸载、信息查询等。
1、初识PMS
PMS由SystemServer创建:
SystemServer的run函数调用startBootstrapServices,startBootstrapServices调用PackageManagerService.main函数
frameworks/base/services/java/com/android/server/SystemServer.java
t.traceBegin("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
2、PMS的main函数分析
frameworks/base/services/core/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();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
t.traceBegin("create package manager");
final Object lock = new Object();
final Object installLock = new Object();
Injector injector = new Injector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
(i, pm) ->
new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
(i, pm) ->
PermissionManagerService.create(context, lock),
(i, pm) ->
new UserManagerService(context, pm,
new UserDataPreparer(installer, installLock, context, onlyCore),
lock),
(i, pm) ->
new Settings(Environment.getDataDirectory(),
i.getPermissionManagerServiceInternal().getPermissionSettings(),
lock),
new Injector.LocalServicesProducer<>(ActivityTaskManagerInternal.class),
new Injector.LocalServicesProducer<>(ActivityManagerInternal.class),
new Injector.LocalServicesProducer<>(DeviceIdleInternal.class),
new Injector.LocalServicesProducer<>(StorageManagerInternal.class),
new Injector.LocalServicesProducer<>(NetworkPolicyManagerInternal.class),
new Injector.LocalServicesProducer<>(PermissionPolicyInternal.class),
new Injector.LocalServicesProducer<>(DeviceStorageMonitorInternal.class),
new Injector.SystemServiceProducer<>(DisplayManager.class),
new Injector.SystemServiceProducer<>(StorageManager.class),
new Injector.SystemServiceProducer<>(AppOpsManager.class),
(i, pm) -> AppsFilter.create(pm.mPmInternal, i),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"));
PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest);
t.traceEnd(); // "create package manager"
injector.getCompatibility().registerListener(SELinuxMMAC.SELINUX_LATEST_CHANGES,
packageName -> {
synchronized (m.mInstallLock) {
final AndroidPackage pkg;
final PackageSetting ps;
final SharedUserSetting sharedUser;
final String oldSeInfo;
synchronized (m.mLock) {
ps = m.mSettings.getPackageLPr(packageName);
if (ps == null) {
Slog.e(TAG, "Failed to find package setting " + packageName);
return;
}
pkg = ps.pkg;
sharedUser = ps.getSharedUser();
oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
}
if (pkg == null) {
Slog.e(TAG, "Failed to find package " + packageName);
return;
}
final String newSeInfo = SELinuxMMAC.getSeInfo(pkg, sharedUser,
m.mInjector.getCompatibility());
if (!newSeInfo.equals(oldSeInfo)) {
Slog.i(TAG, "Updating seInfo for package " + packageName + " from: "
+ oldSeInfo + " to: " + newSeInfo);
ps.getPkgState().setOverrideSeInfo(newSeInfo);
m.prepareAppDataAfterInstallLIF(pkg);
}
}
});
m.installWhitelistedSystemPackages();
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
main是应用程序包管理器的入口点,用于初始化和启动PackageManagerService服务,包括依赖注入、注册监听器、安装系统包等,并将服务添加到系统服务中。
main中执行了PMS的构造函数,PMS的构造函数进行了许多重体力活,这也是Android启动速度慢的原因之一。
PMS主要功能:扫描Android系统中几个目标文件夹中的apk,从而构建合适的数据结构以管理诸如Package信息、四大组件信息、权限信息等各种信息。抽象的看,PMS是一个加工厂,它解析实际的物理文件(APK文件)以生成符合自己要求的产品。例如,PMS将解析APK包的AndroidManifest.xml,并根据其中声明的Activity标签来创建于此对应的对象来加以保管。
PMS工作流程相对简单,复杂的是其中用于保存各种信息的数据结构和他们之间的关系,以及影响最终结果的策略控制。
卷2使用的是Android4的代码,已经是很古老的了,细节上跟现在的新版本Android代码可能有一些区别。但整体的功能应该是一致的。
2.1构造函数分析之前期准备工作
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest) {
PackageManager.disableApplicationInfoCache();
PackageManager.disablePackageInfoCache();
// Avoid invalidation-thrashing by preventing cache invalidations from causing property
// writes if the cache isn't enabled yet. We re-enable writes later when we're
// done initializing.
PackageManager.corkPackageInfoCache();
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing",
Trace.TRACE_TAG_PACKAGE_MANAGER);
mPendingBroadcasts = new PendingPackageBroadcasts();
mInjector = injector;
mInjector.bootstrap(this);
mLock = injector.getLock();
mInstallLock = injector.getInstallLock();
LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = injector.getContext();
mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
mMetrics = new DisplayMetrics();
mInstaller = injector.getInstaller();
// Create sub-components that provide services / data. Order here is important.
t.traceBegin("createSubComponents");
// Expose private service for system components to use.
mPmInternal = new PackageManagerInternalImpl();
LocalServices.addService(PackageManagerInternal.class, mPmInternal);
mUserManager = injector.getUserManagerService();
mComponentResolver = injector.getComponentResolver();
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();
mPermissionManagerService = (IPermissionManager) ServiceManager.getService("permissionmgr");
mIncrementalManager =
(IncrementalManager) mContext.getSystemService(Context.INCREMENTAL_SERVICE);
PlatformCompat platformCompat = mInjector.getCompatibility();
mPackageParserCallback = new PackageParser2.Callback() {
@Override
public boolean isChangeEnabled(long changeId, @NonNull ApplicationInfo appInfo) {
return platformCompat.isChangeEnabled(changeId, appInfo);
}
@Override
public boolean hasFeature(String feature) {
return PackageManagerService.this.hasSystemFeature(feature, 0);
}
};
// CHECKSTYLE:ON IndentationCheck
t.traceEnd();
t.traceBegin("addSharedUsers");
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);
t.traceEnd();
}
前半段主要进行了一些初始化和创建子组件的工作。
在传入的参数中Injector是一个用于依赖注入的辅助类或接口。在这段代码中,Injector被用于创建和初始化PackageManagerService类的实例。
依赖注入是一种设计模式,用于解耦组件之间的依赖关系。通过依赖注入,一个对象可以通过构造函数、方法参数或属性注入的方式获取它所依赖的其他对象,而不需要自己创建或管理这些依赖对象。
在这段代码中,Injector负责创建和提供PackageManagerService所需的依赖对象,例如上下文(Context)、锁(Lock)、安装器(Installer)等。它可能是一个具体的类,也可能是一个接口,具体实现由代码的其他部分提供。
通过使用Injector,PackageManagerService类可以将对这些依赖对象的创建和管理的责任委托给外部,从而使代码更加模块化和可测试。这种依赖注入的方式可以提高代码的可维护性和可扩展性。
在PMS的main函数中创建过Injector
刚进入构造函数,就会遇到第一个较为复杂的数据结构Settings和它的addSharedUserLPw函数,Settings的作用是管理Android系统运行过程中的一些设置信息
初识Settings
注意,Android中有多个Settings,注意区分。
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
以这段代码为例:
这个方法接受四个参数:
-
name:共享用户的名称,这里是"android.uid.system",表示系统级别的共享用户。
-
uid:共享用户的用户ID,这里是Process.SYSTEM_UID,表示系统级别的用户ID。
-
pkgFlags:共享用户的包标志,这里是ApplicationInfo.FLAG_SYSTEM,表示该共享用户是系统级别的。
-
pkgPrivateFlags:共享用户的私有包标志,这里是ApplicationInfo.PRIVATE_FLAG_PRIVILEGED,表示该共享用户是特权级别的。
UID和GID
UID为用户ID缩写,GID为用户组ID缩写,这两个概念与Linux系统中进程的权限管理有关,一般来说,每个进程都会有一个对应的UID(表示该进程属于哪个用户,不同用户有不同权限),一个进程可以分属不同的用户组
在Android平台中,系统定义的UID和GID在Process.java中
frameworks/base/services/core/java/com/android/server/pm/Settings.java
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 (registerExistingAppIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}
这个方法用于向共享用户设置中添加共享用户。它检查是否存在相同的共享用户,如果存在则返回已存在的共享用户对象,如果不存在则创建新的共享用户对象并添加到设置中。这个方法会向mSharedUsers添加一条数据
由上面的方法可知,Settings中有一个mSharedUsers成员,存储的是字符串和SharedUSerSetting键值对
SharedUserSetting分析
在apk的AndroidManifest.xml中通过在mainfest标签里添加android.sharedUserId="android.uid.system"来共享UID,从而使apk获取系统权限。
多个声明了同一种sharedUserId的apk可以共享彼此的数据,并且可以运行在同一进程中。
更重要的是,通过声明特定的sharedUserId,该apk所在进程将被赋予指定的UID
根据以上内容思考,如何组织数据结构来包含以上内容:
1.XML中sharedUserId是指定的字符串来描述UID,数据结构中需要有一个这样的字符串来将代码和XML的属性联系起来。
2.uid是整数,数据结构中需要有一个整型变量
3.多个Package可以声明同一个UID,因此该数据结构必然会保存那些声明了相同sharedUserId的package的某些信息
frameworks/base/services/core/java/com/android/server/pm/SharedUserSetting.java
public final class SharedUserSetting extends SettingBase {
final String name;
int userId;
// flags that are associated with this uid, regardless of any package flags
int uidFlags;
int uidPrivateFlags;
// The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so
// that all apps within the sharedUser run in the same selinux context.
int seInfoTargetSdkVersion;
final ArraySet<PackageSetting> packages = new ArraySet<>();
final PackageSignatures signatures = new PackageSignatures();
Boolean signaturesChanged;
ArrayMap<String, ParsedProcess> processes;
...
}
-
name:共享用户的名称。
-
userId:共享用户的用户ID。
-
uidFlags:与该用户ID关联的标志,不考虑任何包的标志。
-
uidPrivateFlags:与该用户ID关联的私有标志。
-
seInfoTargetSdkVersion:共享用户中所有应用程序的最低targetSdkVersion,用于分配seinfo,以便共享用户中的所有应用程序在相同的SELinux上下文中运行。
-
packages:一个ArraySet,用于存储与该共享用户关联的包设置PackageSetting。
-
signatures:一个PackageSignatures对象,用于存储与该共享用户关联的包的签名信息。
-
signaturesChanged:一个Boolean值,表示与该共享用户关联的包的签名是否发生了变化。
-
processes:一个ArrayMap,用于存储与该共享用户关联的进程信息。
这里是引用PackageSetting是用于存储和管理应用程序包的设置信息的类。
在Android系统中,每个应用程序都有一个对应的PackageSetting对象,用于存储与该应用程序包相关的各种设置和属性,例如包名、版本号、签名信息、权限信息、安装路径等。
PackageSetting类包含了应用程序包的各种属性和成员变量,例如包名、用户ID、应用程序信息、权限信息、签名信息、安装路径等。它还提供了一些方法和接口,用于获取和设置这些属性,以及进行与应用程序包相关的操作,例如安装、卸载、更新等。
XML文件扫描
在卷2的Android4中,PackageManagerService的构造中会直接调用readPermissions方法来读取权限。而Android11中,这个方法在SystemConfig中,叫做readAllPermissions。
PackageManagerService创建了SystemConfig。
SystemConfig的构造方法中调用了readAllPermissions
frameworks/base/core/java/com/android/server/SystemConfig.java
SystemConfig() {
TimingsTraceLog log = new TimingsTraceLog(TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
log.traceBegin("readAllPermissions");
try {
readAllPermissions();
} finally {
log.traceEnd();
}
}
private void readAllPermissions() {
// 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);
// Vendors are only allowed to customize these
int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS
| ALLOW_ASSOCIATIONS;
if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) {
// For backward compatibility
vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);
}
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig"), vendorPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
if (!vendorSkuProperty.isEmpty()) {
String vendorSkuDir = "sku_" + vendorSkuProperty;
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
vendorPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
vendorPermissionFlag);
}
// Allow ODM to customize system configs as much as Vendor, because /odm is another
// vendor partition other than /vendor.
int odmPermissionFlag = vendorPermissionFlag;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
String skuProperty = SystemProperties.get(SKU_PROPERTY, "");
if (!skuProperty.isEmpty()) {
String skuDir = "sku_" + skuProperty;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig", skuDir), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions", skuDir),
odmPermissionFlag);
}
// Allow OEM to customize these
int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), oemPermissionFlag);
// Allow Product to customize all system configs
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
Environment.getProductDirectory(), "etc", "permissions"), ALLOW_ALL);
// Allow /system_ext to customize all system configs
readPermissions(Environment.buildPath(
Environment.getSystemExtDirectory(), "etc", "sysconfig"), ALLOW_ALL);
readPermissions(Environment.buildPath(
Environment.getSystemExtDirectory(), "etc", "permissions"), ALLOW_ALL);
// Skip loading configuration from apex if it is not a system process.
if (!isSystemProcess()) {
return;
}
// Read configuration of libs from apex module.
// TODO: Use a solid way to filter apex module folders?
for (File f: FileUtils.listFilesOrEmpty(Environment.getApexDirectory())) {
if (f.isFile() || f.getPath().contains("@")) {
continue;
}
readPermissions(Environment.buildPath(f, "etc", "permissions"), ALLOW_LIBS);
}
}
@VisibleForTesting
public void readPermissions(File libraryDir, int permissionFlag) {
// Read permissions from given directory.
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
if (permissionFlag == ALLOW_ALL) {
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
File platformFile = null;
for (File f : libraryDir.listFiles()) {
if (!f.isFile()) {
continue;
}
// We'll read platform.xml last
if (f.getPath().endsWith("etc/permissions/platform.xml")) {
platformFile = f;
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, permissionFlag);
}
// Read platform permissions last so it will take precedence
if (platformFile != null) {
readPermissionsFromXml(platformFile, permissionFlag);
}
}
readAllPermissions方法读取了各个目录下的权限配置文件,并进行相应的权限设置。
readPermissions()用于从给定的目录中读取权限配置文件,并进行相应的处理。
注意:在readPermissions()方法中有个逻辑,如果文件的路径以"etc/permissions/platform.xml"结尾,表示这是platform.xml文件,代码会将其保存在platformFile变量中,并继续遍历下一个文件, 最后,代码会读取platformFile中的权限配置,以确保它具有最高的优先级。
以下为Android11,system/etc/permissions/platform.xml的内容:
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- This file is used to define the mappings between lower-level system
user and group IDs and the higher-level permission names managed
by the platform.
Be VERY careful when editing this file! Mistakes made here can open
big security holes.
-->
<permissions>
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- The following tags are associating low-level group IDs with
permission names. By specifying such a mapping, you are saying
that any application process granted the given permission will
also be running with the given group ID attached to its process,
so it can perform any filesystem (read, write, execute) operations
allowed for that group. -->
<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>
<permission name="android.permission.BLUETOOTH" >
<group gid="net_bt" />
</permission>
<permission name="android.permission.BLUETOOTH_STACK" >
<group gid="bluetooth" />
<group gid="wakelock" />
<group gid="uhid" />
</permission>
<permission name="android.permission.NET_TUNNELING" >
<group gid="vpn" />
</permission>
<permission name="android.permission.INTERNET" >
<group gid="inet" />
</permission>
<permission name="android.permission.READ_LOGS" >
<group gid="log" />
</permission>
<permission name="android.permission.MANAGE_EXTERNAL_STORAGE" >
<group gid="external_storage" />
</permission>
<permission name="android.permission.ACCESS_MTP" >
<group gid="mtp" />
</permission>
<permission name="android.permission.NET_ADMIN" >
<group gid="net_admin" />
</permission>
<permission name="android.permission.MAINLINE_NETWORK_STACK" >
<group gid="net_admin" />
<group gid="net_raw" />
</permission>
<!-- The group that /cache belongs to, linked to the permission
set on the applications that can access /cache -->
<permission name="android.permission.ACCESS_CACHE_FILESYSTEM" >
<group gid="cache" />
</permission>
<!-- RW permissions to any system resources owned by group 'diag'.
This is for carrier and manufacture diagnostics tools that must be
installable from the framework. Be careful. -->
<permission name="android.permission.DIAGNOSTIC" >
<group gid="input" />
<group gid="diag" />
</permission>
<!-- Group that can read detailed network usage statistics -->
<permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
<group gid="net_bw_stats" />
</permission>
<!-- Group that can modify how network statistics are accounted -->
<permission name="android.permission.UPDATE_DEVICE_STATS">
<group gid="net_bw_acct" />
</permission>
<permission name="android.permission.LOOP_RADIO" >
<group gid="loop_radio" />
</permission>
<!-- Hotword training apps sometimes need a GID to talk with low-level
hardware; give them audio for now until full HAL support is added. -->
<permission name="android.permission.MANAGE_VOICE_KEYPHRASES">
<group gid="audio" />
</permission>
<permission name="android.permission.ACCESS_BROADCAST_RADIO" >
<!-- /dev/fm is gid media, not audio -->
<group gid="media" />
</permission>
<permission name="android.permission.USE_RESERVED_DISK">
<group gid="reserved_disk" />
</permission>
<!-- These are permissions that were mapped to gids but we need
to keep them here until an upgrade from L to the current
version is to be supported. These permissions are built-in
and in L were not stored in packages.xml as a result if they
are not defined here while parsing packages.xml we would
ignore these permissions being granted to apps and not
propagate the granted state. From N we are storing the
built-in permissions in packages.xml as the saved storage
is negligible (one tag with the permission) compared to
the fragility as one can remove a built-in permission which
no longer needs to be mapped to gids and break grant propagation. -->
<permission name="android.permission.READ_EXTERNAL_STORAGE" />
<permission name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- The following tags are assigning high-level permissions to specific
user IDs. These are used to allow specific core system users to
perform the given operations with the higher-level framework. For
example, we give a wide variety of permissions to the shell user
since that is the user the adb shell runs under and developers and
others should have a fairly open environment in which to
interact with the system. -->
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="media" />
<assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="media" />
<assign-permission name="android.permission.INTERNET" uid="media" />
<assign-permission name="android.permission.INTERNET" uid="shell" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="audioserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="audioserver" />
<assign-permission name="android.permission.WAKE_LOCK" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="audioserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="audioserver" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="audioserver" />
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="cameraserver" />
<assign-permission name="android.permission.WAKE_LOCK" uid="cameraserver" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="cameraserver" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="cameraserver" />
<assign-permission name="android.permission.GET_PROCESS_STATE_AND_OOM_SCORE" uid="cameraserver" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="cameraserver" />
<assign-permission name="android.permission.WATCH_APPOPS" uid="cameraserver" />
<assign-permission name="android.permission.MANAGE_APP_OPS_MODES" uid="cameraserver" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />
<assign-permission name="android.permission.DUMP" uid="incidentd" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="incidentd" />
<assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="incidentd" />
<assign-permission name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL" uid="incidentd" />
<assign-permission name="android.permission.PEEK_DROPBOX_DATA" uid="incidentd" />
<assign-permission name="android.permission.ACCESS_LOWPAN_STATE" uid="lowpan" />
<assign-permission name="android.permission.MANAGE_LOWPAN_INTERFACES" uid="lowpan" />
<assign-permission name="android.permission.DUMP" uid="statsd" />
<assign-permission name="android.permission.PACKAGE_USAGE_STATS" uid="statsd" />
<assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
<assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" />
<assign-permission name="android.permission.REGISTER_STATS_PULL_ATOM" uid="gpu_service" />
<split-permission name="android.permission.ACCESS_FINE_LOCATION">
<new-permission name="android.permission.ACCESS_COARSE_LOCATION" />
</split-permission>
<split-permission name="android.permission.WRITE_EXTERNAL_STORAGE">
<new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
</split-permission>
<split-permission name="android.permission.READ_PRIVILEGED_PHONE_STATE">
<new-permission name="android.permission.READ_PHONE_STATE" />
</split-permission>
<split-permission name="android.permission.READ_CONTACTS"
targetSdk="16">
<new-permission name="android.permission.READ_CALL_LOG" />
</split-permission>
<split-permission name="android.permission.WRITE_CONTACTS"
targetSdk="16">
<new-permission name="android.permission.WRITE_CALL_LOG" />
</split-permission>
<split-permission name="android.permission.ACCESS_FINE_LOCATION"
targetSdk="29">
<new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</split-permission>
<split-permission name="android.permission.ACCESS_COARSE_LOCATION"
targetSdk="29">
<new-permission name="android.permission.ACCESS_BACKGROUND_LOCATION" />
</split-permission>
<split-permission name="android.permission.READ_EXTERNAL_STORAGE"
targetSdk="29">
<new-permission name="android.permission.ACCESS_MEDIA_LOCATION" />
</split-permission>
<!-- This is a list of all the libraries available for application
code to link against. -->
<library name="android.test.base"
file="/system/framework/android.test.base.jar" />
<library name="android.test.mock"
file="/system/framework/android.test.mock.jar"
dependency="android.test.base" />
<library name="android.test.runner"
file="/system/framework/android.test.runner.jar"
dependency="android.test.base:android.test.mock" />
<!-- In BOOT_JARS historically, and now added to legacy applications. -->
<library name="android.hidl.base-V1.0-java"
file="/system/framework/android.hidl.base-V1.0-java.jar" />
<library name="android.hidl.manager-V1.0-java"
file="/system/framework/android.hidl.manager-V1.0-java.jar"
dependency="android.hidl.base-V1.0-java" />
<!-- These are the standard packages that are white-listed to always have internet
access while in power save mode, even if they aren't in the foreground. -->
<allow-in-power-save package="com.android.providers.downloads" />
<!-- These are the standard packages that are white-listed to always have internet
access while in data mode, even if they aren't in the foreground. -->
<allow-in-data-usage-save package="com.android.providers.downloads" />
<!-- This is a core platform component that needs to freely run in the background -->
<allow-in-power-save package="com.android.cellbroadcastreceiver.module" />
<allow-in-power-save package="com.android.cellbroadcastreceiver" />
<allow-in-power-save package="com.android.shell" />
<allow-in-power-save package="com.android.deskclock" />
<allow-in-power-save package="com.android.gallery3d" />
<!-- Whitelist system providers -->
<allow-in-power-save-except-idle package="com.android.providers.calendar" />
<allow-in-power-save-except-idle package="com.android.providers.contacts" />
<!-- The PAC proxy process must have network access, otherwise no app will
be able to connect to the internet when such a proxy is in use, since
all outgoing connections originate from this app. -->
<allow-in-power-save-except-idle package="com.android.proxyhandler" />
<!-- These are the packages that are white-listed to be able to run as system user -->
<system-user-whitelisted-app package="com.android.settings" />
<!-- These are the packages that shouldn't run as system user -->
<system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
</permissions>
<permission name="android.permission.BLUETOOTH_ADMIN" >
<group gid="net_bt_admin" />
</permission>
以上的permission标签建立linux的gid和Android权限之间的联系
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
assign-permission标签向uid添加Android权限
<library name="android.test.mock"
file="/system/framework/android.test.mock.jar"
dependency="android.test.base" />
library用于指定系统库,当应用程序运行时,系统会自动为这些进程加载这些库。
-
allow-in-power-save:这个标签用于指定在省电模式下允许访问互联网的应用程序。例如,com.android.providers.downloads是一个被允许在省电模式下访问互联网的应用程序。
-
allow-in-data-usage-save:这个标签用于指定在数据模式下允许访问互联网的应用程序。例如,com.android.providers.downloads是一个被允许在数据模式下访问互联网的应用程序。
-
allow-in-power-save-except-idle:这个标签用于指定在省电模式下允许访问互联网的应用程序,但不包括空闲模式。例如,com.android.providers.calendar是一个被允许在省电模式下访问互联网,但不包括空闲模式的应用程序。
-
system-user-whitelisted-app:这个标签用于指定被允许以系统用户身份运行的应用程序。例如,com.android.settings是一个被允许以系统用户身份运行的应用程序。
-
system-user-blacklisted-app:这个标签用于指定不允许以系统用户身份运行的应用程序。例如,com.android.wallpaper.livepicker是一个不允许以系统用户身份运行的应用程序。
2.2 构造函数分析之扫描Package
PMS构造函数第一阶段的工作是扫描解析XML文件,第二阶段就是扫描系统中的apk了。
第二阶段首先会进行一些初始化操作,包括创建线程、处理程序和处理器,添加到看门狗机制中,以及添加内置共享库到包管理服务中。这些操作为后续的包管理服务提供了必要的基础设置和准备工作。还会添加共享库之间的依赖关系信息、解析和读取包管理器的设置文件、清理不存在代码路径的孤立包。
之后会进入核心阶段,扫描Package:
final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
PackageParser2 packageParser = new PackageParser2(mSeparateProcesses, mOnlyCore,
mMetrics, mCacheDir, mPackageParserCallback);
ExecutorService executorService = ParallelPackageParser.makeExecutorService();
// Prepare apex package info before scanning APKs, these information are needed when
// scanning apk in apex.
mApexManager.scanApexPackagesTraced(packageParser, executorService);
// Collect vendor/product/system_ext overlay packages. (Do this before scanning
// any apps.)
// For security and version matching reason, only consider overlay packages if they
// reside in the right directory.
for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getOverlayFolder() == null) {
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
scanDirTracedLI(frameworkDir, systemParseFlags,
systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);
if (!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(), systemParseFlags,
systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
preinstallThirdPartyAPK(packageParser,executorService,scanFlags);
代码创建了一个PackageParser2对象packageParser,用于解析APK文件。
代码创建了一个ExecutorService对象executorService,用于并行处理解析APK文件的任务。
-代码调用mApexManager.scanApexPackagesTraced()方法,对APEX包进行扫描和处理。这个操作在扫描APK文件之前进行,因为扫描APEX包时需要相关的信息。
通过一个循环遍历mDirsToScanAsSystem列表,对系统目录中的覆盖包进行扫描和处理。只有当覆盖包所在的目录存在时,才会进行扫描。
代码调用scanDirTracedLI()方法,对指定目录进行扫描和处理。这个方法会传递解析和扫描的标志、packageParser对象和executorService对象。
代码继续调用scanDirTracedLI()方法,对frameworkDir目录进行扫描和处理。这个目录通常包含Android框架的相关文件。
代码检查是否成功加载了名为"android"的框架包,如果没有加载成功,则抛出IllegalStateException异常。
最后,代码通过一个循环遍历mDirsToScanAsSystem列表,对系统目录中的特权应用程序和普通应用程序进行扫描和处理。
最后的方法根据名字来看应该是预安装第三方apk
scanDirTracedLI()方法用于对指定目录进行扫描和处理,方法中主要是调用了scanDirLI方法:
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime,
PackageParser2 packageParser, ExecutorService executorService) {
final 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));
}
ArrayList<String> list = new ArrayList<String>();
boolean isPrebundled = (parseFlags & PackageParser.PARSE_IS_PREBUNDLED_DIR) != 0;
if (isPrebundled) {
synchronized (mPackages) {
mSettings.readPrebundledPackagesLPr();
}
}
if (scanDir.getAbsolutePath().contains(BUNDLED_UNINSTALL_GONE_DIR)) {
if (!readDeleteFile(list)) {
Log.e(TAG, "read data failed");
return;
}
}
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 (file.getAbsolutePath().contains(BUNDLED_UNINSTALL_GONE_DIR)) {
if (list != null && list.size() > 0) {
final boolean isdeleteApk = isDeleteApk(file,parseFlags,list);
if (isdeleteApk) {
// Ignore deleted bundled apps
continue;
}
}
}
parallelPackageParser.submit(file, parseFlags);
fileCount++;
}
// Process results one by one
for (; fileCount > 0; fileCount--) {
ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take();
Throwable throwable = parseResult.throwable;
int errorCode = PackageManager.INSTALL_SUCCEEDED;
if (throwable == null) {
// TODO(toddke): move lower in the scan chain
// Static shared libraries have synthetic package names
if (parseResult.parsedPackage.isStaticSharedLibrary()) {
renameStaticSharedLibraryPackage(parseResult.parsedPackage);
}
try {
addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
currentTime, null);
if (isPrebundled) {
final PackageParser.Package pkg;
try {
pkg = new PackageParser().parsePackage(parseResult.scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
synchronized (mPackages) {
mSettings.markPrebundledPackageInstalledLPr(pkg.packageName);
}
}
} catch (PackageManagerException e) {
errorCode = e.error;
Slog.w(TAG, "Failed to scan " + parseResult.scanFile + ": " + e.getMessage());
}
} else if (throwable instanceof PackageParserException) {
PackageParserException e = (PackageParserException)
throwable;
errorCode = e.error;
Slog.w(TAG, "Failed to parse " + parseResult.scanFile + ": " + e.getMessage());
} else {
throw new IllegalStateException("Unexpected exception occurred while parsing "
+ parseResult.scanFile, throwable);
}
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0 && errorCode != INSTALL_SUCCEEDED) {
mApexManager.reportErrorWithApkInApex(scanDir.getAbsolutePath());
}
// Delete invalid userdata apps
if ((scanFlags & SCAN_AS_SYSTEM) == 0
&& errorCode != PackageManager.INSTALL_SUCCEEDED) {
logCriticalInfo(Log.WARN,
"Deleting invalid package at " + parseResult.scanFile);
removeCodePathLI(parseResult.scanFile);
}
}
if (isPrebundled) {
synchronized (mPackages) {
mSettings.writePrebundledPackagesLPr();
}
}
}
方法中创建了一个ParallelPackageParser对象parallelPackageParser,用于并行解析包。
parallelPackageParser.submit(file, parseFlags); 这句代码是解析包的关键
这里解析完成后,会对结果挨个进行处理,处理时调用的主要函数就是 addForInitLI
ParallelPackageParser:
PMS会对多个目录下的多个apk文件进行解析,工作量巨大,在Android9之后引入ParallelPackageParser类来并发执行解析,ParallelPackageParser使用线程池和队列执行程序的解析任务
frameworks/base/services/core/java/com/android/server/pm/ParallelPackageParser.java
class ParallelPackageParser {
//保存请求结果的队列,会阻塞线程
private final BlockingQueue<ParseResult> mQueue = new ArrayBlockingQueue<>(QUEUE_CAPACITY);
//创建固定线程数的线程池
static ExecutorService makeExecutorService() {
return ConcurrentUtils.newFixedThreadPool(MAX_THREADS, "package-parsing-thread",
Process.THREAD_PRIORITY_FOREGROUND);
}
private final PackageParser2 mPackageParser;
private final ExecutorService mExecutorService;
ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
mPackageParser = packageParser;
mExecutorService = executorService;
}
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();
// Propagate result to callers of take().
// This is helpful to prevent main thread from getting stuck waiting on
// ParallelPackageParser to finish in case of interruption
mInterruptedInThread = Thread.currentThread().getName();
}
});
}
@VisibleForTesting
protected ParsedPackage parsePackage(File scanFile, int parseFlags)
throws PackageParser.PackageParserException {
return mPackageParser.parsePackage(scanFile, parseFlags, true);
}
}
}
submit最后调用到的是PackageParser2的parsePackage方法:
frameworks/base/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@AnyThread
public ParsedPackage parsePackage(File packageFile, int flags, boolean useCaches)
throws PackageParserException {
if (useCaches && mCacher != null) {
ParsedPackage parsed = mCacher.getCachedResult(packageFile, flags);
if (parsed != null) {
return parsed;
}
}
long parseTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
ParseInput input = mSharedResult.get().reset();
ParseResult<ParsingPackage> result = parsingUtils.parsePackage(input, packageFile, flags);
if (result.isError()) {
throw new PackageParserException(result.getErrorCode(), result.getErrorMessage(),
result.getException());
}
ParsedPackage parsed = (ParsedPackage) result.getResult().hideAsParsed();
long cacheTime = LOG_PARSE_TIMINGS ? SystemClock.uptimeMillis() : 0;
if (mCacher != null) {
mCacher.cacheResult(packageFile, flags, parsed);
}
if (LOG_PARSE_TIMINGS) {
parseTime = cacheTime - parseTime;
cacheTime = SystemClock.uptimeMillis() - cacheTime;
if (parseTime + cacheTime > LOG_PARSE_TIMINGS_THRESHOLD_MS) {
Slog.i(TAG, "Parse times for '" + packageFile + "': parse=" + parseTime
+ "ms, update_cache=" + cacheTime + " ms");
}
}
return parsed;
}
调用parsingUtils.parsePackage
frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile,
int flags)
throws PackageParserException {
if (packageFile.isDirectory()) {
return parseClusterPackage(input, packageFile, flags);
} else {
return parseMonolithicPackage(input, packageFile, flags);
}
}
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) throws PackageParserException {
ParseResult<PackageParser.PackageLite> liteResult =
ApkLiteParseUtils.parseMonolithicPackageLite(input, apkFile, flags);
if (liteResult.isError()) {
return input.error(liteResult);
}
final PackageParser.PackageLite lite = liteResult.getResult();
if (mOnlyCoreApps && !lite.coreApp) {
return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
"Not a coreApp: " + apkFile);
}
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
try {
ParseResult<ParsingPackage> result = parseBaseApk(input,
apkFile,
apkFile.getCanonicalPath(),
assetLoader.getBaseAssetManager(), flags);
if (result.isError()) {
return input.error(result);
}
return input.success(result.getResult()
.setUse32BitAbi(lite.use32bitAbi));
} catch (IOException e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to get path: " + apkFile, e);
} finally {
IoUtils.closeQuietly(assetLoader);
}
}
根据是文件夹还是apk,执行不同的方法
parseMonolithicPackage执行parseBaseApk解析apk
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
String codePath, AssetManager assets, int flags) {
final String apkPath = apkFile.getAbsolutePath();
String volumeUuid = null;
if (apkPath.startsWith(PackageParser.MNT_EXPAND)) {
final int end = apkPath.indexOf('/', PackageParser.MNT_EXPAND.length());
volumeUuid = apkPath.substring(PackageParser.MNT_EXPAND.length(), end);
}
if (PackageParser.DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
final int cookie = assets.findCookieForPath(apkPath);
if (cookie == 0) {
return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Failed adding asset path: " + apkPath);
}
//ANDROID_MANIFEST_FILENAME就是Androidmanifest.xml
try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
PackageParser.ANDROID_MANIFEST_FILENAME)) {
final Resources res = new Resources(assets, mDisplayMetrics, null);
ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
parser, flags);
if (result.isError()) {
return input.error(result.getErrorCode(),
apkPath + " (at " + parser.getPositionDescription() + "): "
+ result.getErrorMessage());
}
final ParsingPackage pkg = result.getResult();
if (assets.containsAllocatedTable()) {
final ParseResult<?> deferResult = input.deferError(
"Targeting R+ (version " + Build.VERSION_CODES.R + " and above) requires"
+ " the resources.arsc of installed APKs to be stored uncompressed"
+ " and aligned on a 4-byte boundary",
DeferredError.RESOURCES_ARSC_COMPRESSED);
if (deferResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_RESOURCES_ARSC_COMPRESSED,
deferResult.getErrorMessage());
}
}
ApkAssets apkAssets = assets.getApkAssets()[0];
if (apkAssets.definesOverlayable()) {
SparseArray<String> packageNames = assets.getAssignedPackageIdentifiers();
int size = packageNames.size();
for (int index = 0; index < size; index++) {
String packageName = packageNames.get(index);
Map<String, String> overlayableToActor = assets.getOverlayableMap(packageName);
if (overlayableToActor != null && !overlayableToActor.isEmpty()) {
for (String overlayable : overlayableToActor.keySet()) {
pkg.addOverlayable(overlayable, overlayableToActor.get(overlayable));
}
}
}
}
pkg.setVolumeUuid(volumeUuid);
if ((flags & PackageParser.PARSE_COLLECT_CERTIFICATES) != 0) {
pkg.setSigningDetails(getSigningDetails(pkg, false));
} else {
pkg.setSigningDetails(SigningDetails.UNKNOWN);
}
return input.success(pkg);
} catch (Exception e) {
return input.error(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
"Failed to read manifest from " + apkPath, e);
}
}
XmlResourceParser parser = assets.openXmlResourceParser(cookie,
PackageParser.ANDROID_MANIFEST_FILENAME)这里就是解析Androidmanifest.xml
之后调用了另一个六参的重载方法
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
String codePath, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException, PackageParserException {
final String splitName;
final String pkgName;
ParseResult<Pair<String, String>> packageSplitResult =
ApkLiteParseUtils.parsePackageSplitNames(input, parser, parser);
if (packageSplitResult.isError()) {
return input.error(packageSplitResult);
}
Pair<String, String> packageSplit = packageSplitResult.getResult();
pkgName = packageSplit.first;
splitName = packageSplit.second;
if (!TextUtils.isEmpty(splitName)) {
return input.error(
PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Expected base APK, but found split " + splitName
);
}
final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
try {
final boolean isCoreApp =
parser.getAttributeBooleanValue(null, "coreApp", false);
final ParsingPackage pkg = mCallback.startParsingPackage(
pkgName, apkPath, codePath, manifestArray, isCoreApp);
final ParseResult<ParsingPackage> result =
parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
if (result.isError()) {
return result;
}
return input.success(pkg);
} finally {
manifestArray.recycle();
}
}
调用parseBaseApkTags
private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
TypedArray sa, Resources res, XmlResourceParser parser, int flags)
throws XmlPullParserException, IOException {
ParseResult<ParsingPackage> sharedUserResult = parseSharedUser(input, pkg, sa);
if (sharedUserResult.isError()) {
return sharedUserResult;
}
pkg.setInstallLocation(anInteger(PackageParser.PARSE_DEFAULT_INSTALL_LOCATION,
R.styleable.AndroidManifest_installLocation, sa))
.setTargetSandboxVersion(anInteger(PackageParser.PARSE_DEFAULT_TARGET_SANDBOX,
R.styleable.AndroidManifest_targetSandboxVersion, sa))
/* Set the global "on SD card" flag */
.setExternalStorage((flags & PackageParser.PARSE_EXTERNAL_STORAGE) != 0);
boolean foundApp = false;
final int depth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > depth)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
String tagName = parser.getName();
final ParseResult result;
// TODO(b/135203078): Convert to instance methods to share variables
// <application> has special logic, so it's handled outside the general method
if (PackageParser.TAG_APPLICATION.equals(tagName)) {
if (foundApp) {
if (PackageParser.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);
}
} else {
result = parseBaseApkTag(tagName, input, pkg, res, parser, flags);
}
if (result.isError()) {
return input.error(result);
}
}
if (!foundApp && ArrayUtils.size(pkg.getInstrumentations()) == 0) {
ParseResult<?> deferResult = input.deferError(
"<manifest> does not contain an <application> or <instrumentation>",
DeferredError.MISSING_APP_TAG);
if (deferResult.isError()) {
return input.error(deferResult);
}
}
if (!ParsedAttribution.isCombinationValid(pkg.getAttributions())) {
return input.error(
INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Combination <feature> tags are not valid"
);
}
convertNewPermissions(pkg);
convertSplitPermissions(pkg);
// At this point we can check if an application is not supporting densities and hence
// cannot be windowed / resized. Note that an SDK version of 0 is common for
// pre-Doughnut applications.
if (pkg.getTargetSdkVersion() < DONUT
|| (!pkg.isSupportsSmallScreens()
&& !pkg.isSupportsNormalScreens()
&& !pkg.isSupportsLargeScreens()
&& !pkg.isSupportsExtraLargeScreens()
&& !pkg.isResizeable()
&& !pkg.isAnyDensity())) {
adjustPackageToBeUnresizeableAndUnpipable(pkg);
}
return input.success(pkg);
}
使用循环遍历解析器中的标签,直到遇到文档结束标签或者深度小于初始深度的结束标签。在循环中,代码判断当前标签的类型,如果不是开始标签,则继续下一次循环。
调用parseBaseApplication:
parseBaseApplication方法太长,主要是在解析各个标签:
在这个方法或许可以来强制修改apk的某些属性
自此apk解析完毕,回到PMS继续看addForInitLI方法
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user)
throws PackageManagerException {
...
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags, scanFlags
| SCAN_UPDATE_SIGNATURE, currentTime, user, null);
if (scanResult.success) {
synchronized (mLock) {
boolean appIdCreated = false;
try {
final String pkgName = scanResult.pkgSetting.name;
final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
new ReconcileRequest(
Collections.singletonMap(pkgName, scanResult),
mSharedLibraries,
mPackages,
Collections.singletonMap(
pkgName, getSettingsVersionForPackage(parsedPackage)),
Collections.singletonMap(pkgName,
getSharedLibLatestVersionSetting(scanResult))),
mSettings.mKeySetManagerService);
appIdCreated = optimisticallyRegisterAppId(scanResult);
commitReconciledScanResultLocked(
reconcileResult.get(pkgName), mUserManager.getUserIds());
} catch (PackageManagerException e) {
if (appIdCreated) {
cleanUpAppIdCreation(scanResult);
}
throw e;
}
}
}
if (shouldHideSystemApp) {
synchronized (mLock) {
mSettings.disableSystemPackageLPw(parsedPackage.getPackageName(), true);
}
}
return scanResult.pkgSetting.pkg;
}
调用scanPackageNewLI获取scanResult对象
调用commitReconciledScanResultLocked提交结果,commitReconciledScanResultLocked中调用commitPackageSettings
private void commitPackageSettings(AndroidPackage pkg,
@Nullable AndroidPackage oldPkg, PackageSetting pkgSetting,
final @ScanFlags int scanFlags, boolean chatty, ReconciledPackage reconciledPkg) {
final String pkgName = pkg.getPackageName();
// 判断是不是自定义的ResolverComponentName,这个ResolverComponentName后面再分析
if (mCustomResolverComponentName != null &&
mCustomResolverComponentName.getPackageName().equals(pkg.getPackageName())) {
setUpCustomResolverActivity(pkg, pkgSetting);
}
if (pkg.getPackageName().equals("android")) {
synchronized (mLock) {
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
// The instance stored in PackageManagerService is special cased to be non-user
// specific, so initialize all the needed fields here.
mAndroidApplication = pkg.toAppInfoWithoutState();
mAndroidApplication.flags = PackageInfoUtils.appInfoFlags(pkg, pkgSetting);
mAndroidApplication.privateFlags =
PackageInfoUtils.appInfoPrivateFlags(pkg, pkgSetting);
mAndroidApplication.initForUser(UserHandle.USER_SYSTEM);
if (!mResolverReplaced) {
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_Material_Dialog_Alert;
mResolveActivity.exported = true;
mResolveActivity.enabled = true;
mResolveActivity.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE;
mResolveActivity.configChanges = ActivityInfo.CONFIG_SCREEN_SIZE
| ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE
| ActivityInfo.CONFIG_SCREEN_LAYOUT
| ActivityInfo.CONFIG_ORIENTATION
| ActivityInfo.CONFIG_KEYBOARD
| ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
mResolveInfo.activityInfo = mResolveActivity;
mResolveInfo.priority = 0;
mResolveInfo.preferredOrder = 0;
mResolveInfo.match = 0;
mResolveComponentName = new ComponentName(
mAndroidApplication.packageName, mResolveActivity.name);
}
}
}
...
// writer
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings");
synchronized (mLock) {
// We don't expect installation to fail beyond this point
// 更新mSettings中相关包的数据
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// 存储包信息
mPackages.put(pkg.getPackageName(), pkg);
if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) {
mApexManager.registerApkInApex(pkg);
}
// 把KeySets添加到KeySetManagerService
KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.addScannedPackageLPw(pkg);
// 向mComponentResolver注册
mComponentResolver.addAllComponents(pkg, chatty);
final boolean isReplace =
reconciledPkg.prepareResult != null && reconciledPkg.prepareResult.replace;
// 向mAppsFilter注册
mAppsFilter.addPackage(pkgSetting, isReplace);
// 不允许临时应用程序定义新的权限组
if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
Slog.w(TAG, "Permission groups from package " + pkg.getPackageName()
+ " ignored: instant apps cannot define new permission groups.");
} else {
// 权限组相关处理
mPermissionManager.addAllPermissionGroups(pkg, chatty);
}
// 不允许临时应用程序定义新的权限
if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) {
Slog.w(TAG, "Permissions from package " + pkg.getPackageName()
+ " ignored: instant apps cannot define new permissions.");
} else {
// 权限相关处理
mPermissionManager.addAllPermissions(pkg, chatty);
}
int collectionSize = ArrayUtils.size(pkg.getInstrumentations());
StringBuilder r = null;
int i;
for (i = 0; i < collectionSize; i++) {
ParsedInstrumentation a = pkg.getInstrumentations().get(i);
a.setPackageName(pkg.getPackageName());
// 向mInstrumentation注册
//mInstrumentation 是用来存储 Android 应用中的 instrumentation 类的信息的映射
mInstrumentation.put(a.getComponentName(), a);
if (chatty) {
if (r == null) {
r = new StringBuilder(256);
} else {
r.append(' ');
}
r.append(a.getName());
}
}
if (r != null) {
if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Instrumentation: " + r);
}
if (!pkg.getProtectedBroadcasts().isEmpty()) {
synchronized (mProtectedBroadcasts) {
mProtectedBroadcasts.addAll(pkg.getProtectedBroadcasts());
}
}
if (oldPkg != null) {
// We need to call revokeRuntimePermissionsIfGroupChanged async as permission
// revoke callbacks from this method might need to kill apps which need the
// mPackages lock on a different thread. This would dead lock.
//
// Hence create a copy of all package names and pass it into
// revokeRuntimePermissionsIfGroupChanged. Only for those permissions might get
// revoked. If a new package is added before the async code runs the permission
// won't be granted yet, hence new packages are no problem.
final ArrayList<String> allPackageNames = new ArrayList<>(mPackages.keySet());
AsyncTask.execute(() ->
mPermissionManager.revokeRuntimePermissionsIfGroupChanged(pkg, oldPkg,
allPackageNames));
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
把解析的结果存储到PMS和Settings的相关变量中
自此整个扫描过程结束
之后在构造方法中还会扫描非系统目录的apk
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
packageParser.close();
3、APK Installation分析
apk安装有多种形式,发送广播、手动安装、adb命令等等,所有方式最后都会走到PMS来
下面是packageInstaller中实际执行安装的代码
frameworks/base/packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setInstallAsInstantApp(false);
params.setReferrerUri(getIntent().getParcelableExtra(Intent.EXTRA_REFERRER));
params.setOriginatingUri(getIntent()
.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI));
params.setOriginatingUid(getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
UID_UNKNOWN));
params.setInstallerPackageName(getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME));
params.setInstallReason(PackageManager.INSTALL_REASON_USER);
File file = new File(mPackageURI.getPath());
try {
PackageParser.PackageLite pkg = PackageParser.parsePackageLite(file, 0);
params.setAppPackageName(pkg.packageName);
params.setInstallLocation(pkg.installLocation);
params.setSize(
PackageHelper.calculateInstalledSize(pkg, false, params.abiOverride));
} catch (PackageParser.PackageParserException e) {
Log.e(LOG_TAG, "Cannot parse package " + file + ". Assuming defaults.");
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only apk size.");
params.setSize(file.length());
} catch (IOException e) {
Log.e(LOG_TAG,
"Cannot calculate installed size " + file + ". Try only apk size.");
params.setSize(file.length());
}
try {
mInstallId = InstallEventReceiver
.addObserver(this, EventResultPersister.GENERATE_NEW_ID,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
try {
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
synchronized (this) {
isDone = true;
notifyAll();
}
return null;
}
session.setStagingProgress(0);
try {
File file = new File(mPackageURI.getPath());
try (InputStream in = new FileInputStream(file)) {
long sizeBytes = file.length();
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
byte[] buffer = new byte[1024 * 1024];
while (true) {
int numRead = in.read(buffer);
if (numRead == -1) {
session.fsync(out);
break;
}
if (isCancelled()) {
session.close();
break;
}
out.write(buffer, 0, numRead);
if (sizeBytes > 0) {
float fraction = ((float) numRead / (float) sizeBytes);
session.addProgress(fraction);
}
}
}
}
return session;
} catch (IOException | SecurityException e) {
Log.e(LOG_TAG, "Could not write package", e);
session.close();
return null;
} finally {
synchronized (this) {
isDone = true;
notifyAll();
}
}
}
安装器中主要的安装逻辑就是这个session createSession openSession session.commit
frameworks/base/core/java/android/content/pm/PackageInstaller.java
public void commit(@NonNull IntentSender statusReceiver) {
try {
mSession.commit(statusReceiver, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
commit调用mSession.commit
protected final IPackageInstallerSession mSession;
mSession是IPackageInstallerSession对象 是一个aidl接口
具体实现在frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
if (hasParentSessionId()) {
throw new IllegalStateException(
"Session " + sessionId + " is a child of multi-package session "
+ mParentSessionId + " and may not be committed directly.");
}
if (!markAsSealed(statusReceiver, forTransfer)) {
return;
}
if (isMultiPackage()) {
final SparseIntArray remainingSessions = mChildSessionIds.clone();
final IntentSender childIntentSender =
new ChildStatusIntentReceiver(remainingSessions, statusReceiver)
.getIntentSender();
boolean sealFailed = false;
for (int i = mChildSessionIds.size() - 1; i >= 0; --i) {
final int childSessionId = mChildSessionIds.keyAt(i);
// seal all children, regardless if any of them fail; we'll throw/return
// as appropriate once all children have been processed
if (!mSessionProvider.getSession(childSessionId)
.markAsSealed(childIntentSender, forTransfer)) {
sealFailed = true;
}
}
if (sealFailed) {
return;
}
}
dispatchStreamValidateAndCommit();
}
通过一系列调用,最后在installNonStagedLocked方法调用PMS的installStage
@GuardedBy("mLock")
private void installNonStagedLocked(List<PackageInstallerSession> childSessions)
throws PackageManagerException {
final PackageManagerService.ActiveInstallSession installingSession =
makeSessionActiveLocked();
if (installingSession == null) {
return;
}
if (isMultiPackage()) {
List<PackageManagerService.ActiveInstallSession> installingChildSessions =
new ArrayList<>(childSessions.size());
boolean success = true;
PackageManagerException failure = null;
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
try {
final PackageManagerService.ActiveInstallSession installingChildSession =
session.makeSessionActiveLocked();
if (installingChildSession != null) {
installingChildSessions.add(installingChildSession);
}
} catch (PackageManagerException e) {
failure = e;
success = false;
}
}
if (!success) {
sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId,
isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null,
failure.error, failure.getLocalizedMessage(), null);
return;
}
mPm.installStage(installingChildSessions);
} else {
mPm.installStage(installingSession);
}
}
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void installStage(ActiveInstallSession activeInstallSession) {
if (DEBUG_INSTANT) {
if ((activeInstallSession.getSessionParams().installFlags
& PackageManager.INSTALL_INSTANT_APP) != 0) {
Slog.d(TAG, "Ephemeral install of " + activeInstallSession.getPackageName());
}
}
final Message msg = mHandler.obtainMessage(INIT_COPY);
final InstallParams params = new InstallParams(activeInstallSession);
params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));
mHandler.sendMessage(msg);
}
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
//if(android.provider.Settings.Global.getInt(mContext.getContentResolver(), "allow_install", 1) != 1){
// Toast.makeText(mContext, "No permission, please contact the administrator2", Toast.LENGTH_LONG).show();
// return;
//}
HandlerParams params = (HandlerParams) msg.obj;
if (params != null) {
if (DEBUG_INSTALL) Slog.i(TAG, "init_copy: " + params);
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(params));
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
params.startCopy();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
break;
}
}
}
最后在doHandleMessage的INIT_COPY里执行安装操作,调用了HandlerParams 的startCopy。HandlerParams是一个抽象内部类,这里安装的installStage实现是在内部类InstallParams
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
abstract void handleStartCopy();
abstract void handleReturnCode();
InstallParams中handleStartCopy的实现:
public void handleStartCopy() {
int ret = PackageManager.INSTALL_SUCCEEDED;
// If we're already staged, we've firmly committed to an install location
//根据安装的来源和位置设置安装标志位,以便在后续的安装过程中正确处理安装位置
if (origin.staged) {
if (origin.file != null) {
installFlags |= PackageManager.INSTALL_INTERNAL;
} else {
throw new IllegalStateException("Invalid stage location");
}
}
//获取要安装的包的最小信息,并在需要时尝试释放缓存空间以解决存储空间不足的问题
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
PackageInfoLite pkgLite = null;
//获取最小化的包信息。它接收应用的路径、安装标志位和ABI覆盖参数作为输入,
//并返回一个PackageInfoLite对象,该对象包含了应用的基本信息,如包名、版本号等。
//这个方法通常用于获取应用的元数据信息,以便后续进行安装操作。
//该方法最后会调用到PackageHelper.resolveInstallLocation来确定推荐安装位置
//此处主要是为了获取pkgLite的recommendedInstallLocation值,表示apk推荐安装路径
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
if (DEBUG_INSTANT && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
/*
* If we have too little free space, try to free cache
* before giving up.
*/
if (!origin.staged && pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// TODO: focus freeing disk space on the target device
final StorageManager storage = StorageManager.from(mContext);
final long lowThreshold = storage.getStorageLowBytes(
Environment.getDataDirectory());
final long sizeBytes = PackageManagerServiceUtils.calculateInstalledSize(
origin.resolvedPath, packageAbiOverride);
if (sizeBytes >= 0) {
try {
mInstaller.freeCache(null, sizeBytes + lowThreshold, 0, 0);
pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to free cache", e);
}
}
/*
* The cache free must have deleted the file we downloaded to install.
*
* TODO: fix the "freeCache" call to not delete the file we care about.
*/
if (pkgLite.recommendedInstallLocation
== PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
pkgLite.recommendedInstallLocation
= PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE;
}
}
//根据pkgLite对象的推荐安装位置属性来确定安装的结果,并根据安装位置策略和标志位进一步处理安装位置
if (ret == PackageManager.INSTALL_SUCCEEDED) {
int loc = pkgLite.recommendedInstallLocation;
if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_LOCATION) {
ret = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
} else if (loc == PackageHelper.RECOMMEND_FAILED_ALREADY_EXISTS) {
ret = PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
ret = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_APK) {
ret = PackageManager.INSTALL_FAILED_INVALID_APK;
} else if (loc == PackageHelper.RECOMMEND_FAILED_INVALID_URI) {
ret = PackageManager.INSTALL_FAILED_INVALID_URI;
} else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
} else {
// Override with defaults if needed.
//检查推荐的安装路径,如系统应用不允许安装在sd卡上
loc = installLocationPolicy(pkgLite);
if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
} else if (loc == PackageHelper.RECOMMEND_FAILED_WRONG_INSTALLED_VERSION) {
ret = PackageManager.INSTALL_FAILED_WRONG_INSTALLED_VERSION;
} else if (!onInt) {
// Override install location with flags
if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
// Set the flag to install on external media.
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else if (loc == PackageHelper.RECOMMEND_INSTALL_EPHEMERAL) {
if (DEBUG_INSTANT) {
Slog.v(TAG, "...setting INSTALL_EPHEMERAL install flag");
}
installFlags |= PackageManager.INSTALL_INSTANT_APP;
installFlags &= ~PackageManager.INSTALL_INTERNAL;
} else {
// Make sure the flag for installing on external
// media is unset
installFlags |= PackageManager.INSTALL_INTERNAL;
}
}
}
}
//根据安装位置创建不同的InstallArgs
final InstallArgs args = createInstallArgs(this);
mVerificationCompleted = true;
mIntegrityVerificationCompleted = true;
mEnableRollbackCompleted = true;
mArgs = args;
if (ret == PackageManager.INSTALL_SUCCEEDED) {
final int verificationId = mPendingVerificationToken++;
// Perform package verification (unless we are simply moving the package).
if (!origin.existing) {
PackageVerificationState verificationState =
new PackageVerificationState(this);
mPendingVerification.append(verificationId, verificationState);
//完整性验证
sendIntegrityVerificationRequest(verificationId, pkgLite, verificationState);
ret = sendPackageVerificationRequest(
verificationId, pkgLite, verificationState);
// If both verifications are skipped, we should remove the state.
if (verificationState.areAllVerificationsComplete()) {
mPendingVerification.remove(verificationId);
}
}
if ((installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// TODO(ruhler) b/112431924: Don't do this in case of 'move'?
final int enableRollbackToken = mPendingEnableRollbackToken++;
Trace.asyncTraceBegin(
TRACE_TAG_PACKAGE_MANAGER, "enable_rollback", enableRollbackToken);
mPendingEnableRollback.append(enableRollbackToken, this);
Intent enableRollbackIntent = new Intent(Intent.ACTION_PACKAGE_ENABLE_ROLLBACK);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_TOKEN,
enableRollbackToken);
enableRollbackIntent.putExtra(
PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_SESSION_ID,
mSessionId);
enableRollbackIntent.setType(PACKAGE_MIME_TYPE);
enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Allow the broadcast to be sent before boot complete.
// This is needed when committing the apk part of a staged
// session in early boot. The rollback manager registers
// its receiver early enough during the boot process that
// it will not miss the broadcast.
enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, UserHandle.SYSTEM,
android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// the duration to wait for rollback to be enabled, in millis
long rollbackTimeout = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ROLLBACK,
PROPERTY_ENABLE_ROLLBACK_TIMEOUT_MILLIS,
DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS);
if (rollbackTimeout < 0) {
rollbackTimeout = DEFAULT_ENABLE_ROLLBACK_TIMEOUT_MILLIS;
}
final Message msg = mHandler.obtainMessage(
ENABLE_ROLLBACK_TIMEOUT);
msg.arg1 = enableRollbackToken;
msg.arg2 = mSessionId;
mHandler.sendMessageDelayed(msg, rollbackTimeout);
}
}, null, 0, null, null);
mEnableRollbackCompleted = false;
}
}
mRet = ret;
}
这段代码主要用于处理应用程序的安装过程,包括获取应用程序信息、检查存储空间、生成安装参数、启用回滚等。
@Override
void handleReturnCode() {
if (mVerificationCompleted
&& mIntegrityVerificationCompleted && mEnableRollbackCompleted) {
//模拟安装过程并返回结果
if ((installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
String packageName = "";
ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
new ParseTypeImpl(
(changeId, packageName1, targetSdkVersion) -> {
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.packageName = packageName1;
appInfo.targetSdkVersion = targetSdkVersion;
return mPackageParserCallback.isChangeEnabled(changeId,
appInfo);
}).reset(),
origin.file, 0);
if (result.isError()) {
Slog.e(TAG, "Can't parse package at " + origin.file.getAbsolutePath(),
result.getException());
} else {
packageName = result.getResult().packageName;
}
try {
observer.onPackageInstalled(packageName, mRet, "Dry run", new Bundle());
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
return;
}
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
//拷贝apk 如拷贝到data/app下
mRet = mArgs.copyApk();
}
//处理安装请求 方法中是异步执行
processPendingInstall(mArgs, mRet);
}
}
processPendingInstall
private void processPendingInstall(final InstallArgs args, final int currentStatus) {
if (args.mMultiPackageInstallParams != null) {
args.mMultiPackageInstallParams.tryProcessInstallRequest(args, currentStatus);
} else {
PackageInstalledInfo res = createPackageInstalledInfo(currentStatus);
processInstallRequestsAsync(
res.returnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
// Queue up an async operation since the package installation may take a little while.
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mHandler.post(() -> {
if (success) {
for (InstallRequest request : installRequests) {
request.args.doPreInstall(request.installResult.returnCode);
}
synchronized (mInstallLock) {
installPackagesTracedLI(installRequests);
}
for (InstallRequest request : installRequests) {
request.args.doPostInstall(
request.installResult.returnCode, request.installResult.uid);
}
}
for (InstallRequest request : installRequests) {
restoreAndPostInstall(request.args.user.getIdentifier(), request.installResult,
new PostInstallData(request.args, request.installResult, null));
}
});
}
@GuardedBy({"mInstallLock", "mLock"})
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
installpackageLI执行安装
@GuardedBy("mInstallLock")
private void installPackagesLI(List<InstallRequest> requests) {
final Map<String, ScanResult> preparedScans = new ArrayMap<>(requests.size());
final Map<String, InstallArgs> installArgs = new ArrayMap<>(requests.size());
final Map<String, PackageInstalledInfo> installResults = new ArrayMap<>(requests.size());
final Map<String, PrepareResult> prepareResults = new ArrayMap<>(requests.size());
final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
final Map<String, PackageSetting> lastStaticSharedLibSettings =
new ArrayMap<>(requests.size());
final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
boolean success = false;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
for (InstallRequest request : requests) {
// TODO(b/109941548): remove this once we've pulled everything from it and into
// scan, reconcile or commit.
final PrepareResult prepareResult;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "preparePackage");
prepareResult =
preparePackageLI(request.args, request.installResult);
} catch (PrepareFailure prepareFailure) {
request.installResult.setError(prepareFailure.error,
prepareFailure.getMessage());
request.installResult.origPackage = prepareFailure.conflictingPackage;
request.installResult.origPermission = prepareFailure.conflictingPermission;
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
request.installResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
request.installResult.installerPackageName =
request.args.installSource.installerPackageName;
final String packageName = prepareResult.packageToScan.getPackageName();
prepareResults.put(packageName, prepareResult);
installResults.put(packageName, request.installResult);
installArgs.put(packageName, request.args);
try {
final ScanResult result = scanPackageTracedLI(
prepareResult.packageToScan, prepareResult.parseFlags,
prepareResult.scanFlags, System.currentTimeMillis(),
request.args.user, request.args.abiOverride);
if (null != preparedScans.put(result.pkgSetting.pkg.getPackageName(), result)) {
request.installResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package " + result.pkgSetting.pkg.getPackageName()
+ " in multi-package install request.");
return;
}
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
versionInfos.put(result.pkgSetting.pkg.getPackageName(),
getSettingsVersionForPackage(result.pkgSetting.pkg));
if (result.staticSharedLibraryInfo != null) {
final PackageSetting sharedLibLatestVersionSetting =
getSharedLibLatestVersionSetting(result);
if (sharedLibLatestVersionSetting != null) {
lastStaticSharedLibSettings.put(result.pkgSetting.pkg.getPackageName(),
sharedLibLatestVersionSetting);
}
}
} catch (PackageManagerException e) {
request.installResult.setError("Scanning Failed.", e);
return;
}
}
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults,
prepareResults,
mSharedLibraries,
Collections.unmodifiableMap(mPackages), versionInfos,
lastStaticSharedLibSettings);
CommitRequest commitRequest = null;
synchronized (mLock) {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
reconciledPackages = reconcilePackagesLocked(
reconcileRequest, mSettings.mKeySetManagerService);
} catch (ReconcileFailure e) {
for (InstallRequest request : requests) {
request.installResult.setError("Reconciliation failed...", e);
}
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
commitRequest = new CommitRequest(reconciledPackages,
mUserManager.getUserIds());
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
executePostCommitSteps(commitRequest);
} finally {
if (success) {
for (InstallRequest request : requests) {
final InstallArgs args = request.args;
if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
continue;
}
if (args.signingDetails.signatureSchemeVersion != SIGNING_BLOCK_V4) {
continue;
}
// For incremental installs, we bypass the verifier prior to install. Now
// that we know the package is valid, send a notice to the verifier with
// the root hash of the base.apk.
final String baseCodePath = request.installResult.pkg.getBaseCodePath();
final String[] splitCodePaths = request.installResult.pkg.getSplitCodePaths();
final Uri originUri = Uri.fromFile(args.origin.resolvedFile);
final int verificationId = mPendingVerificationToken++;
final String rootHashString = PackageManagerServiceUtils
.buildVerificationRootHashString(baseCodePath, splitCodePaths);
broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, rootHashString,
args.mDataLoaderType, args.getUser());
}
} else {
for (ScanResult result : preparedScans.values()) {
if (createdAppId.getOrDefault(result.request.parsedPackage.getPackageName(),
false)) {
cleanUpAppIdCreation(result);
}
}
// TODO(patb): create a more descriptive reason than unknown in future release
// mark all non-failure installs as UNKNOWN so we do not treat them as success
for (InstallRequest request : requests) {
if (request.installResult.freezer != null) {
request.installResult.freezer.close();
}
if (request.installResult.returnCode == PackageManager.INSTALL_SUCCEEDED) {
request.installResult.returnCode = PackageManager.INSTALL_UNKNOWN;
}
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
- 首先,创建了一些用于存储安装过程中的结果和临时数据的Map对象,如preparedScans、installArgs、installResults等。
- 创建了一个createdAppId的Map对象,用于存储已创建的应用程序ID。
- 设置一个布尔变量success,用于标记安装过程是否成功。
- 开始一个跟踪标记为TRACE_TAG_PACKAGE_MANAGER的跟踪事件。
- 遍历requests列表中的每个InstallRequest对象。
- 在每个InstallRequest对象中执行以下操作:
- 调用preparePackageLI()方法准备安装包,并将结果存储在prepareResult中。
- 如果准备过程中发生PrepareFailure异常,则将异常信息设置到installResult中,并返回。
- 将installResult的返回码设置为PackageManager.INSTALL_SUCCEEDED。
- 将installResult的安装程序包名设置为installSource的安装程序包名。
- 结束跟踪标记为TRACE_TAG_PACKAGE_MANAGER的跟踪事件。
- 在mLock同步块中执行以下操作:
- 调用reconcilePackagesLocked()方法对准备的安装包进行调和,并将结果存储在reconciledPackages中。
- 如果调和过程中发生ReconcileFailure异常,则将异常信息设置到每个InstallRequest对象的installResult中,并返回。
- 创建一个CommitRequest对象,并将调和结果、用户ID等信息传递给它。
- 在mLock同步块中执行以下操作:
- 调用commitPackagesLocked()方法提交安装包,并将结果存储在commitRequest中。
- 将success设置为true,表示安装过程成功。
- 执行executePostCommitSteps()方法,执行提交后的步骤。
- 最后,如果安装过程成功,则执行以下操作:
- 遍历requests列表中的每个InstallRequest对象。
- 如果args.mDataLoaderType为DataLoaderType.INCREMENTAL,则执行以下操作:
- 关闭installResult中的freezer。
- 将installResult的返回码设置为PackageManager.INSTALL_UNKNOWN。
- 返回。
4、Intent及IntentFilter
主要是PMS里的queryIntentActivities、queryIntentServices、queryBroadcastReceivers这几个方法
书中和Android11的差距有点大,看不懂 ,后面再看。
书中提到的mActivities这个变量在Android11是没有的,但是Android11有mInstrumentation,这是个存储组件的信息的Map,或许在这里面会存Intent相关的信息。