Skip to content

Commit fa111c0

Browse files
committed
vending: suppress EMUI InstallDistActivity; implement splitDeferred
- Add USER_ACTION_NOT_REQUIRED to SessionParams in installPackagesInternal() for API 31+ (Android 12+) to prevent Huawei EMUI InstallDistActivity from intercepting every PackageInstaller session commit with a confirmation dialog. - Implement splitDeferred() in SplitInstallService to route deferred DFM install requests through splitInstallFlow() instead of being a no-op stub. Previously, apps like Facebook would fall back to startInstall() for each deferred module, triggering additional PackageInstaller sessions and additional InstallDistActivity dialogs on EMUI. Fixes: microg#3541
1 parent 352f2d7 commit fa111c0

2 files changed

Lines changed: 28 additions & 2 deletions

File tree

vending-app/src/main/kotlin/com/android/vending/installer/Install.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import android.content.pm.PackageInfo
1313
import android.content.pm.PackageInstaller
1414
import android.content.pm.PackageInstaller.SessionParams
1515
import android.content.pm.PackageManager
16+
import android.os.Build.VERSION.SDK_INT
1617
import android.util.Log
1718
import androidx.annotation.RequiresApi
1819
import androidx.core.app.PendingIntentCompat
@@ -118,6 +119,12 @@ private suspend fun Context.installPackagesInternal(
118119
val key = computeUniqueKey(packageName, componentNames)
119120
params.setAppLabel(key)
120121
params.setInstallLocation(PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY)
122+
// Suppress EMUI (Huawei) InstallDistActivity confirmation dialog for every session.
123+
// Without this flag, EMUI intercepts each PackageInstaller session and shows a
124+
// mandatory user-confirmation dialog — including for Dynamic Feature Module installs.
125+
if (SDK_INT >= 31) {
126+
params.setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED)
127+
}
121128
try {
122129
@SuppressLint("PrivateApi") val method = SessionParams::class.java.getDeclaredMethod(
123130
"setDontKillApp", Boolean::class.javaPrimitiveType

vending-app/src/main/kotlin/com/google/android/finsky/splitinstallservice/SplitInstallService.kt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,27 @@ class SplitInstallServiceImpl(private val installManager: SplitInstallManager, p
9191

9292
override fun splitDeferred(targetPackage: String, splits: List<Bundle>, bundle0: Bundle, callback: ISplitInstallServiceCallback) {
9393
val packageName = PackageUtils.getAndCheckCallingPackage(context, targetPackage)!!
94-
Log.w(TAG, "splitDeferred(${splits.joinToString()}) called for $packageName, but is not implemented")
95-
runCatching { callback.onDeferredInstall(Bundle()) }
94+
Log.d(TAG, "splitDeferred(${splits.joinToString()}) called for $packageName")
95+
// Deferred installs are background pre-fetch requests (e.g. Facebook DFMs like pytorch/papaya).
96+
// If we only ACK without actually installing, the app falls back to calling startInstall()
97+
// for the same modules later — which triggers another PackageInstaller session and, on EMUI,
98+
// another InstallDistActivity confirmation dialog per module.
99+
// Fix: route deferred requests through the same install flow as startInstall().
100+
if (VendingPreferences.isSplitInstallEnabled(context)) {
101+
lifecycleScope.launch {
102+
runCatching {
103+
installManager.splitInstallFlow(packageName, splits)
104+
Log.d(TAG, "splitDeferred install complete for $packageName")
105+
}.onFailure { e ->
106+
Log.w(TAG, "splitDeferred install failed for $packageName: ${e.message}")
107+
}
108+
// Always ACK so the app is not left waiting.
109+
runCatching { callback.onDeferredInstall(Bundle()) }
110+
}
111+
} else {
112+
Log.w(TAG, "splitDeferred rejected for $packageName, service is disabled")
113+
runCatching { callback.onDeferredInstall(Bundle()) }
114+
}
96115
}
97116

98117
override fun getSessionState2(targetPackage: String, sessionId: Int, callback: ISplitInstallServiceCallback) {

0 commit comments

Comments
 (0)