在android系统中,应用的安装方式有多种,本文主要分析通过点击存储的apk安装包进行安装,此时有安装界面以及安装进度显示,需要触发安装apk动作的应用有安装权限。
本文以android13源代码为例进行分析。
如果一个应用触发安装另一个应用的apk文件,需要具有如下权限,即
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
之后通过发送intent来启动安装apk。
File file = new File(Environment.getExternalStorageDirectory().getPath() + "apk_file.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
startActivity(intent);
在上面的代码中,指定数据类型为 application/vnd.android.package-archive,之后就会走到 InstallStart 类。
安装apk,本质上是通过系统的应用packageInstaller.apk来完成的。因此,需要查看的是packageInstaller的源码。
打开 PackageInstaller 的AndroidManifest.xml文件,我们会发现跟上面Intent要启动的Activity匹配的是InstallStart,这也是PackageInstaller应用的入口。
1,在frameworks/base/packages/PackageInstaller/AndroidManifest.xml中
<activity android:name=".InstallStart"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:exported="true"
android:excludeFromRecents="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.intent.action.INSTALL_PACKAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="package" />
<data android:scheme="content" />
</intent-filter>
<intent-filter android:priority="1">
<action android:name="android.content.pm.action.CONFIRM_INSTALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
从上面的代码可以看到,InstallStart 类的过滤器中有 scheme为content,mimeType 为 "application/vnd.android.package-archive"的设置。
2,在frameworks/base/packages/PackageInstaller/src/com/android/package/installer/InstallStart.java中
public class InstallStart extends Activity {
private static final String DOWNLOADS_AUTHORITY = "downloads";
private PackageManager mPackageManager;
private UserManager mUserManager;
private boolean mAbortInstall = false;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPackageManager = getPackageManager();
mUserManager = getSystemService(UserManager.class);
Intent intent = getIntent();
String callingPackage = getCallingPackage();
String callingAttributionTag = null;
// 判断是否需要展示一个确认安装的对话框
final boolean isSessionInstall =
PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
...
final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
final int originatingUid = getOriginatingUid(sourceInfo);
boolean isTrustedSource = false;
if (sourceInfo != null
&& (sourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
// 判断是否勾选“信任未知来源”选项
isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
}
if (!isTrustedSource && originatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
if (targetSdkVersion < 0) {
Log.w(LOG_TAG, "Cannot get target sdk version for uid " + originatingUid);
// Invalid originating uid supplied. Abort install.
mAbortInstall = true;
} else if (targetSdkVersion >= Build.VERSION_CODES.O && !isUidRequestingPermission(
originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
Log.e(LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission "
+ Manifest.permission.REQUEST_INSTALL_PACKAGES);
mAbortInstall = true;
}
}
if (mAbortInstall) {
setResult(RESULT_CANCELED);
finish();
return;
}
Intent nextActivity = new Intent(intent);
nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
if (isSessionInstall) { // 需要确认安装的对话框,则跳转到 PackageInstallerActivity 类。
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Uri packageUri = intent.getData();
// 判断Uri的scheme协议
if (packageUri != null && packageUri.getScheme().equals(
ContentResolver.SCHEME_CONTENT)) { // 是content://则跳转 InstallStaging
// [IMPORTANT] This path is deprecated, but should still work. Only necessary
// features should be added.
// Copy file to prevent it from being changed underneath this process
nextActivity.setClass(this, InstallStaging.class);
} else if (packageUri != null && packageUri.getScheme().equals(
PackageInstallerActivity.SCHEME_PACKAGE)) { // 是 package://则跳转 PackageInstallerActivity
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
Intent result = new Intent();
result.putExtra(Intent.EXTRA_INSTALL_RESULT,
PackageManager.INSTALL_FAILED_INVALID_URI);
setResult(RESULT_FIRST_USER, result);
nextActivity = null;
}
}
if (nextActivity != null) {
startActivity(nextActivity);
}
// finish当前InstallStart界面
finish();
}
}
在上面的代码中,判断Uri的Scheme协议,若是 content:// 则跳转 InstallStaging, 若是 package://则跳转 PackageInstallerActivity。
实际上 InstallStaging 中的 StagingAsyncTask 会将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity。
首先分析下 InstallStaging 类。
3,在frameworks/base/packages/PackageInstaller/serc/com/android/packageinstaller/InstallStaging.java中
public class InstallStaging extends AlertActivity {
/** Currently running task that loads the file from the content URI into a file */
private @Nullable StagingAsyncTask mStagingTask;
private @Nullable File mStagedFile;
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mStagingTask == null) {
// File does not exist, or became invalid
if (mStagedFile == null) {
// Create file delayed to be able to show error
try {
// 将待安装的apk复制一份到data/data对应的目录下
mStagedFile = TemporaryFileManager.getStagedFile(this);
} catch (IOException e) {
showError();
return;
}
}
mStagingTask = new StagingAsyncTask();
mStagingTask.execute(getIntent().getData());
}
}
}
上面的代码中调用 TemporaryFileManager 类的 getStagedFile(this)函数,并执行 StagingAsyncTask 的函数。
首先分析下 getStagedFile 函数,在 TemporaryFileManager.java 中,
public class TemporaryFileManager extends BroadcastReceiver {
/**
* Create a new file to hold a staged file.
*
* @param context The context of the caller
*
* @return A new file
*/
@NonNull
public static File getStagedFile(@NonNull Context context) throws IOException {
return File.createTempFile("package", ".apk", context.getNoBackupFilesDir());
}
}
上面的代码创建了一个临时文件 mStagedFile。
接着分析下 StagingAsyncTask 的函数。
private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
@Override
protected Boolean doInBackground(Uri... params) { // AsyncTask 的核心方法,它在后台线程上执行。它接受一个 Uri 数组作为参数,这个 Uri 指向要读取的数据。
if (params == null || params.length <= 0) {
return false;
}
Uri packageUri = params[0];
try (InputStream in = getContentResolver().openInputStream(packageUri)) { // 打开这个 Uri 指向的输入流(InputStream)
// Despite the comments in ContentResolver#openInputStream the returned stream can
// be null.
if (in == null) {
return false;
}
// 使用 FileOutputStream 将数据写入到 mStagedFile 指向的文件中。数据是以块(1MB大小的缓冲区)的形式读取和写入的。
try (OutputStream out = new FileOutputStream(mStagedFile)) {
byte[] buffer = new byte[1024 * 1024];
int bytesRead;
while ((bytesRead = in.read(buffer)) >= 0) {
// Be nice and respond to a cancellation
if (isCancelled()) {
return false;
}
out.write(buffer, 0, bytesRead);
}
}
} catch (IOException | SecurityException | IllegalStateException e) {
Log.w(LOG_TAG, "Error staging apk from content URI", e);
return false;
}
return true;
}
// onPostExecute 方法在主线程上执行,当 doInBackground 方法完成后被调用。它接受一个 Boolean 类型的参数 success,表示后台任务是否成功完成。
@Override
protected void onPostExecute(Boolean success) {
if (success) {
// Now start the installation again from a file
// 创建一个新的 Intent,设置目标 Activity 为 DeleteStagedFileOnResult,并将 mStagedFile 的 Uri 设置为这个 Intent 的数据。
Intent installIntent = new Intent(getIntent());
installIntent.setClass(InstallStaging.this, DeleteStagedFileOnResult.class);
installIntent.setData(Uri.fromFile(mStagedFile));
if (installIntent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
installIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
}
// 添加 FLAG_ACTIVITY_NO_ANIMATION 标志来启动新的 Activity 时不显示动画。
installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
startActivity(installIntent);
InstallStaging.this.finish();
} else {
showError();
}
}
}
上面的代码将uri从content转为file,之后跳转到 DeleteStagedFileOnResult 函数执行。
4,在frameworks/base/packages/PackageInstaller/serc/com/android/packageinstaller/DeleteStagedFileOnResult.java中
public class DeleteStagedFileOnResult extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 当活动首次创建时(即savedInstanceState为null),它会创建一个新的Intent,这个Intent原本是从启动这个活动的源处获得的,但被重定向到了PackageInstallerActivity。
if (savedInstanceState == null) {
Intent installIntent = new Intent(getIntent());
installIntent.setClass(this, PackageInstallerActivity.class);
installIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
// 代码以 for result 的方式启动 PackageInstallerActivity,这意味着DeleteStagedFileOnResult活动会等待PackageInstallerActivity的结果。
startActivityForResult(installIntent, 0);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
setResult(resultCode, data);
finish();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (isFinishing()) {
// 从启动这个活动的Intent中获取数据URI,并将其转换为文件路径。
File sourceFile = new File(getIntent().getData().getPath());
// 在一个新线程中删除文件
new Thread(sourceFile::delete).start();
}
}
}
DeleteStagedFileOnResult 主要就是跳转到 PackageInstallerActivity 类,然后startActivity,回调之后删除复制的apk文件。
从上面的代码看出,如果 uri scheme 是 content,则通过 InstallStaging 到 DeleteStagedFileOnResult,之后再跳转到 PackageInstallerActivity。
上面第2步骤分析过在 InstallStart 类中,如果是 isSessionInstall 或 uri scheme 为 package,则直接跳转到 PackageInstallerActivity。
5,在frameworks/base/packages/PackageInstaller/serc/com/android/packageinstaller/PackageInstallerActivity.java中
protected void onCreate(Bundle icicle) {
if (mLocalLOGV) Log.i(TAG, "creating for user " + getUserId());
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
super.onCreate(null);
if (icicle != null) {
mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);
}
mPm = getPackageManager(); // 获取当前应用的包管理器(PackageManager)。
mIpm = AppGlobals.getPackageManager(); // 通过AppGlobals.getPackageManager()获取全局的包管理器实例
mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE); // 获取应用操作管理器(AppOpsManager),用于检查应用的特定操作是否被允许。
mInstaller = mPm.getPackageInstaller(); // 获取包安装器(PackageInstaller),用于处理应用安装。
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); // 获取用户管理器(UserManager),用于访问与用户相关的信息和操作。
final Intent intent = getIntent();
// 从启动这个Activity的Intent中获取额外的信息,包括调用包的名称、归因标签、原始源信息、发起者的UID和包名。
mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
mCallingAttributionTag = intent.getStringExtra(EXTRA_CALLING_ATTRIBUTION_TAG);
mSourceInfo = intent.getParcelableExtra(EXTRA_ORIGINAL_SOURCE_INFO);
mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID,
PackageInstaller.SessionParams.UID_UNKNOWN);
mOriginatingPackage = (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN)
? getPackageNameForUid(mOriginatingUid) : null;
final Uri packageUri;
// 如果Intent的动作是PackageInstaller.ACTION_CONFIRM_INSTALL(确认安装),则通过会话ID获取会话信息,并检查会话是否有效(已密封且解析了基础代码路径)。
if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction())) {
final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
finish();
return;
}
// 如果会话有效,则使用会话信息中的解析后的基础代码路径创建URI
mSessionId = sessionId;
packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
mOriginatingURI = null;
mReferrerURI = null;
} else { // 如果动作不是确认安装,则从Intent的数据中获取URI,并尝试获取发起URI和引荐URI。
mSessionId = -1;
packageUri = intent.getData();
mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);
mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
}
// if there's nothing to do, quietly slip into the ether
if (packageUri == null) { // 如果没有指定安装包URI,记录警告日志,设置安装结果为失败(INSTALL_FAILED_INVALID_URI),然后结束Activity。
Log.w(TAG, "Unspecified source");
setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
finish();
return;
}
if (DeviceUtils.isWear(this)) { // 检查是否运行在Wear设备上
showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);
return;
}
// 调用 processPackageUri(packageUri)方法处理URI,并根据返回值(是否设置成功)决定是否继续执行后续操作。
boolean wasSetUp = processPackageUri(packageUri);
if (mLocalLOGV) Log.i(TAG, "wasSetUp: " + wasSetUp);
if (!wasSetUp) {
return;
}
}
上面的代码调用 processPackageUri 函数,该函数接收一个Uri类型的参数 packageUri,这个URI指向要处理的APK文件。
private boolean processPackageUri(final Uri packageUri) { // 接收一个Uri类型的参数packageUri,这个URI指向要处理的APK文件。
mPackageURI = packageUri;
// 通过packageUri.getScheme()获取URI的scheme(协议部分),如file、package等。
final String scheme = packageUri.getScheme();
if (mLocalLOGV) Log.i(TAG, "processPackageUri(): uri=" + packageUri + ", scheme=" + scheme);
switch (scheme) {
case SCHEME_PACKAGE: { // 如果URI的scheme是package,表示URI直接指向一个包名。
try {
// 通过包管理器(mPm)获取包的信息(mPkgInfo),包括权限等。
// 这里使用了PackageManager.GET_PERMISSIONS和PackageManager.MATCH_UNINSTALLED_PACKAGES标志,后者允许获取未安装包的信息。
mPkgInfo = mPm.getPackageInfo(packageUri.getSchemeSpecificPart(),
PackageManager.GET_PERMISSIONS
| PackageManager.MATCH_UNINSTALLED_PACKAGES);
} catch (NameNotFoundException e) {
}
if (mPkgInfo == null) {
Log.w(TAG, "Requested package " + packageUri.getScheme()
+ " not available. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
return false;
}
// 如果找到了包信息,则获取应用程序的标签(名称)和图标,并创建mAppSnippet对象。
CharSequence label = mPm.getApplicationLabel(mPkgInfo.applicationInfo);
if (mLocalLOGV) Log.i(TAG, "creating snippet for " + label);
mAppSnippet = new PackageUtil.AppSnippet(label,
mPm.getApplicationIcon(mPkgInfo.applicationInfo));
} break;
case ContentResolver.SCHEME_FILE: { // 如果URI的scheme是file,表示URI指向一个文件路径。
// 根据文件路径(packageUri.getPath())创建一个File对象
File sourceFile = new File(packageUri.getPath());
// 通过PackageUtil.getPackageInfo方法获取包信息。
mPkgInfo = PackageUtil.getPackageInfo(this, sourceFile,
PackageManager.GET_PERMISSIONS);
// Check for parse errors
if (mPkgInfo == null) {
Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation");
showDialogInner(DLG_PACKAGE_ERROR);
setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK);
return false;
}
if (mLocalLOGV) Log.i(TAG, "creating snippet for local file " + sourceFile);
// 根据文件和应用信息创建mAppSnippet对象。
mAppSnippet = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile);
} break;
default: { // 如果URI的scheme不是上述两种之一,则抛出IllegalArgumentException异常,表示遇到了意外的URI scheme。
throw new IllegalArgumentException("Unexpected URI scheme " + packageUri);
}
}
return true;
}
方法根据提供的APK文件的URI(可以是包名或文件路径),获取相应的包信息,并根据这些信息准备安装过程所需的一些数据(如应用名称、图标等)。如果处理过程中出现错误,它会显示错误对话框,并设置相应的安装失败结果。
上面完成了对PackageInstallerActivity.java中 onCreate 函数的分析,下面看下 onResume 函数。
protected void onResume() {
super.onResume();
if (mLocalLOGV) Log.i(TAG, "onResume(): mAppSnippet=" + mAppSnippet);
if (mAppSnippet != null) {
// load dummy layout with OK button disabled until we override this layout in
// startInstallConfirm
bindUi();
checkIfAllowedAndInitiateInstall();
}
if (mOk != null) {
mOk.setEnabled(mEnableOk);
}
}
在上面的函数中调用 checkIfAllowedAndInitiateInstall 函数检查是否有权限安装应用程序,并根据检查结果采取相应的行动。
private void checkIfAllowedAndInitiateInstall() {
// Check for install apps user restriction first.
// 使用mUserManager.getUserRestrictionSource()方法检查当前用户是否有UserManager.DISALLOW_INSTALL_APPS(禁止安装应用程序)的限制。
final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
// 如果这个限制来源于系统(UserManager.RESTRICTION_SOURCE_SYSTEM),则记录日志,显示一个对话框(DLG_INSTALL_APPS_RESTRICTED_FOR_USER),并返回,不继续执行后续代码。
if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
if (mLocalLOGV) Log.i(TAG, "install not allowed: " + UserManager.DISALLOW_INSTALL_APPS);
showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
return;
} else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
// 如果这个限制不是由系统设置的,但确实存在(即不是UserManager.RESTRICTION_NOT_SET),则记录日志,
// 启动一个意图(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS),用于显示管理员支持详情,然后结束当前Activity并返回。
if (mLocalLOGV) {
Log.i(TAG, "install not allowed by admin; showing "
+ Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
}
startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
finish();
return;
}
// 如果允许从未知来源安装(mAllowUnknownSources为true),或者当前安装请求不是来自未知来源(isInstallRequestFromUnknownSource(getIntent())返回false),则记录日志,并调用initiateInstall()方法来开始安装过程。
if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
if (mLocalLOGV) Log.i(TAG, "install allowed");
initiateInstall();
} else {// 如果不是上述情况,即安装请求来自未知来源且未允许从未知来源安装,则进一步检查未知来源的限制。
// Check for unknown sources restrictions.
// 使用mUserManager.getUserRestrictionSource()方法分别检查当前用户是否有UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES(禁止从未知来源安装)
// 和UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY(全局禁止从未知来源安装)的限制。
final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, Process.myUserHandle());
final int systemRestriction = UserManager.RESTRICTION_SOURCE_SYSTEM
& (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
if (systemRestriction != 0) { // 如果这些限制中任何一个来源于系统(通过位运算检查),则记录日志,并显示一个对话框(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER)。
if (mLocalLOGV) Log.i(TAG, "Showing DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER");
showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
} else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
// 如果UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES的限制不是由系统设置的,但确实存在,则调用startAdminSupportDetailsActivity()方法,并传入相应的限制代码。
startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
} else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
// 如果全局未知来源安装的限制不是由系统设置的,但确实存在,则同样调用startAdminSupportDetailsActivity()方法,并传入全局限制的代码。
startAdminSupportDetailsActivity(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
} else {
handleUnknownSources();
}
}
}
上面代码中,如果所有检查都通过,则调用 initiateInstall() 方法来开始安装过程,调用 initiatenstall()检查应用列表判断该应用是否已安装,若已安装则提示该应用已安装,由用户决定是否替换,然后显示确认安装界面。
private void initiateInstall() {
String pkgName = mPkgInfo.packageName; // 从mPkgInfo对象中获取当前处理的软件包的包名,并将其存储在pkgName字符串变量中。
// Check if there is already a package on the device with this name
// but it has been renamed to something else.
// 通过调用mPm.canonicalToCurrentPackageNames方法,检查设备上是否存在具有相同名称但已被重命名的软件包。
// 如果找到了这样的软件包,则更新pkgName变量及其相关对象(mPkgInfo和mPkgInfo.applicationInfo)的包名为这个新名称。
String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName });
if (oldName != null && oldName.length > 0 && oldName[0] != null) {
pkgName = oldName[0];
mPkgInfo.packageName = pkgName;
mPkgInfo.applicationInfo.packageName = pkgName;
}
// Check if package is already installed. display confirmation dialog if replacing pkg
try {
// This is a little convoluted because we want to get all uninstalled
// apps, but this may include apps with just data, and if it is just
// data we still want to count it as "installed".
// 通过调用mPm.getApplicationInfo方法,并传入PackageManager.MATCH_UNINSTALLED_PACKAGES标志,尝试获取软件包的信息。这个标志允许获取那些标记为已卸载但实际上可能只是删除了数据的软件包的信息。
mAppInfo = mPm.getApplicationInfo(pkgName,
PackageManager.MATCH_UNINSTALLED_PACKAGES);
// 检查返回的ApplicationInfo对象的flags字段是否包含FLAG_INSTALLED标志。如果不包含,说明软件包实际上未安装(可能只是数据被删除了),因此将mAppInfo设置为null。
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
mAppInfo = null;
}
} catch (NameNotFoundException e) {
// 如果在尝试获取软件包信息时抛出NameNotFoundException异常,同样将mAppInfo设置为null,表示软件包未找到或未安装。
mAppInfo = null;
}
startInstallConfirm();
}
上面的代码中调用了 startInstallConfirm 函数。
private void startInstallConfirm() {
View viewToEnable;
if (mAppInfo != null) {
viewToEnable = requireViewById(R.id.install_confirm_question_update);
mOk.setText(R.string.update);
} else {
// This is a new application with no permissions.
viewToEnable = requireViewById(R.id.install_confirm_question);
}
viewToEnable.setVisibility(View.VISIBLE);
mEnableOk = true;
mOk.setEnabled(true);
mOk.setFilterTouchesWhenObscured(true);
}
上面分析了onResume函数中的 checkIfAllowedAndInitiateInstall();函数,在onResume函数中还有一个bindUi函数,下面分析下bindUi函数。
private void bindUi() {
mAlert.setIcon(mAppSnippet.icon);
mAlert.setTitle(mAppSnippet.label);
mAlert.setView(R.layout.install_content_view);
mAlert.setButton(DialogInterface.BUTTON_POSITIVE, getString(R.string.install),
(ignored, ignored2) -> {
if (mOk.isEnabled()) {
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, true);
finish();
} else {
startInstall();
}
}
}, null);
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
(ignored, ignored2) -> {
// Cancel and finish
setResult(RESULT_CANCELED);
if (mSessionId != -1) {
mInstaller.setPermissionsResult(mSessionId, false);
}
finish();
}, null);
setupAlert();
mOk = mAlert.getButton(DialogInterface.BUTTON_POSITIVE);
mOk.setEnabled(false);
if (!mOk.isInTouchMode()) {
mAlert.getButton(DialogInterface.BUTTON_NEGATIVE).requestFocus();
}
}
上面的代码中,在点击了确定按钮后执行 startInstall 函数。
private void startInstall() {
// Start subactivity to actually install the application
// 创建一个新的 Intent 对象 newIntent,用于启动安装过程的子活动。
Intent newIntent = new Intent();
// 通过 putExtra 方法向 newIntent 添加一个额外的数据,键为 PackageUtil.INTENT_ATTR_APPLICATION_INFO,值为 mPkgInfo.applicationInfo。
// 这里 mPkgInfo 是一个包含应用程序信息的对象,applicationInfo 是其中的一个属性,包含了应用程序的基本信息。
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
// 通过 setClass 方法设置 newIntent 的目标组件为当前上下文(this)和 InstallInstalling.class,即安装过程中的一个具体活动类。
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
// 通过多个 if 语句检查并添加额外的数据到 newIntent 中,包括安装程序的包名(installerPackageName)、原始 URI(mOriginatingURI)、引用 URI(mReferrerURI)、
// 原始用户 ID(mOriginatingUid)等。这些数据可能用于在安装过程中提供额外的上下文或信息。
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
// 检查启动当前活动的 Intent 是否包含 EXTRA_RETURN_RESULT 额外数据,并且其值为 true。如果是,那么也在 newIntent 中添加这个额外数据,表示安装完成后需要返回结果。
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
// 通过 addFlags 方法向 newIntent 添加一个标志 FLAG_ACTIVITY_FORWARD_RESULT,这个标志的作用是将结果数据从当前活动直接传递给下一个接收 newIntent 的活动,而不是返回给启动当前活动的那个活动。
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if (mLocalLOGV) Log.i(TAG, "downloaded app uri=" + mPackageURI);
startActivity(newIntent);
finish();
}
上面的代码中 startInstall 方法用来跳转到 InstallInstalling 类文件,并关闭掉当前的 PackageInstallerActivity。
6,在frameworks/base/packages/PackageInstaller/serc/com/android/packageinstaller/InstallInstalling.java中
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 从启动此 Activity 的 Intent 中获取 ApplicationInfo 对象和应用程序包的 URI。
ApplicationInfo appInfo = getIntent()
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mPackageURI = getIntent().getData();
if ("package".equals(mPackageURI.getScheme())) {
try {
// 如果应用程序包的 URI 方案是 "package",则尝试通过包管理器安装已存在的包。
getPackageManager().installExistingPackage(appInfo.packageName);
launchSuccess();// 如果安装成功,则调用 launchSuccess 方法。
} catch (PackageManager.NameNotFoundException e) {
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
} else {
// 创建一个 File 对象,指向安装包的路径。
final File sourceFile = new File(mPackageURI.getPath());
// 使用 PackageUtil.getAppSnippet 方法获取应用程序的图标和标签,并设置到警告对话框(mAlert)中。
PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
mAlert.setIcon(as.icon);
mAlert.setTitle(as.label);
mAlert.setView(R.layout.install_content_view);
// 取消按钮的点击事件会取消安装任务,放弃会话,并结束当前 Activity。
mAlert.setButton(DialogInterface.BUTTON_NEGATIVE, getString(R.string.cancel),
(ignored, ignored2) -> {
if (mInstallingTask != null) {
mInstallingTask.cancel(true);
}
if (mSessionId > 0) {
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
mSessionId = 0;
}
setResult(RESULT_CANCELED);
finish();
}, null);
setupAlert();
requireViewById(R.id.installing).setVisibility(View.VISIBLE);
if (savedInstanceState != null) { // 如果存在保存的实例状态(即 savedInstanceState 不为 null),则恢复会话 ID 和安装 ID。
mSessionId = savedInstanceState.getInt(SESSION_ID);
mInstallId = savedInstanceState.getInt(INSTALL_ID);
// Reregister for result; might instantly call back if result was delivered while
// activity was destroyed
try {
// 重新注册安装事件的观察者,以便在安装完成时接收结果。
InstallEventReceiver.addObserver(this, mInstallId,
this::launchFinishBasedOnResult);
} catch (EventResultPersister.OutOfIdsException e) {
// Does not happen
}
} else { // 如果不存在保存的实例状态,则配置一个新的安装会话。
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
final Uri referrerUri = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);
// 设置会话参数,包括安装模式、包来源、是否作为即时应用安装、引用 URI、原始 URI、原始用户 ID、安装程序包名和安装原因。
params.setPackageSource(
referrerUri != null ? PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE
: PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE);
params.setInstallAsInstantApp(false);
params.setReferrerUri(referrerUri);
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 {
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
// 尝试解析安装包以获取更多信息,并根据解析结果设置会话参数的大小和应用程序包名等。
final ParseResult<PackageLite> result = ApkLiteParseUtils.parsePackageLite(
input.reset(), file, /* flags */ 0);
if (result.isError()) {
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());
} else {
final PackageLite pkg = result.getResult();
params.setAppPackageName(pkg.getPackageName());
params.setInstallLocation(pkg.getInstallLocation());
params.setSize(InstallLocationUtils.calculateInstalledSize(pkg,
params.abiOverride));
}
} 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(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
try {
// 创建安装会话,并获取会话 ID。
mSessionId = getPackageManager().getPackageInstaller().createSession(params);
} catch (IOException e) {
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
}
}
// 获取并配置取消按钮。
mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
}
}
上面的代码中通过注册观察者 InstallEventReceiver 监听安装成功和失败的回调,跳转到对应结果页面。
在AndroidManifest.xml文件中,
<receiver android:name=".InstallEventReceiver"
android:permission="android.permission.INSTALL_PACKAGES"
android:exported="false">
<intent-filter android:priority="1">
<action android:name="com.android.packageinstaller.ACTION_INSTALL_COMMIT" />
</intent-filter>
</receiver>
在 launchFinishBasedOnResult 函数中,
private void launchFinishBasedOnResult(int statusCode, int legacyStatus, String statusMessage) {
if (statusCode == PackageInstaller.STATUS_SUCCESS) {
launchSuccess();
} else {
launchFailure(statusCode, legacyStatus, statusMessage);
}
}
上面的代码涵盖了从解析安装包信息、配置安装会话参数、处理安装过程中的各种情况(如已存在包的安装、新安装包的处理、恢复安装状态等),到最终更新 UI 以反映安装状态或错误信息的整个流程。
下面分析下 onResume 函数。
protected void onResume() {
super.onResume();
// This is the first onResume in a single life of the activity
if (mInstallingTask == null) { // 如果mInstallingTask为null,意味着这是第一次调用。
// 通过getPackageManager().getPackageInstaller()获取PackageInstaller实例。PackageInstaller是一个用于管理应用安装会话的类。
PackageInstaller installer = getPackageManager().getPackageInstaller();
// 使用mSessionId(一个之前在onCreate中已经获得的会话ID)从PackageInstaller中获取SessionInfo对象。这个对象包含了关于安装会话的信息。
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
// 检查sessionInfo是否不为null且会话是否不再处于活动状态(即安装过程已经完成或取消)。
// 如果这两个条件都满足,那么创建一个新的InstallingAsyncTask实例(很可能是一个异步任务,用于处理安装完成后的逻辑)并执行它。
if (sessionInfo != null && !sessionInfo.isActive()) {
mInstallingTask = new InstallingAsyncTask();
mInstallingTask.execute();
} else {
// we will receive a broadcast when the install is finished
mCancelButton.setEnabled(false); // 如果会话仍然处于活动状态(意味着安装过程还在进行中),则禁用取消按钮(mCancelButton)
// 设置setFinishOnTouchOutside(false),这意味着用户不能通过触摸Activity外部来关闭它。这通常是为了防止用户在安装过程中意外关闭安装界面。
setFinishOnTouchOutside(false);
}
}
}
上面的代码中生成 InstallingAsyncTask 类的实例并执行。
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
PackageInstaller.Session> {
// 由于isDone是volatile的,它保证了变量的可见性,即当一个线程修改了isDone的值时,其他线程会立即看到这个修改。
volatile boolean isDone;
@Override
protected PackageInstaller.Session doInBackground(Void... params) {
PackageInstaller.Session session;
try {
// 打开与给定会话ID(mSessionId)相关联的安装会话。
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
} catch (IOException e) {
synchronized (this) {
isDone = true;
notifyAll();
}
return null;
}
session.setStagingProgress(0);
try {
// 创建一个File对象,其路径是从mPackageURI获取的。
File file = new File(mPackageURI.getPath());
// 使用try-with-resources语句打开文件输入流(FileInputStream),以确保在操作完成后自动关闭流。in用于从文件中读取数据。
try (InputStream in = new FileInputStream(file)) {
// 获取文件的大小(以字节为单位),用于后续进度更新。
long sizeBytes = file.length();
// 使用try-with-resources语句打开输出流(OutputStream),这次是通过session.openWrite方法。
try (OutputStream out = session
.openWrite("PackageInstaller", 0, sizeBytes)) {
// 创建一个1MB大小的缓冲区,用于在读取和写入操作之间传输数据。
byte[] buffer = new byte[1024 * 1024];
while (true) {// 开始一个无限循环,用于连续读取文件直到结束。
// 从输入流in读取数据到缓冲区buffer中,numRead表示实际读取的字节数。
int numRead = in.read(buffer);
// 检查是否到达文件末尾(read方法返回-1表示没有更多数据可读)。
if (numRead == -1) {
// 确保所有写入操作都被物理写入到存储中。fsync方法用于同步输出流。
session.fsync(out);
break;
}
if (isCancelled()) { // 检查是否有取消操作发生
session.close();
break;
}
// 将缓冲区中的数据写入输出流。
out.write(buffer, 0, numRead);
if (sizeBytes > 0) { // 检查文件大小是否大于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();
}
}
}
@Override
protected void onPostExecute(PackageInstaller.Session session) {
if (session != null) { // 如果会话不为null,表示安装过程成功,它会创建一个广播意图(Intent),并设置相关的标志和额外数据。
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
broadcastIntent.setPackage(getPackageName());
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
// 创建一个PendingIntent,并将其与安装会话的提交操作相关联。PendingIntent允许在将来的某个时刻执行一个意图,即使创建它的组件(如Activity)已经不存在了。
PendingIntent pendingIntent = PendingIntent.getBroadcast(
InstallInstalling.this,
mInstallId,
broadcastIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
// 提交安装会话,禁用取消按钮,并设置不允许通过触摸外部来关闭Activity。
session.commit(pendingIntent.getIntentSender());
mCancelButton.setEnabled(false);
setFinishOnTouchOutside(false);
} else { // 如果会话为null,表示安装过程失败,它会放弃会话ID,并根据情况启动失败处理逻辑。
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
if (!isCancelled()) {
launchFailure(PackageInstaller.STATUS_FAILURE,
PackageManager.INSTALL_FAILED_INVALID_APK, null);
}
}
}
}
上面的代码中在异步任务中的onPostExecute方法中执行 session.commit(pendingIntent.getIntentSender()) session的类型是 PackageInstaller.Session。
7,在frameworks/base/core/java/android/content/pm/PackageInstaller.java中
public class PackageInstaller {
public static class Session implements Closeable {
/** {@hide} */
protected final IPackageInstallerSession mSession;
/** {@hide} */
public Session(IPackageInstallerSession session) {
mSession = session;
}
public void commit(@NonNull IntentSender statusReceiver) {
try {
mSession.commit(statusReceiver, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
在上面的代码中,IPackageInstallerSession 是一个aidl文件,类 PackageInstallerSession 继承 IPackageInstallerSession.Stub。
8,在frameworks/base/services/core/java/com/android/server/pm/PackageInstallerSession.java中
public class PackageInstallerSession extends IPackageInstallerSession.Stub {
private static final int MSG_ON_SESSION_SEALED = 1;
private final Handler mHandler;
@Override
public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
...
dispatchSessionSealed();
}
}
上面的代码调用 dispatchSessionSealed 函数。
private void dispatchSessionSealed() {
mHandler.obtainMessage(MSG_ON_SESSION_SEALED).sendToTarget();
}
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MSG_ON_SESSION_SEALED:
handleSessionSealed();
break;
case MSG_STREAM_VALIDATE_AND_COMMIT:
handleStreamValidateAndCommit();
break;
case MSG_INSTALL:
handleInstall();
break;
}
return true;
}
}
上面的mHandlerCallback在 PackageInstallerSession 构造函数中创建Handler实例时被调用,mHandler = new Handler(looper, mHandlerCallback);
上面的代码中调用 handleSessionSealed 函数。
private void handleSessionSealed() {
assertSealed("dispatchSessionSealed");
// Persist the fact that we've sealed ourselves to prevent
// mutations of any hard links we create.
mCallback.onSessionSealedBlocking(this);
dispatchStreamValidateAndCommit();
}
private void dispatchStreamValidateAndCommit() {
mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
}
@WorkerThread
private void handleStreamValidateAndCommit() {
try {
// This will track whether the session and any children were validated and are ready to
// progress to the next phase of install
// 声明一个布尔变量allSessionsReady并初始化为true。这个变量将用于跟踪当前会话及其所有子会话是否都已验证并准备好进入安装的下一个阶段。
boolean allSessionsReady = true;
// 遍历getChildSessions()方法返回的所有子会话(PackageInstallerSession对象)。
// 对于每个子会话,调用其streamValidateAndCommit方法,并使用逻辑与(&=)操作符更新allSessionsReady变量的值。
// 如果任何子会话的streamValidateAndCommit方法返回false,则allSessionsReady也将变为false。
for (PackageInstallerSession child : getChildSessions()) {
allSessionsReady &= child.streamValidateAndCommit();
}
// 如果所有会话(包括当前会话)都已准备好(即allSessionsReady为true),并且当前会话的streamValidateAndCommit方法也返回true,
// 则通过消息处理器(mHandler)发送一个消息(MSG_INSTALL)
if (allSessionsReady && streamValidateAndCommit()) {
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}
} catch (PackageManagerException e) {
destroy();
String msg = ExceptionUtils.getCompleteMessage(e);
dispatchSessionFinished(e.error, msg, null);
maybeFinishChildSessions(e.error, msg);
}
}
@WorkerThread
private void handleInstall() {
// 如果当前设备是安装器设备所有者(Device Owner)或者相关联的配置文件所有者(Affiliated Profile Owner),
// 则创建一个事件日志,标记为INSTALL_PACKAGE,并设置安装源(通过getInstallSource().installerPackageName获取安装器包名),然后写入这个日志。这通常用于记录和管理设备上的应用程序安装活动。
if (isInstallerDeviceOwnerOrAffiliatedProfileOwner()) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
.setAdmin(getInstallSource().installerPackageName)
.write();
}
/**
* Stops the installation of the whole session set if one session needs user action
* in its belong session set. When the user answers the yes,
* {@link #setPermissionsResult(boolean)} is called and then {@link #MSG_INSTALL} is
* handled to come back here to check again.
*/
// 如果确实需要发送一个待处理的用户操作意图(Intent),则方法会返回,不执行后续的代码。
if (sendPendingUserActionIntentIfNeeded()) {
return;
}
if (params.isStaged) { // 如果安装参数(params)标记为分阶段(isStaged),则调用mStagedSession.verifySession()方法来验证分阶段会话。
mStagedSession.verifySession();
} else { // 如果不是分阶段安装,则调用verify()方法来验证安装。
verify();
}
}
上面的代码中调用 verify 函数。
private void verify() {
try {
// 调用getChildSessions方法获取子会话列表,这个列表的类型是List<PackageInstallerSession>,即PackageInstallerSession对象的列表。
List<PackageInstallerSession> children = getChildSessions();
if (isMultiPackage()) {
// 如果是多包安装,遍历每个子会话(PackageInstallerSession对象),对每个子会话调用prepareInheritedFiles方法准备继承的文件,然后调用parseApkAndExtractNativeLibraries方法解析APK并提取原生库。
for (PackageInstallerSession child : children) {
child.prepareInheritedFiles();
child.parseApkAndExtractNativeLibraries();
}
} else {
// 不是多包安装,直接对当前会话调用prepareInheritedFiles和parseApkAndExtractNativeLibraries方法。
prepareInheritedFiles();
parseApkAndExtractNativeLibraries();
}
// 无论是否为多包安装,都调用verifyNonStaged方法进行非分阶段验证。
verifyNonStaged();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
// 调用PackageManager.installStatusToString(e.error, completeMsg)方法,将异常的错误码和完整消息转换成人类可读的错误字符串。
final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg);
setSessionFailed(e.error, errorMsg);
onSessionVerificationFailure(e.error, errorMsg);
}
}
上面的代码调用 verifyNonStaged 函数。
private void verifyNonStaged() throws PackageManagerException {
synchronized (mLock) {
markStageDirInUseLocked();
}
// 通过mSessionProvider获取一个会话验证器(getSessionVerifier()),然后调用其verify方法来验证当前会话。
// verify方法接受一个回调接口,这个接口有两个参数:error和msg,分别用于表示验证结果和可能的错误消息。
mSessionProvider.getSessionVerifier().verify(this, (error, msg) -> {
// 使用mHandler.post(() -> { ... })将回调逻辑发送到消息队列中处理,这通常是为了避免在UI线程或主线程中执行耗时操作。
mHandler.post(() -> {
// 调用dispatchPendingAbandonCallback()方法检查是否有待处理的放弃回调,如果有,则直接返回,不再继续执行后续逻辑。
if (dispatchPendingAbandonCallback()) {
// No need to continue if abandoned
return;
}
if (error == INSTALL_SUCCEEDED) { // 调用onVerificationComplete()方法处理验证成功的逻辑。
onVerificationComplete();
} else { // 调用onSessionVerificationFailure(error, msg)方法处理验证失败的逻辑。
onSessionVerificationFailure(error, msg);
}
});
});
}
上面代码的主要作用是在一个同步的上下文中,通过会话验证器来验证当前的会话或包,然后根据验证结果执行相应的回调逻辑。
上面的代码调用 onVerificationComplete 函数。
private void onVerificationComplete() {
if (isStaged()) {
mStagingManager.commitSession(mStagedSession);
sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
return;
}
install();
}
上面的代码调用 install 函数。
private CompletableFuture<Void> install() {
// 调用installNonStaged方法,该方法返回一个CompletableFuture<InstallResult>对象的列表。每个CompletableFuture对象都代表一个异步的安装任务,这些任务可能并行执行。
List<CompletableFuture<InstallResult>> futures = installNonStaged();
// 创建了一个与futures列表大小相同的CompletableFuture<InstallResult>数组,并通过futures.toArray(arr)方式将列表转换为数组,以便传递给CompletableFuture.allOf方法
CompletableFuture<InstallResult>[] arr = new CompletableFuture[futures.size()];
// CompletableFuture.allOf方法接受一个CompletableFuture对象的数组,并返回一个新的CompletableFuture对象。这个新的对象在所有传入的CompletableFuture对象都完成时才会完成。
return CompletableFuture.allOf(futures.toArray(arr)).whenComplete((r, t) -> {
if (t == null) { // 如果t == null,表示所有安装任务都成功完成
setSessionApplied();
// 遍历futures列表,对每个CompletableFuture<InstallResult>对象调用join方法以获取其结果,并调用dispatchSessionFinished方法发送安装成功的通知。
for (CompletableFuture<InstallResult> f : futures) {
InstallResult result = f.join();
result.session.dispatchSessionFinished(
INSTALL_SUCCEEDED, "Session installed", result.extras);
}
} else {
// 从异常中获取PackageManagerException的实例,并提取错误代码和消息。
PackageManagerException e = (PackageManagerException) t.getCause();
// 调用setSessionFailed方法标记会话失败,并可能调用dispatchSessionFinished和maybeFinishChildSessions方法发送失败通知和处理相关子会话。
setSessionFailed(e.error,
PackageManager.installStatusToString(e.error, e.getMessage()));
dispatchSessionFinished(e.error, e.getMessage(), null);
maybeFinishChildSessions(e.error, e.getMessage());
}
});
}
上面的代码调用了 installNonStaged 函数。
private List<CompletableFuture<InstallResult>> installNonStaged() {
try {
// 创建了一个 ArrayList<CompletableFuture<InstallResult>> 类型的 futures 列表,用于存储每个安装操作的 CompletableFuture 对象。
List<CompletableFuture<InstallResult>> futures = new ArrayList<>();
// 创建了一个 CompletableFuture<InstallResult> 类型的 future 对象,并将其添加到 futures 列表中。
CompletableFuture<InstallResult> future = new CompletableFuture<>();
futures.add(future);
// 调用 makeInstallParams(future) 方法,传入刚刚创建的 future 对象,以生成安装参数 installingSession。
final InstallParams installingSession = makeInstallParams(future);
if (isMultiPackage()) {
// 获取子会话列表 childSessions,并为每个子会话创建一个新的 CompletableFuture 对象和安装参数。
final List<PackageInstallerSession> childSessions = getChildSessions();
List<InstallParams> installingChildSessions = new ArrayList<>(childSessions.size());
for (int i = 0; i < childSessions.size(); ++i) {
final PackageInstallerSession session = childSessions.get(i);
future = new CompletableFuture<>();
futures.add(future);
final InstallParams installingChildSession = session.makeInstallParams(future);
if (installingChildSession != null) { // 如果子会话的安装参数不为空,则将其添加到 installingChildSessions 列表中。
installingChildSessions.add(installingChildSession);
}
}
// 如果 installingChildSessions 列表不为空,则调用 installingSession.installStage(installingChildSessions) 方法来开始安装过程。
if (!installingChildSessions.isEmpty()) {
installingSession.installStage(installingChildSessions);
}
} else if (installingSession != null) {
// 调用 installingSession.installStage() 方法来开始安装过程。
installingSession.installStage();
}
return futures;
} catch (PackageManagerException e) {
List<CompletableFuture<InstallResult>> futures = new ArrayList<>();
futures.add(CompletableFuture.failedFuture(e));
return futures;
}
}
上面的代码通过 InstallParams 类型的对象 installingSession 调用 installStage 函数。
9,在frameworks/base/services/core/java/com/android/server/pm/InstallParams.java中
final class InstallParams extends HandlerParams {
public void installStage() {
final Message msg = mPm.mHandler.obtainMessage(INIT_COPY);
setTraceMethod("installStage").setTraceCookie(System.identityHashCode(this));
msg.obj = this;
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));
mPm.mHandler.sendMessage(msg);
}
}
上面的代码中 InstallParams 继承自 HandlerParams。
在 HandlerParams.java 中定义有 final PackageManagerService mPm;
在 PackageManagerService.java 中定义有 final Handler mHandler;
在 PackageManagerService 的构造函数中对mHandler进行赋值,
即 mHandler = injector.getHandler();
而在 PackageManagerService 的构造函数中 定义有一个 injector 变量。
在该变量的定义中,它接收多个参数,并通过这些参数初始化一系列的服务和组件。这些参数包括上下文(context)、锁(lock)、安装器(installer)、安装锁(installLock)、以及其他各种服务和组件的工厂方法或实例。
通过lambda表达式或方法引用,为各种服务提供工厂方法,这些服务包括ComponentResolver、PermissionManagerService、UserManagerService等。
// PackageManagerServiceInjector是一个依赖注入容器,用于提供PackageManagerService所需的各种服务和组件。
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, onlyCore),
lock),
......
(i, pm) -> new PackageInstallerService(
i.getContext(), pm, i::getScanningPackageParser),
(i, pm) -> {
HandlerThread thread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DEFAULT, true /*allowIo*/);
thread.start();
return new PackageHandler(thread.getLooper(), pm);
},
(i, pm) -> new SharedLibrariesImpl(pm, i)
);
在上面的代码中,创建了一个HandlerThread对象,并为其指定了一个线程名(TAG)、线程优先级(Process.THREAD_PRIORITY_DEFAULT),以及一个标志(true,允许IO操作)。
调用thread.start()启动线程。创建一个PackageHandler对象,并将其返回。
这个PackageHandler对象是在新启动的线程的Looper上运行的。
通过在新线程上创建的Looper来返回一个新的PackageHandler对象。这个PackageHandler对象将在新线程的上下文中处理消息,允许PackageManagerService在不阻塞主线程的情况下执行某些操作。
从 injector中获取的handler即是PackageHandler。
上面的代码中通过mPm.mHandler构建并发送消息,会走到 PackageHandler.java中。
10,在frameworks/base/services/core/java/com/android/server/pm/PackageHandler.java中
final class PackageHandler extends Handler {
private final PackageManagerService mPm; //在构造函数中由传递的参数进行赋值
@Override
public void handleMessage(Message msg) {
try {
doHandleMessage(msg);
} finally {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
}
}
void doHandleMessage(Message msg) {
switch (msg.what) {
case INIT_COPY: {
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;
}
}
}
}
上面的代码调用 HandlerParams类的 startCopy 函数。
11,在frameworks/base/services/core/java/com/android/server/pm/HandlerParams.java中
abstract class HandlerParams {
final void startCopy() {
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);
handleStartCopy();
handleReturnCode();
}
abstract void handleStartCopy();
abstract void handleReturnCode();
}
上面的代码中,HandlerParams 是抽象类,handleStartCopy 会走到实现类 InstallParams 中。
12,在frameworks/base/services/core/java/com/android/server/pm/InstallParams.java中
public void handleStartCopy() {
// 这行代码检查安装标志(mInstallFlags)是否包含PackageManager.INSTALL_APEX。如果是,表示正在安装的是一个APEX模块,不是传统意义上的APK。
if ((mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
mRet = INSTALL_SUCCEEDED;
return;
}
// 获取一个轻量版的包信息(PackageInfoLite),用于后续的安装过程。
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mPm.mContext,
mPackageLite, mOriginInfo.mResolvedPath, mInstallFlags, mPackageAbiOverride);
// For staged session, there is a delay between its verification and install. Device
// state can change within this delay and hence we need to re-verify certain conditions.
boolean isStaged = (mInstallFlags & INSTALL_STAGED) != 0;
if (isStaged) {
// 如果是分阶段安装,调用verifyReplacingVersionCode方法验证替换的版本码是否符合要求。
Pair<Integer, String> ret = mInstallPackageHelper.verifyReplacingVersionCode(
pkgLite, mRequiredInstalledVersionCode, mInstallFlags);
mRet = ret.first;
if (mRet != INSTALL_SUCCEEDED) {
return;
}
}
// 检查安装标志是否包含INSTALL_INSTANT_APP,以判断是否是即时应用(Instant App)。
final boolean ephemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
if (DEBUG_INSTANT && ephemeral) {
Slog.v(TAG, "pkgLite for install: " + pkgLite);
}
// 检查是否不是分阶段安装且推荐的安装位置因为存储空间不足而失败
if (!mOriginInfo.mStaged && pkgLite.recommendedInstallLocation
== InstallLocationUtils.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
// If we are not staged and have too little free space, try to free cache
// before giving up.
// 如果是存储空间不足导致安装失败,则尝试清理缓存以腾出空间,并更新推荐的安装位置。
pkgLite.recommendedInstallLocation = mPm.freeCacheForInstallation(
pkgLite.recommendedInstallLocation, mPackageLite,
mOriginInfo.mResolvedPath, mPackageAbiOverride, mInstallFlags);
}
// 调用overrideInstallLocation方法,根据包名、推荐的安装位置和原始的安装位置来决定最终的安装位置,并更新安装结果(mRet)。
mRet = overrideInstallLocation(pkgLite.packageName, pkgLite.recommendedInstallLocation,
pkgLite.installLocation);
}
上面的代码根据不同的安装标志(如APEX模块、分阶段安装、即时应用等)和存储条件来决定是否继续安装过程,并更新安装结果。
下面分析下 handleReturnCode 函数。
@Override
void handleReturnCode() {
processPendingInstall();
}
上面的代码调用 processPendingInstall 函数。
private void processPendingInstall() {
InstallArgs args = createInstallArgs(this);
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
// 调用InstallArgs对象的copyApk方法,该方法负责将APK文件从源位置复制到目标位置。这个方法的返回值(成功或失败)被赋值给mRet,用于表示当前步骤的结果。
mRet = args.copyApk();
}
// 再次检查mRet是否为成功。这一步确保了APK文件已经成功复制,之后可以执行与文件处理相关的后续步骤。
if (mRet == PackageManager.INSTALL_SUCCEEDED) {
// 调用F2fsUtils.releaseCompressedBlocks方法,释放APK文件所在文件系统(可能是F2FS)中压缩的块。这个步骤是为了优化存储性能和空间使用。args.getCodePath()返回APK文件的路径。
F2fsUtils.releaseCompressedBlocks(
mPm.mContext.getContentResolver(), new File(args.getCodePath()));
}
if (mParentInstallParams != null) {
mParentInstallParams.tryProcessInstallRequest(args, mRet);
} else {
// 如果mParentInstallParams为空,则创建一个PackageInstalledInfo对象,传入当前的安装结果(mRet)
PackageInstalledInfo res = new PackageInstalledInfo(mRet);
// 调用processInstallRequestsAsync方法,
// 它接受两个参数:一个布尔值,表示安装是否成功(通过比较res.mReturnCode和PackageManager.INSTALL_SUCCEEDED得出);
// 另一个是包含InstallRequest对象的列表,这个对象封装了当前的安装参数(args)和安装结果信息(res)。
processInstallRequestsAsync(
res.mReturnCode == PackageManager.INSTALL_SUCCEEDED,
Collections.singletonList(new InstallRequest(args, res)));
}
}
上面的代码中 processPendingInstall 函数现在执行了 args.copyApk() 和调用 processInstallRequestsAsync 函数。
先看下 copyApk 函数。
InstallArgs 是一个抽象类,
abstract class InstallArgs {
abstract int copyApk();
abstract int doPreInstall(int status);
abstract int doPostInstall(int status, int uid);
int doPreCopy() {
return PackageManager.INSTALL_SUCCEEDED;
}
int doPostCopy(int uid) {
return PackageManager.INSTALL_SUCCEEDED;
}
}
copyApk 函数在抽象类 InstallArgs 的实现类 FileInstallArgs 中实现。
在InstallParams.java中
int copyApk() {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
try {
return doCopyApk();
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
上面的代码调用 doCopyApk 函数。
private int doCopyApk() {
if (mOriginInfo.mStaged) {
if (DEBUG_INSTALL) Slog.d(TAG, mOriginInfo.mFile + " already staged; skipping copy");
mCodeFile = mOriginInfo.mFile;
return PackageManager.INSTALL_SUCCEEDED;
}
try {
// 判断是否为即时应用:通过检查 mInstallFlags 是否包含 PackageManager.INSTALL_INSTANT_APP 标志来判断。
final boolean isEphemeral = (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
// 分配临时目录:调用 InstallerService 的 allocateStageDirLegacy 方法分配一个临时目录,用于存放APK的副本。这个目录的分配考虑了卷UUID和是否为即时应用。
final File tempDir =
mPm.mInstallerService.allocateStageDirLegacy(mVolumeUuid, isEphemeral);
// 设置APK文件路径:将分配的临时目录设置为 mCodeFile。
mCodeFile = tempDir;
} catch (IOException e) {
Slog.w(TAG, "Failed to create copy file: " + e);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
// 调用 PackageManagerServiceUtils.copyPackage 方法,将原始APK文件复制到 mCodeFile 指定的位置。
int ret = PackageManagerServiceUtils.copyPackage(
mOriginInfo.mFile.getAbsolutePath(), mCodeFile);
if (ret != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, "Failed to copy package");
return ret;
}
final boolean isIncremental = isIncrementalPath(mCodeFile.getAbsolutePath());
// 设置库根目录:创建一个指向APK文件内库目录的 File 对象。
final File libraryRoot = new File(mCodeFile, LIB_DIR_NAME);
// 创建一个 NativeLibraryHelper.Handle 对象,用于处理原生库文件。
NativeLibraryHelper.Handle handle = null;
try {
// 复制原生库文件:调用 NativeLibraryHelper.copyNativeBinariesWithOverride 方法,根据是否增量和ABI覆盖选项复制原生库文件。
// 如果复制过程中发生IOException,则打印错误信息,并将返回值设置为 PackageManager.INSTALL_FAILED_INTERNAL_ERROR。
handle = NativeLibraryHelper.Handle.create(mCodeFile);
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
mAbiOverride, isIncremental);
} catch (IOException e) {
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
IoUtils.closeQuietly(handle);
}
return ret;
}
doCopyApk() 先获取了拷贝文件路径:/data/app,使用PackageManagerServiceUtils.copyPackage()进行APK拷贝,接着是 .so文件的拷贝。
再看下 processInstallRequestsAsync 函数。
private void processInstallRequestsAsync(boolean success,
List<InstallRequest> installRequests) {
mPm.mHandler.post(() -> {
mInstallPackageHelper.processInstallRequests(success, installRequests);
});
}
mInstallPackageHelper是在父类 HandlerParams中声明并在父类构造函数中初始化,
即 final InstallPackageHelper mInstallPackageHelper;mInstallPackageHelper = new InstallPackageHelper(mPm);
上面的代码中方法 processInstallRequestsAsync 接受两个参数:一个布尔值 success,表示安装是否成功;一个 List 类型的 installRequests,包含了一个或多个安装请求。在函数体中调用 processInstallRequests 函数。
13,在frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java中
public void processInstallRequests(boolean success, List<InstallRequest> installRequests) {
// 初始化了两个列表apexInstallRequests和apkInstallRequests,用于分别存储APEX包和APK包的安装请求。
List<InstallRequest> apexInstallRequests = new ArrayList<>();
List<InstallRequest> apkInstallRequests = new ArrayList<>();
// 遍历输入的installRequests列表。
for (InstallRequest request : installRequests) {
// 对于每个请求,通过检查request.mArgs.mInstallFlags与PackageManager.INSTALL_APEX的位运算结果,来判断该请求是APEX包的安装请求还是APK包的安装请求,并分别添加到相应的列表中。
if ((request.mArgs.mInstallFlags & PackageManager.INSTALL_APEX) != 0) {
apexInstallRequests.add(request);
} else {
apkInstallRequests.add(request);
}
}
// Note: supporting multi package install of both APEXes and APKs might requir some
// thinking to ensure atomicity of the install.
// 如果同时有APEX和APK的安装请求,代码会抛出一个IllegalStateException异常,提示不允许同时进行APEX和APK的多包安装。
if (!apexInstallRequests.isEmpty() && !apkInstallRequests.isEmpty()) {
// This should've been caught at the validation step, but for some reason wasn't.
throw new IllegalStateException(
"Attempted to do a multi package install of both APEXes and APKs");
}
if (!apexInstallRequests.isEmpty()) {
if (success) {// 如果存在APEX安装请求且安装成功(success为true),则创建一个新线程异步执行installApexPackagesTraced方法,该方法需要与外部服务(如apexd)通信。
// Since installApexPackages requires talking to external service (apexd), we
// schedule to run it async. Once it finishes, it will resume the install.
Thread t = new Thread(() -> installApexPackagesTraced(apexInstallRequests),
"installApexPackages");
t.start();
} else { // 如果安装失败(success为false),则只通知第一个APEX安装请求的观察者关于安装失败的信息。
// Non-staged APEX installation failed somewhere before
// processInstallRequestAsync. In that case just notify the observer about the
// failure.
InstallRequest request = apexInstallRequests.get(0);
mPm.notifyInstallObserver(request.mInstallResult,
request.mArgs.mObserver);
}
return;
}
if (success) {
// 如果存在APK安装请求且安装成功(success为true),则首先对每个请求执行doPreInstall方法
for (InstallRequest request : apkInstallRequests) {
request.mArgs.doPreInstall(request.mInstallResult.mReturnCode);
}
// 在同步块中调用installPackagesTracedLI方法执行实际的安装操作
synchronized (mPm.mInstallLock) {
installPackagesTracedLI(apkInstallRequests);
}
// 对每个请求执行doPostInstall方法。
for (InstallRequest request : apkInstallRequests) {
request.mArgs.doPostInstall(
request.mInstallResult.mReturnCode, request.mInstallResult.mUid);
}
}
for (InstallRequest request : apkInstallRequests) {
// 调用restoreAndPostInstall()进行 备份、可能的回滚、发送安装完成相关广播
restoreAndPostInstall(request.mArgs.mUser.getIdentifier(),
request.mInstallResult,
new PostInstallData(request.mArgs,
request.mInstallResult, null));
}
}
上面的代码中调用了 installPackagesTracedLI 和 restoreAndPostInstall 函数。
先分析下 installPackagesTracedLI 函数。
@GuardedBy("mPm.mInstallLock")
private void installPackagesTracedLI(List<InstallRequest> requests) {
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackages");
installPackagesLI(requests);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
上面的代码调用 installPackagesLI 函数。
@GuardedBy("mPm.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, Settings.VersionInfo> versionInfos = 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对象。
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");
// 调用preparePackageLI方法准备安装包,如果准备失败(抛出PrepareFailure异常),则设置安装结果为失败,并返回。
prepareResult =
preparePackageLI(request.mArgs, request.mInstallResult);
} catch (PrepareFailure prepareFailure) {
request.mInstallResult.setError(prepareFailure.error,
prepareFailure.getMessage());
request.mInstallResult.mOrigPackage = prepareFailure.mConflictingPackage;
request.mInstallResult.mOrigPermission = prepareFailure.mConflictingPermission;
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
// 准备成功则设置安装结果的返回码为成功,并记录安装源(installerPackageName)。
request.mInstallResult.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
request.mInstallResult.mInstallerPackageName =
request.mArgs.mInstallSource.installerPackageName;
final String packageName = prepareResult.mPackageToScan.getPackageName();
// 将准备结果(PrepareResult)和安装包信息存入相应的Map中。
prepareResults.put(packageName, prepareResult);
installResults.put(packageName, request.mInstallResult);
installArgs.put(packageName, request.mArgs);
try {
// 调用scanPackageTracedLI方法扫描准备好的安装包。
final ScanResult result = scanPackageTracedLI(
prepareResult.mPackageToScan, prepareResult.mParseFlags,
prepareResult.mScanFlags, System.currentTimeMillis(),
request.mArgs.mUser, request.mArgs.mAbiOverride);
// 如果扫描过程中发现重复的包(即同一个包名已经在preparedScans中存在),则设置安装结果为失败(INSTALL_FAILED_DUPLICATE_PACKAGE),并返回。
if (null != preparedScans.put(result.mPkgSetting.getPkg().getPackageName(),
result)) {
request.mInstallResult.setError(
PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE,
"Duplicate package "
+ result.mPkgSetting.getPkg().getPackageName()
+ " in multi-package install request.");
return;
}
// 检查应用存储一致性:通过 checkNoAppStorageIsConsistent 方法检查旧包和新包的 PROPERTY_NO_APP_DATA_STORAGE 属性是否一致。
if (!checkNoAppStorageIsConsistent(
result.mRequest.mOldPkg, result.mPkgSetting.getPkg())) {
// TODO: INSTALL_FAILED_UPDATE_INCOMPATIBLE is about incomptabible
// signatures. Is there a better error code?
// 如果不一致,则设置安装结果为失败(INSTALL_FAILED_UPDATE_INCOMPATIBLE),并返回。
request.mInstallResult.setError(
INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"Update attempted to change value of "
+ PackageManager.PROPERTY_NO_APP_DATA_STORAGE);
return;
}
// 调用optimisticallyRegisterAppId方法尝试注册应用ID,并将结果记录到createdAppId中。
createdAppId.put(packageName, optimisticallyRegisterAppId(result));
// 通过mPm.getSettingsVersionForPackage方法获取并记录包的版本信息。
versionInfos.put(result.mPkgSetting.getPkg().getPackageName(),
mPm.getSettingsVersionForPackage(result.mPkgSetting.getPkg()));
} catch (PackageManagerException e) {
request.mInstallResult.setError("Scanning Failed.", e);
return;
}
}
// 创建一个ReconcileRequest对象,这个对象包含了准备安装的扫描结果、安装参数、安装结果、准备结果、不可修改的包映射以及版本信息。
ReconcileRequest reconcileRequest = new ReconcileRequest(preparedScans, installArgs,
installResults, prepareResults,
Collections.unmodifiableMap(mPm.mPackages), versionInfos);
CommitRequest commitRequest = null;
synchronized (mPm.mLock) {
Map<String, ReconciledPackage> reconciledPackages;
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "reconcilePackages");
// 调用ReconcilePackageUtils.reconcilePackages方法,传入reconcileRequest、共享库、密钥集管理服务以及包管理器的设置,以进行包的协调处理。
// 协调处理的结果是一个Map<String, ReconciledPackage>,包含了协调后的包信息。
reconciledPackages = ReconcilePackageUtils.reconcilePackages(
reconcileRequest, mSharedLibraries,
mPm.mSettings.getKeySetManagerService(), mPm.mSettings);
} catch (ReconcileFailure e) {
// 如果在协调过程中发生ReconcileFailure异常,则遍历所有的安装请求,将安装结果设置为错误,并返回。
for (InstallRequest request : requests) {
request.mInstallResult.setError("Reconciliation failed...", e);
}
return;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
try {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "commitPackages");
// 创建一个CommitRequest对象,传入协调后的包信息和用户ID列表。
commitRequest = new CommitRequest(reconciledPackages,
mPm.mUserManager.getUserIds());
// 调用commitPackagesLocked方法,传入commitRequest,执行包的提交操作。
commitPackagesLocked(commitRequest);
success = true;
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
executePostCommitSteps(commitRequest);
} finally {
if (success) {
// 如果成功,遍历所有的安装请求,对于使用增量数据加载器且签名方案版本为V4的包,发送一个包验证的广播,包含验证ID、原始URI、验证允许标志、根哈希字符串、数据加载器类型、用户ID以及上下文。
for (InstallRequest request : requests) {
final InstallArgs args = request.mArgs;
if (args.mDataLoaderType != DataLoaderType.INCREMENTAL) {
continue;
}
if (args.mSigningDetails.getSignatureSchemeVersion() != 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.mInstallResult.mPkg.getBaseApkPath();
final String[] splitCodePaths = request.mInstallResult.mPkg.getSplitCodePaths();
final Uri originUri = Uri.fromFile(args.mOriginInfo.mResolvedFile);
final int verificationId = mPm.mPendingVerificationToken++;
final String rootHashString = PackageManagerServiceUtils
.buildVerificationRootHashString(baseCodePath, splitCodePaths);
VerificationUtils.broadcastPackageVerified(verificationId, originUri,
PackageManager.VERIFICATION_ALLOW, rootHashString,
args.mDataLoaderType, args.getUser(), mContext);
}
} else {
// 如果失败,遍历所有的扫描结果,对于创建了应用ID但安装失败的包,执行清理操作。然后,将非失败安装的结果标记为INSTALL_UNKNOWN,表示未知状态。
for (ScanResult result : preparedScans.values()) {
if (createdAppId.getOrDefault(result.mRequest.mParsedPackage.getPackageName(),
false)) {
cleanUpAppIdCreation(result);
}
}
// TODO(b/194319951): create a more descriptive reason than unknown
// mark all non-failure installs as UNKNOWN so we do not treat them as success
for (InstallRequest request : requests) {
if (request.mInstallResult.mFreezer != null) {
request.mInstallResult.mFreezer.close();
}
if (request.mInstallResult.mReturnCode == PackageManager.INSTALL_SUCCEEDED) {
request.mInstallResult.mReturnCode = PackageManager.INSTALL_UNKNOWN;
}
}
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
}
上面的代码中分别调用了 preparePackageLI, scanPackageTracedLI, reconcilePackages, commitPackagesLocked, executePostCommitSteps 等函数。
在 preparePackageLI() 内使用 PackageParser2.parsePackage() 解析AndroidManifest.xml,获取四大组件等信息;
使用ParsingPackageUtils.getSigningDetails() 解析签名信息;重命名包最终路径 等。
在 scanPackageTracedLI 中,根据准备阶段解析的包信息上下文 进一步解析:确认包名真实;根据解析出的信息校验包有效性(是否有签名信息等);搜集apk信息——PackageSetting、apk的静态库/动态库信息等。
在 reconcilePackages 中,验证扫描后的包信息,确保安装成功:主要就是覆盖安装的签名匹配验证。
在 commitPackagesLocked 中,提交扫描的包、更新系统状态:添加 PackageSetting 到 PMS 的 mSettings、添加 AndroidPackage 到 PMS 的 mPackages 、添加 秘钥集 到系统、应用的权限添加到 mPermissionManager、四大组件信息添加到 mComponentResolver 。这是唯一可以修改系统状态的地方,并且要对所有可预测的错误进行检测。
安装完成后,调用 executePostCommitSteps 准备app数据,执行dex优化: prepareAppDataAfterInstallLIF 函数提供目录结构/data/user/用户ID/包名/cache(/data/user/用户ID/包名/code_cache)。 mPackageDexOptimizer.performDexOpt():dexopt 是对 dex 文件 进行 verification 和 optimization 的操作,其对 dex 文件的优化结果变成了 odex 文件,这个文件和 dex 文件很像,只是使用了一些优化操作码(譬如优化调用虚拟指令等)。
14,在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() {
IBinder binder = ServiceManager.getService("installd");
if (binder != null) {
try {
// 为该IBinder注册一个死亡监听器(linkToDeath方法)。这个监听器会在installd服务死亡时被调用。
binder.linkToDeath(() -> {
Slog.w(TAG, "installd died; reconnecting");
mInstalldLatch = new CountDownLatch(1);
connect();
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
// 通过IInstalld.Stub.asInterface(binder)方法创建一个IInstalld接口的代理对象
IInstalld installd = IInstalld.Stub.asInterface(binder);
mInstalld = installd;
mInstalldLatch.countDown();
try {
invalidateMounts();
executeDeferredActions();
} catch (InstallerException ignored) {
}
} else {
Slog.w(TAG, "installd not found; trying again");
BackgroundThread.getHandler().postDelayed(this::connect, CONNECT_RETRY_DELAY_MS);
}
}
}
在 Installer 的 onStart()方法中 通过 installd 的Binder对象获取了 mInstalld 实例。
上面分析了 installPackagesTracedLI 函数,下面分析下 restoreAndPostInstall 函数。
15,在frameworks/base/service/core/java/com/android/server/pm/InstallPackageHelper.java中
public void restoreAndPostInstall(int userId, PackageInstalledInfo res, @Nullable PostInstallData data) {
// 如果没有执行恢复操作(无论是常规的还是回滚的),则直接触发后续安装工作请求。
if (!doRestore) {
// No restore possible, or the Backup Manager was mysteriously not
// available -- just fire the post-install work request directly.
if (DEBUG_INSTALL) Log.v(TAG, "No restore - queue post-install for " + token);
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "postInstall", token);
Message msg = mPm.mHandler.obtainMessage(POST_INSTALL, token, 0);
mPm.mHandler.sendMessage(msg);
}
}
整个方法的目的是在安装过程完成后,根据安装的类型(新安装、更新或降级)和是否需要恢复数据,来决定是否执行恢复操作,并最终触发后续安装工作请求,如执行观察者回调和广播等。 mHandler 使用 PMS的 handlePackagePostInstall()方法处理 POST_INSTALL.
16,在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 POST_INSTALL: {
if (DEBUG_INSTALL) Log.v(TAG, "Handling post-install for " + msg.arg1);
// 通过msg.arg1作为键获取到对应的PostInstallData对象,这个对象包含了安装后的数据
PostInstallData data = mPm.mRunningInstalls.get(msg.arg1);
// 通过msg.arg2的值判断是否有进行恢复操作(didRestore),如果msg.arg2不为0,则表示有进行恢复。
final boolean didRestore = (msg.arg2 != 0);
// 从mPm.mRunningInstalls中删除当前处理完毕的安装任务,表示该任务已经完成。
mPm.mRunningInstalls.delete(msg.arg1);
if (data != null && data.res.mFreezer != null) {
data.res.mFreezer.close();
}
// 判断data对象中的mPostInstallRunnable(一个表示安装后需要执行的操作的Runnable对象)是否为空
if (data != null && data.mPostInstallRunnable != null) {
data.mPostInstallRunnable.run();
} else if (data != null && data.args != null) {
// 如果mPostInstallRunnable为空,但data.args(安装后的参数)不为空,则调用mInstallPackageHelper.handlePackagePostInstall方法处理安装后的逻辑,传入安装结果、参数和是否恢复的标志。
mInstallPackageHelper.handlePackagePostInstall(data.res, data.args, didRestore);
} else if (DEBUG_INSTALL) {
// No post-install when we run restore from installExistingPackageForUser
Slog.i(TAG, "Nothing to do for post-install token " + msg.arg1);
}
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
}
break;
}
}
}
上面的代码调用 handlePackagePostInstall 函数。
17,在frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java中
final class InstallPackageHelper {
void handlePackagePostInstall(PackageInstalledInfo res, InstallArgs installArgs, boolean launchedForRestore) {
// 判断是否需要杀死应用(killApp),这取决于安装参数中是否没有设置PackageManager.INSTALL_DONT_KILL_APP标志。
final boolean killApp =
(installArgs.mInstallFlags & PackageManager.INSTALL_DONT_KILL_APP) == 0;
// 判断是否为虚拟预加载(virtualPreload),这取决于安装参数中是否设置了PackageManager.INSTALL_VIRTUAL_PRELOAD标志。
final boolean virtualPreload =
((installArgs.mInstallFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
// 获取安装源的安装器包名(installerPackage)。
final String installerPackage = installArgs.mInstallSource.installerPackageName;
// 获取安装观察者(installObserver),用于在安装完成后通知调用者。
final IPackageInstallObserver2 installObserver = installArgs.mObserver;
// 获取数据加载器类型(dataLoaderType)。
final int dataLoaderType = installArgs.mDataLoaderType;
// 判断安装是否成功(succeeded),通过比较返回码是否为PackageManager.INSTALL_SUCCEEDED。
final boolean succeeded = res.mReturnCode == PackageManager.INSTALL_SUCCEEDED;
// 判断是否为更新(update),通过检查是否有被移除的信息且被移除的包名不为空。
final boolean update = res.mRemovedInfo != null && res.mRemovedInfo.mRemovedPackage != null;
// 获取安装的包名(packageName)。
final String packageName = res.mName;
// 如果安装成功,则获取包的状态信息(pkgSetting),否则为null。
final PackageStateInternal pkgSetting =
succeeded ? mPm.snapshotComputer().getPackageStateInternal(packageName) : null;
// 判断在更新前包是否已被移除(removedBeforeUpdate),这通过检查包设置是否为空或者包是系统包但路径不匹配来确定。
final boolean removedBeforeUpdate = (pkgSetting == null)
|| (pkgSetting.isSystem() && !pkgSetting.getPath().getPath().equals(
res.mPkg.getPath()));
// 如果安装成功但在处理安装后操作之前包已被移除,则记录错误日志,修改返回码和消息,表明包在安装完成前已被移除。然后,如果存在被移除的包的信息,则安全地移除旧资源,并通知安装观察者。
if (succeeded && removedBeforeUpdate) {
Slog.e(TAG, packageName + " was removed before handlePackagePostInstall "
+ "could be executed");
res.mReturnCode = INSTALL_FAILED_PACKAGE_CHANGED;
res.mReturnMsg = "Package was removed before install could complete.";
// Remove the update failed package's older resources safely now
// 如果需要移除旧资源,首先获取旧包的安装参数(args),然后在包管理器的安装锁同步块中调用doPostDeleteLI方法安全地移除资源。
InstallArgs args = res.mRemovedInfo != null ? res.mRemovedInfo.mArgs : null;
if (args != null) {
synchronized (mPm.mInstallLock) {
args.doPostDeleteLI(true);
}
}
// 使用notifyInstallObserver方法通知安装观察者安装结果。
mPm.notifyInstallObserver(res, installObserver);
return;
}
if (succeeded) {
// Clear the uid cache after we installed a new package.
// 在安装新包后,清空按用户ID读取超时的缓存
mPm.mPerUidReadTimeoutsCache = null;
// Send the removed broadcasts
if (res.mRemovedInfo != null) {
if (res.mRemovedInfo.mIsExternal) { // 如果被移除的包是外部存储上的(ASEC-hosted)
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.mRemovedInfo.mRemovedPackage
+ " is ASEC-hosted -> UNAVAILABLE");
}
// 记录其UID和包名,并发送资源变更广播(sendResourcesChangedBroadcast),标记该包为UNAVAILABLE。
final int[] uidArray = new int[]{res.mRemovedInfo.mUid};
final ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(res.mRemovedInfo.mRemovedPackage);
mBroadcastHelper.sendResourcesChangedBroadcast(
false, true, pkgList, uidArray, null);
}
// 发送包移除广播,killApp参数决定是否杀死相关应用,removedBySystem为false表示不是由系统移除。
res.mRemovedInfo.sendPackageRemovedBroadcasts(killApp, false /*removedBySystem*/);
}
// 获取安装这个包的安装器包名。如果直接指定了安装器包名,则使用该值;否则,如果被移除的包信息中包含了安装器包名,则使用该值;如果都没有,则为null。
final String installerPackageName =
res.mInstallerPackageName != null
? res.mInstallerPackageName
: res.mRemovedInfo != null
? res.mRemovedInfo.mInstallerPackageName
: null;
// 通知即时应用(Instant App)包已安装,res.mPkg.getPackageName()为安装的包名,res.mNewUsers为安装该包的新用户数组。
mPm.notifyInstantAppPackageInstalled(res.mPkg.getPackageName(), res.mNewUsers);
// Send installed broadcasts if the package is not a static shared lib.
if (res.mPkg.getStaticSharedLibName() == null) {// 如果安装的包没有静态共享库名(getStaticSharedLibName()返回null),则执行以下逻辑。
// 调用invalidateBaseApkHash方法,传入基础APK的路径,以清理与该APK相关的哈希信息。
mPm.mProcessLoggingHandler.invalidateBaseApkHash(res.mPkg.getBaseApkPath());
// Send added for users that see the package for the first time
// sendPackageAddedForNewUsers also deals with system apps
// 获取应用的UID、判断是否为系统应用,并调用sendPackageAddedForNewUsers方法,向首次安装该包的用户发送添加广播。
int appId = UserHandle.getAppId(res.mUid);
boolean isSystem = res.mPkg.isSystem();
mPm.sendPackageAddedForNewUsers(mPm.snapshotComputer(), packageName,
isSystem || virtualPreload, virtualPreload /*startReceiver*/, appId,
firstUserIds, firstInstantUserIds, dataLoaderType);
// Send added for users that don't see the package for the first time
Bundle extras = new Bundle();
extras.putInt(Intent.EXTRA_UID, res.mUid);
if (update) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
extras.putInt(PackageInstaller.EXTRA_DATA_LOADER_TYPE, dataLoaderType);
// Send to all running apps.
final SparseArray<int[]> newBroadcastAllowList;
synchronized (mPm.mLock) {
final Computer snapshot = mPm.snapshotComputer();
newBroadcastAllowList = mPm.mAppsFilter.getVisibilityAllowList(snapshot,
snapshot.getPackageStateInternal(packageName, Process.SYSTEM_UID),
updateUserIds, mPm.mSettings.getPackagesLocked());
}
// 调用sendPackageBroadcast方法,向非首次安装该包的用户发送添加广播。广播允许列表(newBroadcastAllowList),它决定了哪些应用可以接收到这个广播。
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, newBroadcastAllowList, null);
if (installerPackageName != null) {
// Send to the installer, even if it's not running.
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// if the required verifier is defined, but, is not the installer of record
// for the package, it gets notified
final boolean notifyVerifier = mPm.mRequiredVerifierPackage != null
&& !mPm.mRequiredVerifierPackage.equals(installerPackageName);
if (notifyVerifier) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, 0 /*flags*/,
mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// If package installer is defined, notify package installer about new
// app installed
if (mPm.mRequiredInstallerPackage != null) {
// 如果定义了必需的包安装器,则向包安装器发送添加广播。这里使用了不同的标志(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),允许后台接收者接收广播。
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
extras, Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND /*flags*/,
mPm.mRequiredInstallerPackage, null /*finishedReceiver*/,
firstUserIds, instantUserIds, null /* broadcastAllowList */, null);
}
// Send replaced for users that don't see the package for the first time
if (update) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED,
packageName, extras, 0 /*flags*/,
null /*targetPackage*/, null /*finishedReceiver*/,
updateUserIds, instantUserIds, res.mRemovedInfo.mBroadcastAllowList,
null);
if (installerPackageName != null) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
installerPackageName, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /*broadcastAllowList*/,
null);
}
if (notifyVerifier) {
mPm.sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
extras, 0 /*flags*/,
mPm.mRequiredVerifierPackage, null /*finishedReceiver*/,
updateUserIds, instantUserIds, null /*broadcastAllowList*/,
null);
}
mPm.sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
null /*package*/, null /*extras*/, 0 /*flags*/,
packageName /*targetPackage*/,
null /*finishedReceiver*/, updateUserIds, instantUserIds,
null /*broadcastAllowList*/,
mBroadcastHelper.getTemporaryAppAllowlistBroadcastOptions(
REASON_PACKAGE_REPLACED).toBundle());
} else if (launchedForRestore && !res.mPkg.isSystem()) {
// 这一行检查是否是因为恢复操作而启动的,并且被恢复的软件包不是系统软件包。
// First-install and we did a restore, so we're responsible for the
// first-launch broadcast.
if (DEBUG_BACKUP) {
Slog.i(TAG, "Post-restore of " + packageName
+ " sending FIRST_LAUNCH in " + Arrays.toString(firstUserIds));
}
// 调用sendFirstLaunchBroadcast方法来发送首次启动的广播,包含软件包名称、安装程序软件包名称、首次启动的用户ID列表和首次启动的即时用户ID列表。
mBroadcastHelper.sendFirstLaunchBroadcast(packageName, installerPackage,
firstUserIds, firstInstantUserIds);
}
// Send broadcast package appeared if external for all users
if (res.mPkg.isExternalStorage()) { // 检查当前正在处理的软件包(res.mPkg)是否安装在外部存储上
if (!update) { // 在外部存储的情况下,进一步检查是否不是更新操作(即首次安装或重新安装到外部存储)。如果是首次安装或重新安装,则执行以下代码块。
final StorageManager storageManager =
mInjector.getSystemService(StorageManager.class);
// 使用软件包的卷UUID(通过res.mPkg.getVolumeUuid()获取)来查找对应的VolumeInfo对象。
VolumeInfo volume =
storageManager.findVolumeByUuid(
StorageManager.convert(
res.mPkg.getVolumeUuid()).toString());
// 调用PackageManagerServiceUtils.getPackageExternalStorageType方法来确定软件包的外部存储类型。
int packageExternalStorageType =
PackageManagerServiceUtils.getPackageExternalStorageType(volume,
res.mPkg.isExternalStorage());
// If the package was installed externally, log it.
if (packageExternalStorageType != StorageEnums.UNKNOWN) {// 如果外部存储类型不是UNKNOWN,则记录一条日志,表示该软件包已安装在外部存储上。
FrameworkStatsLog.write(
FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
packageExternalStorageType, packageName);
}
}
if (DEBUG_INSTALL) {
Slog.i(TAG, "upgrading pkg " + res.mPkg + " is external");
}
final int[] uidArray = new int[]{res.mPkg.getUid()};
ArrayList<String> pkgList = new ArrayList<>(1);
pkgList.add(packageName);
// 调用mBroadcastHelper.sendResourcesChangedBroadcast方法发送一个资源更改的广播。这个广播通知系统和其他应用关于资源(如应用程序图标、标签等)可能已更改的信息。
mBroadcastHelper.sendResourcesChangedBroadcast(
true, true, pkgList, uidArray, null);
}
} else if (!ArrayUtils.isEmpty(res.mLibraryConsumers)) { // if static shared lib
// No need to kill consumers if it's installation of new version static shared lib.
// 如果当前处理的软件包不是安装在外部存储上,但有一个或多个静态共享库的消费者(即其他依赖该静态库的应用),则执行以下代码块。
final Computer snapshot = mPm.snapshotComputer();
final boolean dontKillApp = !update && res.mPkg.getStaticSharedLibName() != null;
for (int i = 0; i < res.mLibraryConsumers.size(); i++) { // 遍历所有依赖该静态共享库的应用(res.mLibraryConsumers)
AndroidPackage pkg = res.mLibraryConsumers.get(i);
// send broadcast that all consumers of the static shared library have changed
// 发送一个包更改的广播,通知依赖该静态共享库的应用库已更改。广播包含当前系统的快照、消费者应用的包名、是否不需要杀死应用、消费者应用的包名列表、消费者应用的UID等信息。
mPm.sendPackageChangedBroadcast(snapshot, pkg.getPackageName(), dontKillApp,
new ArrayList<>(Collections.singletonList(pkg.getPackageName())),
pkg.getUid(), null);
}
}
// Work that needs to happen on first install within each user
if (firstUserIds.length > 0) {
for (int userId : firstUserIds) {
// 对每个用户ID调用restorePermissionsAndUpdateRolesForNewUserInstall方法,为这些新用户安装应用时恢复权限并更新角色。
mPm.restorePermissionsAndUpdateRolesForNewUserInstall(packageName,
userId);
}
}
if (allNewUsers && !update) {
// 如果allNewUsers为真且update为假(意味着为所有新用户安装了新应用而不是更新),则调用notifyPackageAdded方法通知系统应用已添加。
mPm.notifyPackageAdded(packageName, res.mUid);
} else {
// 否则(即不是为所有新用户安装新应用,可能是更新或仅为部分用户安装),调用notifyPackageChanged方法通知系统应用已更改。
mPm.notifyPackageChanged(packageName, res.mUid);
}
final boolean deferInstallObserver = succeeded && update;
// 根据安装是否成功以及是否为更新操作,决定是否延迟通知安装观察者(installObserver)。
if (deferInstallObserver) {
// 如果是更新且成功安装,根据是否杀死应用来决定是延迟到杀死应用后通知还是延迟但不杀死应用后通知。如果不是更新或安装失败,则立即通知安装观察者。
if (killApp) {
mPm.scheduleDeferredPendingKillInstallObserver(res, installObserver);
} else {
mPm.scheduleDeferredNoKillInstallObserver(res, installObserver);
}
} else {
mPm.notifyInstallObserver(res, installObserver);
}
// Prune unused static shared libraries which have been cached a period of time
mPm.schedulePruneUnusedStaticSharedLibraries(true /* delay */);
}
}
}
安装完成后发送安装结果通知UI层。
综上如下:
InstallInstalling 执行:创建打开session,apk写入session,session提交。
PMS执行:apk拷贝/data/app;解析apk,诸如四大组件,签名,packageSetting等;扫描apk,packageSetting等;签名匹配验证;更新系统状态、PMS的内存数据。
Installer执行:准备用户目录/data/user;进行dexOpt。
APK用写入Session且包信息和APK安装操作 都提交到了PMS; PMS中先把APK拷贝到 /data/app,然后使用PackageParser2解析APK 获取 四大组件、搜集签名、PackageSetting等信息,并进行校验确保安装成功; 接着提交信息包更新系统状态及PMS的内存数据; 然后使用 Installer 准备用户目录/data/user、进行 dexOpt; 最后发送安装结果通知UI层。