Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b09b6ef0 authored by Sumedh Sen's avatar Sumedh Sen
Browse files

Migrate AsyncTask to Coroutines

AsyncTask is deprecated in Java. Use Kotlin's coroutines instead

Bug: 182205982
Test: Manual. Sideload an APK and observe the staging dialog
Change-Id: I7e9394417be0ca3f8b5e12b1e31b8b1941290114
parent af35e04d
Loading
Loading
Loading
Loading
+14 −18
Original line number Diff line number Diff line
@@ -60,6 +60,10 @@ import com.android.packageinstaller.v2.model.PackageUtil.isInstallPermissionGran
import com.android.packageinstaller.v2.model.PackageUtil.isPermissionGranted
import java.io.File
import java.io.IOException
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch

class InstallRepository(private val context: Context) {

@@ -242,6 +246,7 @@ class InstallRepository(private val context: Context) {
        }
    }

    @OptIn(DelicateCoroutinesApi::class)
    fun stageForInstall() {
        val uri = intent.data
        if (stagedSessionId != SessionInfo.INVALID_ID
@@ -290,13 +295,14 @@ class InstallRepository(private val context: Context) {
                    return
                }
            }
            val listener: SessionStageListener = object : SessionStageListener {
                override fun onStagingSuccess(info: SessionInfo?) {
                    //TODO: Verify if the returned sessionInfo should be used anywhere
                    _stagingResult.value = InstallReady()
                }

                override fun onStagingFailure() {
            sessionStager = SessionStager(context, uri, stagedSessionId)
            GlobalScope.launch(Dispatchers.Main) {
                val wasFileStaged = sessionStager!!.execute()

                if (wasFileStaged) {
                    _stagingResult.value = InstallReady()
                } else {
                    cleanupStagingSession()
                    _stagingResult.value = InstallAborted(
                        ABORT_REASON_INTERNAL_ERROR,
@@ -307,9 +313,6 @@ class InstallRepository(private val context: Context) {
                    )
                }
            }
            sessionStager?.cancel(true)
            sessionStager = SessionStager(context, uri, stagedSessionId, listener)
            sessionStager?.execute()
        }
    }

@@ -845,10 +848,8 @@ class InstallRepository(private val context: Context) {
        return generateConfirmationSnippet()
    }

    val stagingProgress: MutableLiveData<Int>
        get() = if (sessionStager != null) {
            sessionStager?.progress ?: MutableLiveData(0)
        } else MutableLiveData(0)
    val stagingProgress: LiveData<Int>
        get() = sessionStager?.progress ?: MutableLiveData(0)

    companion object {
        const val EXTRA_STAGED_SESSION_ID = "com.android.packageinstaller.extra.STAGED_SESSION_ID"
@@ -857,11 +858,6 @@ class InstallRepository(private val context: Context) {
        private val LOG_TAG = InstallRepository::class.java.simpleName
    }

    interface SessionStageListener {
        fun onStagingSuccess(info: SessionInfo?)
        fun onStagingFailure()
    }

    data class CallerInfo(val packageName: String?, val uid: Int)
    data class AppOpRequestInfo(
        val callingPackage: String?,
+28 −35
Original line number Diff line number Diff line
@@ -20,55 +20,53 @@ import android.content.Context
import android.content.pm.PackageInstaller
import android.content.res.AssetFileDescriptor
import android.net.Uri
import android.os.AsyncTask
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.android.packageinstaller.v2.model.InstallRepository.SessionStageListener
import java.io.IOException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

class SessionStager internal constructor(
    private val context: Context,
    private val uri: Uri,
    private val stagedSessionId: Int,
    private val listener: SessionStageListener,
) : AsyncTask<Void, Int, PackageInstaller.SessionInfo?>() {
    private val stagedSessionId: Int
) {

    companion object {
        private val LOG_TAG = SessionStager::class.java.simpleName
    }

    val progress = MutableLiveData(0)
    private val _progress = MutableLiveData(0)
    val progress: LiveData<Int>
        get() = _progress

    override fun doInBackground(vararg params: Void): PackageInstaller.SessionInfo? {
        val pi = context.packageManager.packageInstaller
    suspend fun execute(): Boolean = withContext(Dispatchers.IO) {
        val pi: PackageInstaller = context.packageManager.packageInstaller
        var sessionInfo: PackageInstaller.SessionInfo?
        try {
            val session = pi.openSession(stagedSessionId)
            context.contentResolver.openInputStream(uri).use { instream ->
                session.setStagingProgress(0f)

                if (instream == null) {
                    return null
                    return@withContext false
                }

                val sizeBytes = getContentSizeBytes()
                progress.postValue(if (sizeBytes > 0) 0 else -1)
                publishProgress(if (sizeBytes > 0) 0 else -1)

                var totalRead: Long = 0
                session.openWrite("PackageInstaller", 0, sizeBytes).use { out ->
                    val buffer = ByteArray(1024 * 1024)
                    while (true) {
                        val numRead = instream.read(buffer)

                        if (numRead == -1) {
                            session.fsync(out)
                            break
                        }

                        if (isCancelled) {
                            break
                        }

                        out.write(buffer, 0, numRead)

                        if (sizeBytes > 0) {
                            totalRead += numRead.toLong()
                            val fraction = totalRead.toFloat() / sizeBytes.toFloat()
@@ -77,12 +75,21 @@ class SessionStager internal constructor(
                        }
                    }
                }
                return pi.getSessionInfo(stagedSessionId)!!
                sessionInfo = pi.getSessionInfo(stagedSessionId)
            }

        } catch (e: Exception) {
            Log.w(LOG_TAG, "Error staging apk from content URI", e)
            return null
            sessionInfo = null
        }

        return@withContext if (sessionInfo == null
            || !sessionInfo?.isActive!!
            || sessionInfo?.resolvedBaseApkPath == null
        ) {
            Log.w(LOG_TAG, "Session info is invalid: $sessionInfo")
            false
        } else {
            true
        }
    }

@@ -97,21 +104,7 @@ class SessionStager internal constructor(
        }
    }

    override fun onPostExecute(sessionInfo: PackageInstaller.SessionInfo?) {
        if ((sessionInfo == null)
            || !sessionInfo.isActive
            || (sessionInfo.resolvedBaseApkPath == null)
        ) {
            Log.w(LOG_TAG, "Session info is invalid: $sessionInfo")
            listener.onStagingFailure()
            return
        }
        listener.onStagingSuccess(sessionInfo)
    }

    override fun onProgressUpdate(vararg progressVal: Int?) {
        if (progressVal.isNotEmpty()) {
            progress.value = progressVal[0]
        }
    private suspend fun publishProgress(progressValue: Int) = withContext(Dispatchers.Main) {
        _progress.value = progressValue
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.packageinstaller.v2.viewmodel
import android.app.Application
import android.content.Intent
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import com.android.packageinstaller.v2.model.InstallRepository
@@ -56,7 +57,7 @@ class InstallViewModel(application: Application, val repository: InstallReposito
        }
    }

    val stagingProgress: MutableLiveData<Int>
    val stagingProgress: LiveData<Int>
        get() = repository.stagingProgress

    private fun checkIfAllowedAndInitiateInstall() {