summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt138
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt5
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt49
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java2
-rw-r--r--packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java9
5 files changed, 110 insertions, 93 deletions
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
index a23df64f3582..c260426d47f5 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt
@@ -95,9 +95,22 @@ class InstallRepository(private val context: Context) {
*/
var stagedSessionId = SessionInfo.INVALID_ID
private set
+
+ /**
+ * UID of the last caller of Pia. This can point to a 3P installer if it uses intents to install
+ * an APK, or receives a
+ * [STATUS_PENDING_USER_ACTION][PackageInstaller.STATUS_PENDING_USER_ACTION] status code.
+ * It may point to Pia, when it receives the STATUS_PENDING_USER_ACTION status code in case of
+ * an update-ownership change.
+ */
private var callingUid = Process.INVALID_UID
+
+ /**
+ * UID of the origin of the installation. This UID is used to fetch the app-label of the
+ * source of the install, and also check whether the source app has the AppOp to install other
+ * apps.
+ */
private var originatingUid = Process.INVALID_UID
- private var originatingUidFromSessionInfo = Process.INVALID_UID
private var callingPackage: String? = null
private var sessionStager: SessionStager? = null
private lateinit var intent: Intent
@@ -136,68 +149,60 @@ class InstallRepository(private val context: Context) {
stagedSessionId = intent.getIntExtra(EXTRA_STAGED_SESSION_ID, SessionInfo.INVALID_ID)
callingPackage = callerInfo.packageName
-
- // Uid of the source package, coming from ActivityManager
callingUid = callerInfo.uid
- if (callingUid == Process.INVALID_UID) {
- Log.e(LOG_TAG, "Could not determine the launching uid.")
+
+ val sourceInfo: ApplicationInfo? = getSourceInfo(callingPackage)
+ if (callingUid == Process.INVALID_UID && sourceInfo == null) {
+ // Caller's identity could not be determined. Abort the install
+ Log.e(LOG_TAG, "Cannot determine caller since UID is invalid and sourceInfo is null")
+ return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
}
- originatingUidFromSessionInfo = callingUid
+ originatingUid = callingUid
val sessionInfo: SessionInfo? =
if (sessionId != SessionInfo.INVALID_ID)
packageInstaller.getSessionInfo(sessionId)
else null
if (sessionInfo != null) {
- callingPackage = sessionInfo.installerPackageName
callingAttributionTag = sessionInfo.installerAttributionTag
if (sessionInfo.originatingUid != Process.INVALID_UID) {
- originatingUidFromSessionInfo = sessionInfo.originatingUid
+ originatingUid = sessionInfo.originatingUid
}
}
- val sourceInfo: ApplicationInfo? = getSourceInfo(callingPackage)
- // Uid of the source package, with a preference to uid from ApplicationInfo
- originatingUid = sourceInfo?.uid ?: callingUid
appOpRequestInfo = AppOpRequestInfo(
getPackageNameForUid(context, originatingUid, callingPackage),
- originatingUid, callingAttributionTag
+ originatingUid,
+ callingAttributionTag
)
- if(localLogv) {
- Log.i(LOG_TAG, "Intent: $intent\n" +
- "sessionId: $sessionId\n" +
- "staged sessionId: $stagedSessionId\n" +
- "calling package: $callingPackage\n" +
- "callingUid: $callingUid\n" +
- "originatingUid: $originatingUid")
- }
-
- if (callingUid == Process.INVALID_UID && sourceInfo == null) {
- // Caller's identity could not be determined. Abort the install
- Log.e(LOG_TAG, "Cannot determine caller since UID is invalid and sourceInfo is null")
- return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
+ if (localLogv) {
+ Log.i(
+ LOG_TAG, "Intent: $intent\n" +
+ "sessionId: $sessionId\n" +
+ "staged sessionId: $stagedSessionId\n" +
+ "calling package: $callingPackage\n" +
+ "callingUid: $callingUid\n" +
+ "originatingUid: $originatingUid\n" +
+ "sourceInfo: $sourceInfo"
+ )
}
if ((sessionId != SessionInfo.INVALID_ID
- && !isCallerSessionOwner(packageInstaller, originatingUid, sessionId))
+ && !isCallerSessionOwner(packageInstaller, callingUid, sessionId))
|| (stagedSessionId != SessionInfo.INVALID_ID
&& !isCallerSessionOwner(packageInstaller, Process.myUid(), stagedSessionId))
) {
- Log.e(LOG_TAG, "UID is not the owner of the session:\n" +
- "CallingUid: $originatingUid | SessionId: $sessionId\n" +
- "My UID: ${Process.myUid()} | StagedSessionId: $stagedSessionId")
+ Log.e(
+ LOG_TAG, "UID is not the owner of the session:\n" +
+ "CallingUid: $callingUid | SessionId: $sessionId\n" +
+ "My UID: ${Process.myUid()} | StagedSessionId: $stagedSessionId"
+ )
return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
}
- isTrustedSource = isInstallRequestFromTrustedSource(sourceInfo, this.intent, originatingUid)
- if (!isInstallPermissionGrantedOrRequested(
- context, callingUid, originatingUid, isTrustedSource
- )
- ) {
- Log.e(LOG_TAG, "UID $originatingUid needs to declare " +
- Manifest.permission.REQUEST_INSTALL_PACKAGES
- )
+ isTrustedSource = isInstallRequestFromTrustedSource(sourceInfo, this.intent, callingUid)
+ if (!isInstallPermissionGrantedOrRequested(context, callingUid, isTrustedSource)) {
return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
}
@@ -205,7 +210,7 @@ class InstallRepository(private val context: Context) {
if (restriction != null) {
val adminSupportDetailsIntent =
devicePolicyManager!!.createAdminSupportIntent(restriction)
- Log.e(LOG_TAG, "$restriction set in place. Cannot install." )
+ Log.e(LOG_TAG, "$restriction set in place. Cannot install.")
return InstallAborted(
ABORT_REASON_POLICY, message = restriction, resultIntent = adminSupportDetailsIntent
)
@@ -230,12 +235,12 @@ class InstallRepository(private val context: Context) {
private fun isInstallRequestFromTrustedSource(
sourceInfo: ApplicationInfo?,
intent: Intent,
- originatingUid: Int,
+ callingUid: Int,
): Boolean {
val isNotUnknownSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
return (sourceInfo != null && sourceInfo.isPrivilegedApp
&& (isNotUnknownSource
- || isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, originatingUid)))
+ || isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, callingUid)))
}
private fun getDevicePolicyRestrictions(): String? {
@@ -320,7 +325,7 @@ class InstallRepository(private val context: Context) {
Intent.EXTRA_INSTALL_RESULT, PackageManager.INSTALL_FAILED_INVALID_APK
),
activityResultCode = Activity.RESULT_FIRST_USER,
- errorDialogType = if (e is IOException) DLG_PACKAGE_ERROR else DLG_NONE
+ errorDialogType = if (e is IOException) DLG_PACKAGE_ERROR else DLG_NONE
)
return
}
@@ -401,8 +406,9 @@ class InstallRepository(private val context: Context) {
Log.e(LOG_TAG, "Cannot parse package $debugPathName. Assuming defaults.", e)
params.setSize(pfd.statSize)
} catch (e: IOException) {
- Log.e(LOG_TAG, "Cannot calculate installed size $debugPathName. " +
- "Try only apk size.", e
+ Log.e(
+ LOG_TAG, "Cannot calculate installed size $debugPathName. " +
+ "Try only apk size.", e
)
}
} else {
@@ -661,10 +667,9 @@ class InstallRepository(private val context: Context) {
if (isAppUpdating(pkgInfo)) {
val existingUpdateOwnerLabel = getExistingUpdateOwnerLabel(pkgInfo)
- val originatingPackageNameFromSessionInfo =
- getPackageNameForUid(context, originatingUidFromSessionInfo, callingPackage)
- val requestedUpdateOwnerLabel =
- getApplicationLabel(originatingPackageNameFromSessionInfo)
+ val originatingPackageName =
+ getPackageNameForUid(context, originatingUid, callingPackage)
+ val requestedUpdateOwnerLabel = getApplicationLabel(originatingPackageName)
if (!TextUtils.isEmpty(existingUpdateOwnerLabel)
&& userActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP
@@ -768,14 +773,14 @@ class InstallRepository(private val context: Context) {
}
private fun handleUnknownSources(requestInfo: AppOpRequestInfo): InstallStage {
- if (requestInfo.callingPackage == null) {
+ if (requestInfo.originatingPackage == null) {
Log.i(LOG_TAG, "No source found for package " + newPackageInfo?.packageName)
return InstallUserActionRequired(USER_ACTION_REASON_ANONYMOUS_SOURCE)
}
// Shouldn't use static constant directly, see b/65534401.
val appOpStr = AppOpsManager.permissionToOp(Manifest.permission.REQUEST_INSTALL_PACKAGES)
val appOpMode = appOpsManager!!.noteOpNoThrow(
- appOpStr!!, requestInfo.originatingUid, requestInfo.callingPackage,
+ appOpStr!!, requestInfo.originatingUid, requestInfo.originatingPackage,
requestInfo.attributionTag, "Started package installation activity"
)
if (localLogv) {
@@ -786,20 +791,20 @@ class InstallRepository(private val context: Context) {
AppOpsManager.MODE_DEFAULT, AppOpsManager.MODE_ERRORED -> {
if (appOpMode == AppOpsManager.MODE_DEFAULT) {
appOpsManager.setMode(
- appOpStr, requestInfo.originatingUid, requestInfo.callingPackage,
+ appOpStr, requestInfo.originatingUid, requestInfo.originatingPackage,
AppOpsManager.MODE_ERRORED
)
}
try {
val sourceInfo =
- packageManager.getApplicationInfo(requestInfo.callingPackage, 0)
+ packageManager.getApplicationInfo(requestInfo.originatingPackage, 0)
val sourceAppSnippet = getAppSnippet(context, sourceInfo)
InstallUserActionRequired(
USER_ACTION_REASON_UNKNOWN_SOURCE, appSnippet = sourceAppSnippet,
- dialogMessage = requestInfo.callingPackage
+ sourceApp = requestInfo.originatingPackage
)
} catch (e: PackageManager.NameNotFoundException) {
- Log.e(LOG_TAG, "Did not find appInfo for " + requestInfo.callingPackage)
+ Log.e(LOG_TAG, "Did not find appInfo for " + requestInfo.originatingPackage)
InstallAborted(ABORT_REASON_INTERNAL_ERROR)
}
}
@@ -841,8 +846,10 @@ class InstallRepository(private val context: Context) {
setStageBasedOnResult(PackageInstaller.STATUS_SUCCESS, -1, null)
} catch (e: PackageManager.NameNotFoundException) {
setStageBasedOnResult(
- PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
- null)
+ PackageInstaller.STATUS_FAILURE,
+ PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+ null
+ )
}
return
}
@@ -862,7 +869,8 @@ class InstallRepository(private val context: Context) {
}
} catch (e: OutOfIdsException) {
setStageBasedOnResult(
- PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null)
+ PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null
+ )
return
}
val broadcastIntent = Intent(BROADCAST_ACTION)
@@ -880,7 +888,8 @@ class InstallRepository(private val context: Context) {
Log.e(LOG_TAG, "Session $stagedSessionId could not be opened.", e)
packageInstaller.abandonSession(stagedSessionId)
setStageBasedOnResult(
- PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null)
+ PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null
+ )
}
}
@@ -890,9 +899,11 @@ class InstallRepository(private val context: Context) {
message: String?,
) {
if (localLogv) {
- Log.i(LOG_TAG, "Status code: $statusCode\n" +
- "legacy status: $legacyStatus\n" +
- "message: $message")
+ Log.i(
+ LOG_TAG, "Status code: $statusCode\n" +
+ "legacy status: $legacyStatus\n" +
+ "message: $message"
+ )
}
if (statusCode == PackageInstaller.STATUS_SUCCESS) {
val shouldReturnResult = intent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)
@@ -905,11 +916,12 @@ class InstallRepository(private val context: Context) {
_installResult.setValue(InstallSuccess(appSnippet, shouldReturnResult, resultIntent))
} else {
if (statusCode != PackageInstaller.STATUS_FAILURE_ABORTED) {
- _installResult.setValue(InstallFailed(appSnippet, statusCode, legacyStatus, message))
+ _installResult.setValue(
+ InstallFailed(appSnippet, statusCode, legacyStatus, message)
+ )
} else {
_installResult.setValue(InstallAborted(ABORT_REASON_INTERNAL_ERROR))
}
-
}
}
@@ -953,7 +965,7 @@ class InstallRepository(private val context: Context) {
data class CallerInfo(val packageName: String?, val uid: Int)
data class AppOpRequestInfo(
- val callingPackage: String?,
+ val originatingPackage: String?,
val originatingUid: Int,
val attributionTag: String?,
)
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt
index bbb9bca6db51..5dd4d2905f47 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt
@@ -43,7 +43,10 @@ data class InstallUserActionRequired(
val actionReason: Int,
private val appSnippet: PackageUtil.AppSnippet? = null,
val isAppUpdating: Boolean = false,
- val dialogMessage: String? = null,
+ /**
+ * This holds either a package name or the app label of the install source.
+ */
+ val sourceApp: String? = null,
) : InstallStage(STAGE_USER_ACTION_REQUIRED) {
val appIcon: Drawable?
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
index bae6f6876580..85728528a25c 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt
@@ -128,18 +128,19 @@ object PackageUtil {
/**
* @param context the [Context] object
- * @param callingUid the UID of the caller who's permission is being checked
- * @param originatingUid the UID from where install is being originated. This could be same as
- * callingUid or it will be the UID of the package performing a session based install
- * @param isTrustedSource whether install request is coming from a privileged app or an app that
- * has [Manifest.permission.INSTALL_PACKAGES] permission granted
- * @return `true` if the package is granted the said permission
+ * @param callingUid the UID of the caller of Pia
+ * @param isTrustedSource indicates whether install request is coming from a privileged app
+ * that has passed EXTRA_NOT_UNKNOWN_SOURCE as `true` in the installation intent, or that has
+ * the [INSTALL_PACKAGES][Manifest.permission.INSTALL_PACKAGES] permission granted.
+ *
+ * @return `true` if the package is either a system downloads provider, a document manager,
+ * a trusted source, or has declared the
+ * [REQUEST_INSTALL_PACKAGES][Manifest.permission.REQUEST_INSTALL_PACKAGES] in its manifest.
*/
@JvmStatic
fun isInstallPermissionGrantedOrRequested(
context: Context,
callingUid: Int,
- originatingUid: Int,
isTrustedSource: Boolean,
): Boolean {
val isDocumentsManager =
@@ -148,19 +149,18 @@ object PackageUtil {
getSystemDownloadsProviderInfo(context.packageManager, callingUid) != null
if (!isTrustedSource && !isSystemDownloadsProvider && !isDocumentsManager) {
- val targetSdkVersion = getMaxTargetSdkVersionForUid(context, originatingUid)
+ val targetSdkVersion = getMaxTargetSdkVersionForUid(context, callingUid)
if (targetSdkVersion < 0) {
- // Invalid originating uid supplied. Abort install.
- Log.w(LOG_TAG, "Cannot get target sdk version for uid $originatingUid")
+ // Invalid calling uid supplied. Abort install.
+ Log.e(LOG_TAG, "Cannot get target SDK version for uid $callingUid")
return false
} else if (targetSdkVersion >= Build.VERSION_CODES.O
&& !isUidRequestingPermission(
- context.packageManager, originatingUid,
- Manifest.permission.REQUEST_INSTALL_PACKAGES
+ context.packageManager, callingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES
)
) {
Log.e(
- LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission "
+ LOG_TAG, "Requesting uid " + callingUid + " needs to declare permission "
+ Manifest.permission.REQUEST_INSTALL_PACKAGES
)
return false
@@ -204,13 +204,13 @@ object PackageUtil {
* @return `true` if the caller is the session owner
*/
@JvmStatic
- fun isCallerSessionOwner(pi: PackageInstaller, originatingUid: Int, sessionId: Int): Boolean {
- if (originatingUid == Process.ROOT_UID) {
+ fun isCallerSessionOwner(pi: PackageInstaller, callingUid: Int, sessionId: Int): Boolean {
+ if (callingUid == Process.ROOT_UID) {
return true
}
val sessionInfo = pi.getSessionInfo(sessionId) ?: return false
val installerUid = sessionInfo.getInstallerUid()
- return originatingUid == installerUid
+ return callingUid == installerUid
}
/**
@@ -362,8 +362,8 @@ object PackageUtil {
* @return the packageName corresponding to a UID.
*/
@JvmStatic
- fun getPackageNameForUid(context: Context, sourceUid: Int, callingPackage: String?): String? {
- if (sourceUid == Process.INVALID_UID) {
+ fun getPackageNameForUid(context: Context, uid: Int, preferredPkgName: String?): String? {
+ if (uid == Process.INVALID_UID) {
return null
}
// If the sourceUid belongs to the system downloads provider, we explicitly return the
@@ -371,20 +371,21 @@ object PackageUtil {
// packages, resulting in uncertainty about which package will end up first in the list
// of packages associated with this UID
val pm = context.packageManager
- val systemDownloadProviderInfo = getSystemDownloadsProviderInfo(pm, sourceUid)
+ val systemDownloadProviderInfo = getSystemDownloadsProviderInfo(pm, uid)
if (systemDownloadProviderInfo != null) {
return systemDownloadProviderInfo.packageName
}
- val packagesForUid = pm.getPackagesForUid(sourceUid) ?: return null
+
+ val packagesForUid = pm.getPackagesForUid(uid) ?: return null
if (packagesForUid.size > 1) {
- if (callingPackage != null) {
+ Log.i(LOG_TAG, "Multiple packages found for source uid $uid")
+ if (preferredPkgName != null) {
for (packageName in packagesForUid) {
- if (packageName == callingPackage) {
+ if (packageName == preferredPkgName) {
return packageName
}
}
}
- Log.i(LOG_TAG, "Multiple packages found for source uid $sourceUid")
}
return packagesForUid[0]
}
@@ -439,7 +440,7 @@ object PackageUtil {
*/
data class AppSnippet(var label: CharSequence?, var icon: Drawable?) {
override fun toString(): String {
- return "AppSnippet[label = ${label}, hasIcon = ${icon != null}]"
+ return "AppSnippet[label = $label, hasIcon = ${icon != null}]"
}
}
}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java
index a95137d57a32..343a213780b3 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java
@@ -63,7 +63,7 @@ public class ExternalSourcesBlockedFragment extends DialogFragment {
.setMessage(R.string.untrusted_external_source_warning)
.setPositiveButton(R.string.external_sources_settings,
(dialog, which) -> mInstallActionListener.sendUnknownAppsIntent(
- mDialogData.getDialogMessage()))
+ mDialogData.getSourceApp()))
.setNegativeButton(R.string.cancel,
(dialog, which) -> mInstallActionListener.onNegativeResponse(
mDialogData.getStageCode()))
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java
index 99b1eec9cd9e..e186590fa5e2 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java
@@ -64,7 +64,7 @@ public class InstallConfirmationFragment extends DialogFragment {
int positiveBtnTextRes;
if (mDialogData.isAppUpdating()) {
- if (mDialogData.getDialogMessage() != null) {
+ if (mDialogData.getSourceApp() != null) {
positiveBtnTextRes = R.string.update_anyway;
} else {
positiveBtnTextRes = R.string.update;
@@ -88,9 +88,10 @@ public class InstallConfirmationFragment extends DialogFragment {
TextView viewToEnable;
if (mDialogData.isAppUpdating()) {
viewToEnable = dialogView.requireViewById(R.id.install_confirm_question_update);
- String dialogMessage = mDialogData.getDialogMessage();
- if (dialogMessage != null) {
- viewToEnable.setText(Html.fromHtml(dialogMessage, Html.FROM_HTML_MODE_LEGACY));
+ String sourcePackageName = mDialogData.getSourceApp();
+ if (sourcePackageName != null) {
+ // Show the update-ownership change message
+ viewToEnable.setText(Html.fromHtml(sourcePackageName, Html.FROM_HTML_MODE_LEGACY));
}
} else {
viewToEnable = dialogView.requireViewById(R.id.install_confirm_question);