app 安装方式
APK的安装方式主要有以下几种:
- 通过adb命令安装:adb 命令包括adb push/install
- 用户下载的Apk,通过系统安装器PackageInstaller安装该Apk。PackageInstaller是系统内置的应用程序,用于安装和卸载应用程序。
- 系统开机时安装系统应用。 persistent属性
- 应用商店下载后自动安装。
PackageInstaller的位置
frameworks\base\packages\PackageInstaller\路径下
其中InstallStart为PackageInstaller入口
-
<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>
安装apk的代码主要是调用InstallStart
-
Intent intent = new Intent(Intent.ACTION_VIEW);
-
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
intent.setDataAndType(Uri.parse("file://" path),"application/vnd.android.package-archive");
-
context.startActivity(intent);
PackageInstaller是系统内置的应用程序,用于安装和卸载应用。当我们调用PackageInstaller来安装应用时会跳转到InstallStart,并调用它的onCreate方法:
-
String callingPackage = getCallingPackage();
-
-
final boolean isSessionInstall =
-
PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
-
-
-
-
if (isSessionInstall) {
-
nextActivity.setClass(this, PackageInstallerActivity.class);
-
} else {
-
Uri packageUri = intent.getData();
-
-
if (packageUri != null && packageUri.getScheme().equals(
-
ContentResolver.SCHEME_CONTENT)) {
-
// [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
-
//调用这里,启动InstallStaging
-
nextActivity.setClass(this, InstallStaging.class);
-
} else if (packageUri != null && packageUri.getScheme().equals(
-
PackageInstallerActivity.SCHEME_PACKAGE)) {
-
-
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();
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallStaging.java InstallStaging的onResume方法
-
@Override
-
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 {
-
如果File类型的mStagedFile 为null,则创建mStagedFile ,mStagedFile用于存储临时数据
-
mStagedFile = TemporaryFileManager.getStagedFile(this);
-
} catch (IOException e) {
-
showError();
-
return;
-
}
-
}
-
启动StagingAsyncTask
-
mStagingTask = new StagingAsyncTask();
-
mStagingTask.execute(getIntent().getData());
-
}
-
}
StagingAsyncTask是InstallStaging的内部类,
-
private final class StagingAsyncTask extends AsyncTask<Uri, Void, Boolean> {
-
@Override
-
protected Boolean doInBackground(Uri... params) {
-
if (params == null || params.length <= 0) {
-
return false;
-
}
-
Uri packageUri = params[0];
-
try (InputStream in = getContentResolver().openInputStream(packageUri)) {
-
// Despite the comments in ContentResolver#openInputStream the returned stream can
-
// be null.
-
if (in == null) {
-
return false;
-
}
-
-
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;
-
}
-
-
@Override
-
protected void onPostExecute(Boolean success) {
-
if (success) {
-
// Now start the installation again from a file
-
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);
-
}
-
-
installIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-
startActivity(installIntent);
-
-
InstallStaging.this.finish();
-
} else {
-
showError();
-
}
-
}
-
}
doInBackground方法中将packageUri(content协议的Uri)的内容写入到mStagedFile中,如果写入成功,onPostExecute方法中会跳转到DeleteStagedFileOnResult中,
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\DeleteStagedFileOnResult.java
DeleteStagedFileOnResult启动PackageInstallerActivity实现apk的安装
-
public class DeleteStagedFileOnResult extends Activity {
-
-
protected void onCreate( Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
-
if (savedInstanceState == null) {
-
Intent installIntent = new Intent(getIntent());
-
installIntent.setClass(this, PackageInstallerActivity.class);
-
-
installIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-
startActivityForResult(installIntent, 0);
-
}
-
}
-
-
-
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
-
File sourceFile = new File(getIntent().getData().getPath());
-
sourceFile.delete();
-
-
setResult(resultCode, data);
-
finish();
-
}
-
}
DeleteStagedFileOnResult将mStagedFile传入PackageInstallerActivity,InstallStaging主要将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity,这样就可以像此前版本(Android7.0之前)一样启动安装流程了。
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\PackageInstallerActivity.java
-
@Override
-
protected void onCreate(Bundle icicle) {
-
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
-
-
super.onCreate(null);
-
-
if (icicle != null) {
-
mAllowUnknownSources = icicle.getBoolean(ALLOW_UNKNOWN_SOURCES_KEY);
-
}
-
//初始话安装所需要的各种对象
-
mPm = getPackageManager();
-
mIpm = AppGlobals.getPackageManager();
-
mAppOpsManager = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
-
mInstaller = mPm.getPackageInstaller();
-
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
-
-
final Intent intent = getIntent();
-
-
mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
-
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;
-
-
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;
-
}
-
-
mSessionId = sessionId;
-
packageUri = Uri.fromFile(new File(info.resolvedBaseCodePath));
-
mOriginatingURI = null;
-
mReferrerURI = null;
-
} else {
-
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) {
-
Log.w(TAG, "Unspecified source");
-
setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI);
-
finish();
-
return;
-
}
-
-
if (DeviceUtils.isWear(this)) {
-
showDialogInner(DLG_NOT_SUPPORTED_ON_WEAR);
-
return;
-
}
-
-
boolean wasSetUp = processPackageUri(packageUri);
-
if (!wasSetUp) {
-
return;
-
}
-
-
// load dummy layout with OK button disabled until we override this layout in
-
// startInstallConfirm
-
bindUi();
-
//判断是否是未知来源的应用,如果开启允许安装未知来源选项则直接初始化安装
-
checkIfAllowedAndInitiateInstall();
-
}
类名 | 描述 |
---|---|
PackageManager | 用于向应用程序进程提供一些功能,最终的功能是由PMS来实现的 |
IPackageManager | 一个AIDL的接口,用于和PMS进行进程间通信 |
AppOpsManager | 用于权限动态检测,在Android4.3中被引入 |
PackageInstaller | 提供安装、升级和删除应用程序功能 |
UserManager | 用于多用户管理 |
bindUi();
-
/**
-
* Check if it is allowed to install the package and initiate install if allowed. If not allowed
-
* show the appropriate dialog.
-
*/
-
private void checkIfAllowedAndInitiateInstall() {
-
// Check for install apps user restriction first.
-
final int installAppsRestrictionSource = mUserManager.getUserRestrictionSource(
-
UserManager.DISALLOW_INSTALL_APPS, Process.myUserHandle());
-
if ((installAppsRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
-
showDialogInner(DLG_INSTALL_APPS_RESTRICTED_FOR_USER);
-
return;
-
} else if (installAppsRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
-
startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
-
finish();
-
return;
-
}
-
//判断如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源
-
if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
-
initiateInstall();
-
} else {
-
// 如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面
-
// Check for unknown sources restrictions.
-
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) {
-
showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
-
} else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
-
startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
-
} else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
-
startAdminSupportDetailsActivity(
-
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
-
} else {
-
handleUnknownSources();
-
}
-
}
-
}
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 {
-
完成app的安装
-
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();
-
}
-
}
-
private void initiateInstall() {
-
String pkgName = mPkgInfo.packageName;
-
// Check if there is already a package on the device with this name
-
// but it has been renamed to something else.
-
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".
-
mAppInfo = mPm.getApplicationInfo(pkgName,
-
PackageManager.MATCH_UNINSTALLED_PACKAGES);
-
if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) {
-
mAppInfo = null;
-
}
-
} catch (NameNotFoundException e) {
-
mAppInfo = null;
-
}
-
-
startInstallConfirm();
-
}
-
private void startInstallConfirm() {
-
View viewToEnable;
-
-
if (mAppInfo != null) {
-
viewToEnable = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0
-
? requireViewById(R.id.install_confirm_question_update_system)
-
: requireViewById(R.id.install_confirm_question_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);
-
}
具体加载的布局文件再frameworks\base\packages\PackageInstaller\res\layout\下
现在来总结下PackageInstaller初始化的过程:
- 根据Uri的Scheme协议不同,跳转到不同的界面,content协议跳转到InstallStart,其他的跳转到PackageInstallerActivity。
- InstallStart将content协议的Uri转换为File协议,然后跳转到PackageInstallerActivity。
- PackageInstallerActivity会分别对package协议和file协议的Uri进行处理,如果是file协议会解析APK文件得到包信息PackageInfo。
- PackageInstallerActivity中会对未知来源进行处理,如果允许安装未知来源或者根据Intent判断得出该APK不是未知来源,就会初始化安装确认界面,如果管理员限制来自未知源的安装, 就弹出提示Dialog或者跳转到设置界面。
startInstall();方法调用 InstallInstalling 来安装apk
startInstall方法用于跳转到InstallInstalling这个Activity,并关闭掉当前的PackageInstallerActivity。InstallInstalling主要用于向包管理器发送包的信息并处理包管理的回调。
-
private void startInstall() {
-
// Start subactivity to actually install the application
-
Intent newIntent = new Intent();
-
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
-
mPkgInfo.applicationInfo);
-
newIntent.setData(mPackageURI);
-
newIntent.setClass(this, InstallInstalling.class);
-
String installerPackageName = getIntent().getStringExtra(
-
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
-
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);
-
}
-
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
-
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
-
}
-
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
-
if(localLOGV) Log.i(TAG, "downloaded app uri=" mPackageURI);
-
startActivity(newIntent);
-
finish();
-
}
frameworks\base\packages\PackageInstaller\src\com\android\packageinstaller\InstallInstalling.java
-
@Override
-
protected void onCreate(@Nullable Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
-
ApplicationInfo appInfo = getIntent()
-
.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
-
mPackageURI = getIntent().getData();
-
-
if ("package".equals(mPackageURI.getScheme())) {
-
try {
-
getPackageManager().installExistingPackage(appInfo.packageName);
-
launchSuccess();
-
} catch (PackageManager.NameNotFoundException e) {
-
launchFailure(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null);
-
}
-
} else {
-
//根据mPackageURI创建一个对应的File
-
final File sourceFile = new File(mPackageURI.getPath());
-
PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, appInfo, sourceFile);
-
-
mAlert.setIcon(as.icon);
-
mAlert.setTitle(as.label);
-
mAlert.setView(R.layout.install_content_view);
-
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);
-
//如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId
-
if (savedInstanceState != null) {
-
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注册一个观察者
-
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);
-
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);
-
}
-
}
-
-
mCancelButton = mAlert.getButton(DialogInterface.BUTTON_NEGATIVE);
-
-
mSessionCallback = new InstallSessionCallback();
-
}
-
}
onCreate方法中会分别对package和content协议的Uri进行处理,我们来看content协议的Uri处理部分。注释1处如果savedInstanceState不为null,获取此前保存的mSessionId和mInstallId,其中mSessionId是安装包的会话id,mInstallId是等待的安装事件id。注释2处根据mInstallId向InstallEventReceiver注册一个观察者,launchFinishBasedOnResult会接收到安装事件的回调,无论安装成功或者失败都会关闭当前的Activity(InstallInstalling)。如果savedInstanceState为null,代码的逻辑也是类似的,注释3处创建SessionParams,它用来代表安装会话的参数,注释4、5处根据mPackageUri对包(APK)进行轻量级的解析,并将解析的参数赋值给SessionParams。注释6处和注释2处类似向InstallEventReceiver注册一个观察者返回一个新的mInstallId,其中InstallEventReceiver继承自BroadcastReceiver,用于接收安装事件并回调给EventResultPersister。 注释7处PackageInstaller的createSession方法内部会通过IPackageInstaller与PackageInstallerService进行进程间通信,最终调用的是PackageInstallerService的createSession方法来创建并返回mSessionId。
-
@Override
-
protected void onResume() {
-
super.onResume();
-
-
// This is the first onResume in a single life of the activity
-
if (mInstallingTask == null) {
-
PackageInstaller installer = getPackageManager().getPackageInstaller();
-
PackageInstaller.SessionInfo sessionInfo = installer.getSessionInfo(mSessionId);
-
-
if (sessionInfo != null && !sessionInfo.isActive()) {
-
mInstallingTask = new InstallingAsyncTask();
-
mInstallingTask.execute();
-
} else {
-
// we will receive a broadcast when the install is finished
-
mCancelButton.setEnabled(false);
-
setFinishOnTouchOutside(false);
-
}
-
}
-
}
根据mSessionId得到SessionInfo,SessionInfo代表安装会话的详细信息。如果sessionInfo不为Null并且不是活动的,就创建并执行InstallingAsyncTask。InstallingAsyncTask的doInBackground方法中会根据包(APK)的Uri,将APK的信息通过IO流的形式写入到PackageInstaller.Session中
onResune 启动InstallingAsyncTask
-
private final class InstallingAsyncTask extends AsyncTask<Void, Void,
-
PackageInstaller.Session> {
-
volatile boolean isDone;
-
-
@Override
-
protected PackageInstaller.Session doInBackground(Void... params) {
-
PackageInstaller.Session session;
-
try {
-
session = getPackageManager().getPackageInstaller().openSession(mSessionId);
-
} catch (IOException e) {
-
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();
-
}
-
}
-
}
-
-
@Override
-
protected void onPostExecute(PackageInstaller.Session session) {
-
if (session != null) {
-
Intent broadcastIntent = new Intent(BROADCAST_ACTION);
-
broadcastIntent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-
broadcastIntent.setPackage(getPackageName());
-
broadcastIntent.putExtra(EventResultPersister.EXTRA_ID, mInstallId);
-
-
PendingIntent pendingIntent = PendingIntent.getBroadcast(
-
InstallInstalling.this,
-
mInstallId,
-
broadcastIntent,
-
PendingIntent.FLAG_UPDATE_CURRENT);
-
-
session.commit(pendingIntent.getIntentSender());
-
mCancelButton.setEnabled(false);
-
setFinishOnTouchOutside(false);
-
} else {
-
getPackageManager().getPackageInstaller().abandonSession(mSessionId);
-
-
if (!isCancelled()) {
-
launchFailure(PackageManager.INSTALL_FAILED_INVALID_APK, null);
-
}
-
}
-
}
-
}
创建了一个PendingIntent,并将该PendingIntent的IntentSender通过PackageInstaller.Session的commit方法发送出去
frameworks\base\core\java\android\content\pm\PackageInstaller.java
-
protected final IPackageInstallerSession mSession;
-
-
public void commit() { IntentSender statusReceiver
-
try {
-
mSession.commit(statusReceiver, false);
-
} catch (RemoteException e) {
-
throw e.rethrowFromSystemServer();
-
}
-
}
mSession的类型为IPackageInstallerSession,这说明要通过IPackageInstallerSession来进行进程间的通信,最终会调用PackageInstallerSession的commit方法
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();
-
}
-
private void dispatchStreamValidateAndCommit() {
-
mHandler.obtainMessage(MSG_STREAM_VALIDATE_AND_COMMIT).sendToTarget();
-
}
-
-
private void handleStreamValidateAndCommit() {
-
PackageManagerException unrecoverableFailure = null;
-
// This will track whether the session and any children were validated and are ready to
-
// progress to the next phase of install
-
boolean allSessionsReady = false;
-
try {
-
allSessionsReady = streamValidateAndCommit();
-
} catch (PackageManagerException e) {
-
unrecoverableFailure = e;
-
}
-
-
if (isMultiPackage()) {
-
int childCount = mChildSessionIds.size();
-
-
// This will contain all child sessions that do not encounter an unrecoverable failure
-
ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);
-
-
for (int i = childCount - 1; i >= 0; --i) {
-
final int childSessionId = mChildSessionIds.keyAt(i);
-
// commit all children, regardless if any of them fail; we'll throw/return
-
// as appropriate once all children have been processed
-
try {
-
PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
-
allSessionsReady &= session.streamValidateAndCommit();
-
nonFailingSessions.add(session);
-
} catch (PackageManagerException e) {
-
allSessionsReady = false;
-
if (unrecoverableFailure == null) {
-
unrecoverableFailure = e;
-
}
-
}
-
}
-
// If we encountered any unrecoverable failures, destroy all other sessions including
-
// the parent
-
if (unrecoverableFailure != null) {
-
// {@link #streamValidateAndCommit()} calls
-
// {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't
-
// expect it to ever do so for parent sessions. Call that on this parent to clean
-
// it up and notify listeners of the error.
-
onSessionVerificationFailure(unrecoverableFailure);
-
// fail other child sessions that did not already fail
-
for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
-
PackageInstallerSession session = nonFailingSessions.get(i);
-
session.onSessionVerificationFailure(unrecoverableFailure);
-
}
-
}
-
}
-
-
if (!allSessionsReady) {
-
return;
-
}
-
-
mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
-
}
-
private void handleInstall() {
-
if (isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()) {
-
DevicePolicyEventLogger
-
.createEvent(DevicePolicyEnums.INSTALL_PACKAGE)
-
.setAdmin(mInstallSource.installerPackageName)
-
.write();
-
}
-
if (params.isStaged) {
-
mStagingManager.commitSession(this);
-
destroyInternal();
-
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
-
return;
-
}
-
-
if (isApexInstallation()) {
-
destroyInternal();
-
dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
-
"APEX packages can only be installed using staged sessions.", null);
-
return;
-
}
-
-
// For a multiPackage session, read the child sessions
-
// outside of the lock, because reading the child
-
// sessions with the lock held could lead to deadlock
-
// (b/123391593).
-
List<PackageInstallerSession> childSessions = getChildSessionsNotLocked();
-
-
try {
-
synchronized (mLock) {
-
installNonStagedLocked(childSessions);
-
}
-
} catch (PackageManagerException e) {
-
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
-
Slog.e(TAG, "Commit of session " sessionId " failed: " completeMsg);
-
destroyInternal();
-
dispatchSessionFinished(e.error, completeMsg, null);
-
}
-
}
-
@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);
-
}
-
}
调用 mPm的installStage方法
private final PackageManagerService mPm;
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);
-
}
创建InstallParams,它对应于包的安装数据
-
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;
-
}
params.startCopy();
params是HandlerParams类
-
final void startCopy() {
-
if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " mUser ": " this);
-
handleStartCopy();
-
handleReturnCode();
-
}
-
abstract void handleStartCopy();
-
abstract void handleReturnCode();
具体实现在 InstallParams里 是PackageManagerService的内部类
class InstallParams extends HandlerParams {
-
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");
-
}
-
}
-
//确定APK的安装位置。 onInt:内部存储即Data分区,ephemeral:安装到临时存储(Instant Apps安装)
-
final boolean onInt = (installFlags & PackageManager.INSTALL_INTERNAL) != 0;
-
final boolean ephemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
-
PackageInfoLite pkgLite = null;
-
-
//获取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;
-
}
-
}
-
-
-
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.
-
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;
-
}
-
}
-
}
-
}
-
//根据InstallParams创建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;
-
}
InstallArgs 是一个抽象类,定义了APK的安装逻辑,比如复制和重命名APK等,
其中FileInstallArgs用于处理安装到非ASEC的存储空间的APK,也就是内部存储空间(Data分区)
MoveInstallArgs用于处理已安装APK的移动的逻辑。
-
static abstract class InstallArgs {
-
-
-
class FileInstallArgs extends InstallArgs {
-
class MoveInstallArgs extends InstallArgs {
-
@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) {
-
mRet = mArgs.copyApk();
-
}
-
processPendingInstall(mArgs, mRet);
-
}
-
}
mArgs.copyApk();
private InstallArgs mArgs;
-
int copyApk() {
-
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "copyApk");
-
try {
-
return doCopyApk();
-
} finally {
-
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-
}
-
}
-
-
private int doCopyApk() {
-
if (origin.staged) {
-
if (DEBUG_INSTALL) Slog.d(TAG, origin.file " already staged; skipping copy");
-
codeFile = origin.file;
-
resourceFile = origin.file;
-
return PackageManager.INSTALL_SUCCEEDED;
-
}
-
-
try {
-
final boolean isEphemeral = (installFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
-
//创建临时文件存储目录
-
final File tempDir =
-
mInstallerService.allocateStageDirLegacy(volumeUuid, isEphemeral);
-
codeFile = tempDir;
-
resourceFile = tempDir;
-
} catch (IOException e) {
-
Slog.w(TAG, "Failed to create copy file: " e);
-
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-
}
-
将APK复制到临时存储目录
-
int ret = PackageManagerServiceUtils.copyPackage(
-
origin.file.getAbsolutePath(), codeFile);
-
if (ret != PackageManager.INSTALL_SUCCEEDED) {
-
Slog.e(TAG, "Failed to copy package");
-
return ret;
-
}
-
-
final boolean isIncremental = isIncrementalPath(codeFile.getAbsolutePath());
-
final File libraryRoot = new File(codeFile, LIB_DIR_NAME);
-
NativeLibraryHelper.Handle handle = null;
-
try {
-
handle = NativeLibraryHelper.Handle.create(codeFile);
-
ret = NativeLibraryHelper.copyNativeBinariesWithOverride(handle, libraryRoot,
-
abiOverride, isIncremental);
-
} catch (IOException e) {
-
Slog.e(TAG, "Copying native libraries failed", e);
-
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-
} finally {
-
IoUtils.closeQuietly(handle);
-
}
-
-
return ret;
-
}
processPendingInstall(mArgs, mRet);
-
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));
-
}
-
});
-
}
-
private PackageInstalledInfo createPackageInstalledInfo(
-
int currentStatus) {
-
PackageInstalledInfo res = new PackageInstalledInfo();
-
res.setReturnCode(currentStatus);
-
res.uid = -1;
-
res.pkg = null;
-
res.removedInfo = null;
-
return res;
-
}
-
"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);
-
}
-
}
-
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);
-
}
-
}
executePostCommitSteps执行安装
installPackageLI方法的代码有将近500行,这里截取主要的部分,主要做了几件事:
- 创建PackageParser解析APK。
- 检查APK是否存在,如果存在就获取此前没被改名前的包名并在注释1处赋值给PackageParser.Package类型的pkg,在注释3处将标志位replace置为true表示是替换安装。
- 注释3处,如果Settings中保存有要安装的APK的信息,说明此前安装过该APK,则需要校验APK的签名信息,确保安全的进行替换。
- 在注释4处将临时文件重新命名,比如前面提到的/data/app/vmdl18300388.tmp/base.apk,重命名为/data/app/包名-1/base.apk。这个新命名的包名会带上一个数字后缀1,每次升级一个已有的App,这个数字会不断的累加。
- 系统APP的更新安装会有两个限制,一个是系统APP不能在SD卡上替换安装,另一个是系统APP不能被Instant App替换。
- 注释5处根据replace来做区分,如果是替换安装就会调用replacePackageLIF方法,其方法内部还会对系统APP和非系统APP进行区分处理,如果是新安装APK会调用installNewPackageLIF方法。
installNewPackageLIF主要做了以下3件事:
- 扫描APK,将APK的信息存储在PackageParser.Package类型的newPackage中,一个Package的信息包含了1个base APK以及0个或者多个split APK。
- 更新该APK对应的Settings信息,Settings用于保存所有包的动态设置。
- 如果安装成功就为新安装的应用程序准备数据,安装失败就删除APK。
安装APK的过程就讲到这里,就不再往下分析下去,有兴趣的同学可以接着深挖。
**4.总结 **
本文主要讲解了PMS是如何处理APK安装的,主要有几个步骤:
- PackageInstaller安装APK时会将APK的信息交由PMS处理,PMS通过向PackageHandler发送消息来驱动APK的复制和安装工作。
- PMS发送INIT_COPY和MCS_BOUND类型的消息,控制PackageHandler来绑定DefaultContainerService,完成复制APK等工作。
- 复制APK完成后,会开始进行安装APK的流程,包括安装前的检查、安装APK和安装后的收尾工作。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgejcef
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01