Search code examples
androidandroid-package-managerspackageinstaller

Not getting status updates from PackageInstaller


I am trying to use PackageInstaller to install apk's, when I commit the session to package install to begin the install process my Broadcast Receiver gets the action but none of the extras for the status, package name, status message, session id are in the intent

Here is how I create the session

override suspend fun installUpdates(): Unit = withContext(Dispatchers.IO) {

    try {
        apkDirectory.listFiles()?.forEach { apk ->
            val params = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)

            val sessionId = context.packageManager.packageInstaller.createSession(params)
            val session = context.packageManager.packageInstaller.openSession(sessionId)
            apk.inputStream().use { apkStream ->
                session.openWrite(apk.nameWithoutExtension, 0, apk.length()).use { sessionStream ->
                    apkStream.copyTo(sessionStream)
                    session.fsync(sessionStream)
                }
            }

            val intent = Intent(context, InstallReceiver::class.java)
            intent.action = InstallReceiver.ACTION_INSTALL
            val pi = PendingIntent.getBroadcast(
                context,
                InstallReceiver::class.hashCode(),
                intent,
                PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
            )

            session.commit(pi.intentSender)
            session.close()
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

Here is my broadcast receiver

    <receiver android:name=".shared.updater.InstallReceiver"
        android:exported="false">
        <intent-filter>
            <action android:name="xx.xx.installer.InstallReceiver.ACTION_INSTALL" />
        </intent-filter>
    </receiver>

Code

override fun onReceive(context: Context, intent: Intent) {

    if(intent.action == ACTION_INSTALL){

        val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -2)
        val message: String? = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
        val pname = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)
        val sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, 0)
        val sessionInfo: SessionInfo? = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION)
        Log.d(TAG, "Status: $status, Message: $message, Package Name: $pname, Session ID: $sessionId")

        when (status) {
            PackageInstaller.STATUS_PENDING_USER_ACTION -> {
                // This test app isn't privileged, so the user has to confirm the install.
                Log.d(TAG, "Install needs user interaction")
            }

            PackageInstaller.STATUS_SUCCESS -> {
                Log.d(TAG, "Installed successfully")
            }
            PackageInstaller.STATUS_FAILURE,
            PackageInstaller.STATUS_FAILURE_ABORTED,
            PackageInstaller.STATUS_FAILURE_BLOCKED,
            PackageInstaller.STATUS_FAILURE_CONFLICT,
            PackageInstaller.STATUS_FAILURE_INCOMPATIBLE,
            PackageInstaller.STATUS_FAILURE_INVALID,
            PackageInstaller.STATUS_FAILURE_STORAGE,
            PackageInstaller.STATUS_FAILURE_TIMEOUT -> {
                val message: String? = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
                Log.d(TAG, "Install failure, Status: $status, Message: $message")
            }

            else -> {
                //Unknown status
                Log.d(TAG, "Unknown install status $status")
            }
        }
    }else{
        Log.d(TAG, "Unknown action ${intent.action}")
    }

}

}

All the extras come back as the default value or null but the apk's do install correctly.

I have the install packages permission too (app was copied to the system/priv-app folder on a rooted device)

<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>

I am not sure what I am doing wrong, all the examples I have looked at for using package manager appear to be doing what I am doing


Solution

  • The issue was the Pending Intent flag PendingIntent.FLAG_IMMUTABLE it needs to be PendingIntent.FLAG_MUTABLE for the extras to be present