1 概述
installStart 本质一个Activity,属于系统应用程序PackageInstaller
android8.0后系统禁止跨进程传递文件url,所以文件的url都以content做scheme来进行传递
8.0后安装应用请求
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(xxxxx, "application/vnd.android.package-archive");
这里通过封装该intent启动InstallStartActivity
<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>
通过PackageInstaller应用程序的manifest.xml文件我们可以知道为什么会启动InstallStart
<intent-filter android:priority="1">
<action android:name="android.intent.action.VIEW" />
<data android:scheme="content" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
2 installStart都做了什么
首先作为Activity,在启动后一定遵循生命周期
2.1 onCreate
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获取packageManager
mPackageManager = getPackageManager();
//获取UserManager类对象
mUserManager = getSystemService(UserManager.class);
//获取调用方intent
Intent intent = getIntent();
// 获取调用者包名用于验证调用者信息
String callingPackage = getCallingPackage();
String callingAttributionTag = null;
//这里ACTION_CONFIRM_INSTALL主要是用户确认是否安装应用的操作
//一般场景为安装程序需要执行敏感操作,需用户确认才能继续安装
final boolean isSessionInstall =
PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intent.getAction());
// If the activity was started via a PackageInstaller session, we retrieve the calling
// package from that session
//这里获取安装sessionid,普通安装 sessionid -1
final int sessionId = (isSessionInstall
? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
: -1);
/**
* 这里主要针对这种异常case进行判断
* 调用者包信息,找不到,但是存在安装会话
*/
if (callingPackage == null && sessionId != -1) {
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId);
callingPackage = (sessionInfo != null) ? sessionInfo.getInstallerPackageName() : null;
callingAttributionTag =
(sessionInfo != null) ? sessionInfo.getInstallerAttributionTag() : null;
}
//根据包获取应用相关信息
final ApplicationInfo sourceInfo = getSourceInfo(callingPackage);
//获取元进程用户id
final int originatingUid = getOriginatingUid(sourceInfo);
//定义了一个flag,作用 检查安装资源是否值得信任
boolean isTrustedSource = false;
if (sourceInfo != null
&& (sourceInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0) {
/**
* case
* 条件 元进程不为空,并且元进程为系统应用进程
*
* 从intent获取EXTRA_NOT_UNKNOWN_SOURCE的值确认是否为值得信任的资源
*/
isTrustedSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
}
if (!isTrustedSource && originatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
/**
* case 如果不是可信任资源且元进程的uid不是未知的
*
* 过程
* 获取sdk版本
* 获取失败直接拒绝安装
*
* 获取成功
* 检查sdk版本大于 Build.VERSION_CODES.O并且该UID所对应应用未请求安装包权限
*
*拒绝安装
*/
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) {
//设置启动结果RESULT_CANCELED 通知启动activity
setResult(RESULT_CANCELED);
//关闭当前activity
finish();
return;
}
//这里构建新的intent封装 启动Activity的intent
Intent nextActivity = new Intent(intent);
//定义新intent的flag
//Intent.FLAG_ACTIVITY_FORWARD_RESULT 通知启动Activity可以接受结果
// Intent.FLAG_GRANT_READ_URI_PERMISSION 设置目标activity可以读取url
nextActivity.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
| Intent.FLAG_GRANT_READ_URI_PERMISSION);
// The the installation source as the nextActivity thinks this activity is the source, hence
// set the originating UID and sourceInfo explicitly
//元进程包信息
nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_PACKAGE, callingPackage);
nextActivity.putExtra(PackageInstallerActivity.EXTRA_CALLING_ATTRIBUTION_TAG,
callingAttributionTag);
//元进程 进程信息
nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
//元进程 用户id
nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
if (isSessionInstall) {
/**
* case1 这里判断当前是否为用户确认安装操作
*
* 结果 跳转到PackageInstallerActivity
*
*/
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
/**
* case2 普通安装,这里检查packageUri的Scheme是否为content
*
* 结果跳转到InstallStaging
*/
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
nextActivity.setClass(this, InstallStaging.class);
} else if (packageUri != null && packageUri.getScheme().equals(
PackageInstallerActivity.SCHEME_PACKAGE)) {
//case3 这里判断packageUri的scheme是否为package
nextActivity.setClass(this, PackageInstallerActivity.class);
} else {
//case4 如果上述几种情况都不满足,则通知源端,应用安装失败
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) {
//启动下一个Activity
startActivity(nextActivity);
}
//退出当前activity
finish();
}
总结:InstallStart类作为系统应用程序安装启动的第一个Activity,它的主要职责为
- 1 获取元进程的包信息,应用信息 用户id
- 2 确认当次操作是普通安装还是用户确认安装
- 3 确认安装资源是否可信任
- 4 最后根据安装方式和intent的data的scheme来确认跳转哪一个Acitivty,进行接下来的处理
普通安装这里首先看InstallStaging