Loading packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +2 −2 Original line number Diff line number Diff line Loading @@ -270,7 +270,7 @@ public class InstallInstalling extends Activity { * during an uninstall. */ private void launchFinishBasedOnResult(int statusCode, int legacyStatus, String statusMessage, int serviceId /* ignore */, boolean hasDeveloperVerificationFailure) { int serviceId /* ignore */) { if (statusCode == PackageInstaller.STATUS_SUCCESS) { launchSuccess(); } else { Loading @@ -280,7 +280,7 @@ public class InstallInstalling extends Activity { /** * Send the package to the package installer and then register a event result observer that * will call {@link #launchFinishBasedOnResult(int, int, String, int, boolean)} * will call {@link #launchFinishBasedOnResult(int, int, String, int)} */ private final class InstallingAsyncTask extends AsyncTask<Void, Void, PackageInstaller.Session> { Loading packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java +2 −3 Original line number Diff line number Diff line Loading @@ -132,7 +132,7 @@ public class UninstallUninstalling extends Activity implements } catch (EventResultPersister.OutOfIdsException | IllegalArgumentException e) { Log.e(LOG_TAG, "Fails to start uninstall", e); onResult(PackageInstaller.STATUS_FAILURE, PackageManager.DELETE_FAILED_INTERNAL_ERROR, null, 0, false); null, 0); } } Loading @@ -149,8 +149,7 @@ public class UninstallUninstalling extends Activity implements } @Override public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure) { public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId) { if (mCallback != null) { // The caller will be informed about the result via a callback mCallback.onUninstallComplete(mAppInfo.packageName, legacyStatus, message); Loading packages/PackageInstaller/src/com/android/packageinstaller/common/EventResultPersister.java +35 −39 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import android.content.Context; import android.content.Intent; import android.content.pm.Flags; import android.content.pm.PackageInstaller; import android.os.AsyncTask; import android.util.AtomicFile; Loading @@ -31,6 +30,8 @@ import android.util.Xml; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.packageinstaller.PackageUtil; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading Loading @@ -98,8 +99,15 @@ public class EventResultPersister { /** * Called when a result is received. */ void onResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure); void onResult(int status, int legacyStatus, @Nullable String message, int serviceId); /** * Return true if the intent is handled by the observer. When the intent is handled, * do not trigger #onResult() and not remove the observer. */ default boolean onHandleIntent(Intent intent) { return false; } } /** Loading Loading @@ -139,19 +147,6 @@ public class EventResultPersister { return parser.getAttributeValue(null, name); } /** * Read a boolean attribute from the current element * * @param parser The parser to read from * @param name The attribute name to read * * @return The value of the attribute */ private static boolean readBooleanAttribute(@NonNull XmlPullParser parser, @NonNull String name) { return Boolean.parseBoolean(parser.getAttributeValue(null, name)); } /** * Read persisted state. * Loading @@ -176,15 +171,13 @@ public class EventResultPersister { int legacyStatus = readIntAttribute(parser, "legacyStatus"); String statusMessage = readStringAttribute(parser, "statusMessage"); int serviceId = readIntAttribute(parser, "serviceId"); boolean hasDeveloperVerificationFailure = Flags.verificationService() && readBooleanAttribute(parser, "hasDeveloperVerificationFailure"); if (mResults.get(id) != null) { throw new Exception("id " + id + " has two results"); } mResults.put(id, new EventResult(status, legacyStatus, statusMessage, serviceId, hasDeveloperVerificationFailure)); serviceId)); } else { throw new Exception("unexpected tag"); } Loading @@ -198,17 +191,22 @@ public class EventResultPersister { } /** * Add a result. If the result is an pending user action, execute the pending user action * directly and do not queue a result. * Add a result. If the result is a pending user action, execute the pending user action * directly and do not queue a result in version one. In version two, call back the * EventResultObserver#onHandleIntent to make sure if the intent is handled first. * * @param context The context the event was received in * @param intent The intent the activity received */ void onEventReceived(@NonNull Context context, @NonNull Intent intent) { int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0); Log.d(LOG_TAG, "Received event with status " + status + ", action = " + intent.getAction()); if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) { Intent intentToStart = intent.getParcelableExtra(Intent.EXTRA_INTENT); // If it is PIA version one, starts the activity directly. if (!PackageUtil.isVersionTwoEnabled(context) && status == PackageInstaller.STATUS_PENDING_USER_ACTION) { Intent intentToStart = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class); intentToStart.addFlags(FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentToStart); Loading @@ -219,27 +217,32 @@ public class EventResultPersister { String statusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE); int legacyStatus = intent.getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 0); int serviceId = intent.getIntExtra(EXTRA_SERVICE_ID, 0); boolean hasDeveloperVerificationFailure = Flags.verificationService() && intent.hasExtra(PackageInstaller.EXTRA_DEVELOPER_VERIFICATION_FAILURE_REASON); EventResultObserver observerToCall = null; boolean isIntentHandled = false; synchronized (mLock) { int numObservers = mObservers.size(); for (int i = 0; i < numObservers; i++) { if (mObservers.keyAt(i) == id) { observerToCall = mObservers.valueAt(i); // If the intent is handled, don't remove the observer, still needs to // receive the later events. isIntentHandled = observerToCall.onHandleIntent(intent); if (!isIntentHandled) { mObservers.removeAt(i); } break; } } if (observerToCall != null) { observerToCall.onResult(status, legacyStatus, statusMessage, serviceId, hasDeveloperVerificationFailure); // If the intent is handled, don't call back the observer#onResult(). if (!isIntentHandled) { observerToCall.onResult(status, legacyStatus, statusMessage, serviceId); } } else { mResults.put(id, new EventResult(status, legacyStatus, statusMessage, serviceId, hasDeveloperVerificationFailure)); mResults.put(id, new EventResult(status, legacyStatus, statusMessage, serviceId)); writeState(); } } Loading Loading @@ -291,10 +294,6 @@ public class EventResultPersister { serializer.attribute(null, "statusMessage", results.valueAt(i).message); } if (results.valueAt(i).hasDeveloperVerificationFailure) { serializer.attribute(null, "hasDeveloperVerificationFailure", "true"); } serializer.attribute(null, "serviceId", Integer.toString(results.valueAt(i).serviceId)); serializer.endTag(null, "result"); Loading Loading @@ -351,7 +350,7 @@ public class EventResultPersister { EventResult result = mResults.valueAt(resultIndex); observer.onResult(result.status, result.legacyStatus, result.message, result.serviceId, result.hasDeveloperVerificationFailure); result.serviceId); mResults.removeAt(resultIndex); writeState(); } else { Loading Loading @@ -382,15 +381,12 @@ public class EventResultPersister { public final int legacyStatus; @Nullable public final String message; public final int serviceId; public final boolean hasDeveloperVerificationFailure; private EventResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure) { private EventResult(int status, int legacyStatus, @Nullable String message, int serviceId) { this.status = status; this.legacyStatus = legacyStatus; this.message = message; this.serviceId = serviceId; this.hasDeveloperVerificationFailure = hasDeveloperVerificationFailure; } } Loading packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAppProgress.java +2 −3 Original line number Diff line number Diff line Loading @@ -298,7 +298,7 @@ public class UninstallAppProgress extends Activity implements } catch (EventResultPersister.OutOfIdsException e) { Log.e(TAG, "Fails to start uninstall", e); onResult(PackageInstaller.STATUS_FAILURE, PackageManager.DELETE_FAILED_INTERNAL_ERROR, null, 0, false); null, 0); } mHandler.sendMessageDelayed(mHandler.obtainMessage(UNINSTALL_IS_SLOW), Loading @@ -310,8 +310,7 @@ public class UninstallAppProgress extends Activity implements } @Override public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure) { public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId) { Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE); msg.arg1 = legacyStatus; msg.obj = mAppInfo.packageName; Loading packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt +75 −32 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch @SuppressLint("MissingPermission") class InstallRepository(private val context: Context) { class InstallRepository(private val context: Context) : EventResultPersister.EventResultObserver { private val packageManager: PackageManager = context.packageManager private val packageInstaller: PackageInstaller = packageManager.packageInstaller Loading Loading @@ -137,6 +137,7 @@ class InstallRepository(private val context: Context) { * PackageInfo of the app being installed on device. */ private var newPackageInfo: PackageInfo? = null private var wasUserConfirmationTriggeredByPia = false /** * Extracts information from the incoming install intent, checks caller's permission to install Loading Loading @@ -887,8 +888,16 @@ class InstallRepository(private val context: Context) { packageInstaller.setDeveloperVerificationUserResponse( sessionId, DEVELOPER_VERIFICATION_USER_RESPONSE_INSTALL_ANYWAY ) // If it is triggered by PIA itself, show the installing dialog and wait for the // result from the receiver. Don't need to set the aborted. if (wasUserConfirmationTriggeredByPia) { wasUserConfirmationTriggeredByPia = false return InstallInstalling(appSnippet, isAppUpdating) } else { return InstallAborted( ABORT_REASON_DONE, activityResultCode = Activity.RESULT_OK) ABORT_REASON_DONE, activityResultCode = Activity.RESULT_OK ) } } /** Loading Loading @@ -985,9 +994,16 @@ class InstallRepository(private val context: Context) { if (localLogv) { Log.i(LOG_TAG, "Install permission granted for session $sessionId") } // If it is triggered by PIA itself, show the installing dialog and wait for the // result from the receiver. Don't need to set the aborted. if (wasUserConfirmationTriggeredByPia) { wasUserConfirmationTriggeredByPia = false _installResult.value = InstallInstalling(appSnippet, isAppUpdating) } else { _installResult.value = InstallAborted( ABORT_REASON_DONE, activityResultCode = Activity.RESULT_OK ) } return } val uri = intent.data Loading Loading @@ -1016,13 +1032,10 @@ class InstallRepository(private val context: Context) { try { _installResult.value = InstallInstalling(appSnippet, isAppUpdating) installId = InstallEventReceiver.addObserver( context, EventResultPersister.GENERATE_NEW_ID ) { statusCode: Int, legacyStatus: Int, message: String?, serviceId: Int, hasDeveloperVerificationFailure: Boolean -> setStageBasedOnResult(statusCode, legacyStatus, message, hasDeveloperVerificationFailure context, EventResultPersister.GENERATE_NEW_ID, this ) } } catch (e: OutOfIdsException) { setStageBasedOnResult( PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null Loading Loading @@ -1052,7 +1065,6 @@ class InstallRepository(private val context: Context) { statusCode: Int, legacyStatus: Int, message: String?, hasDeveloperVerificationFailure: Boolean = false ) { if (localLogv) { Log.i( Loading @@ -1071,14 +1083,12 @@ class InstallRepository(private val context: Context) { val intent = packageManager.getLaunchIntentForPackage(newPackageInfo!!.packageName) if (isLauncherActivityEnabled(intent)) intent else null } _installResult.setValue( InstallSuccess( _installResult.value = InstallSuccess( appSnippet, shouldReturnResult, isAppUpdating, resultIntent ) ) } else { // TODO (b/346655018): Use INSTALL_FAILED_ABORTED legacyCode in the condition // statusCode can be STATUS_FAILURE_ABORTED if: Loading @@ -1093,20 +1103,16 @@ class InstallRepository(private val context: Context) { if (shouldReturnResult) { val resultIntent = Intent().putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus) _installResult.setValue( InstallFailed( _installResult.value = InstallFailed( legacyCode = legacyStatus, statusCode = statusCode, shouldReturnResult = true, resultIntent = resultIntent ) ) } else if (userDenied) { _installResult.setValue(InstallAborted(ABORT_REASON_INTERNAL_ERROR)) _installResult.value = InstallAborted(ABORT_REASON_INTERNAL_ERROR) } else { _installResult.setValue( InstallFailed(appSnippet, legacyStatus, statusCode, message) ) _installResult.value = InstallFailed(appSnippet, legacyStatus, statusCode, message) } } } Loading Loading @@ -1140,6 +1146,43 @@ class InstallRepository(private val context: Context) { val stagingProgress: LiveData<Int> get() = sessionStager?.progress ?: MutableLiveData(0) /** Override the callback method of the EventResultPersister.EventResultObserver */ override fun onResult( status: Int, legacyStatus: Int, message: String?, serviceId: Int, ) { setStageBasedOnResult(status, legacyStatus, message) } /** Override the callback method of the EventResultPersister.EventResultObserver */ override fun onHandleIntent(intent: Intent): Boolean { val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0) // If the status is pending user action, trigger the user confirmation from PIA. if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) { val intentToStart = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java) // Get the value of should return result from the original intent and add it into // the intentToStart val shouldReturnResult = this.intent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false) intentToStart!!.putExtra(Intent.EXTRA_RETURN_RESULT, shouldReturnResult) // In this case, the caller is PIA itself val stage = performPreInstallChecks( intentToStart!!, CallerInfo(context.packageName, context.applicationInfo.uid)) if (stage.stageCode == InstallStage.STAGE_ABORTED) { _installResult.value = stage return false } wasUserConfirmationTriggeredByPia = true stageForInstall() return true } return false } companion object { const val EXTRA_STAGED_SESSION_ID = "com.android.packageinstaller.extra.STAGED_SESSION_ID" const val SCHEME_PACKAGE = "package" Loading Loading
packages/PackageInstaller/src/com/android/packageinstaller/InstallInstalling.java +2 −2 Original line number Diff line number Diff line Loading @@ -270,7 +270,7 @@ public class InstallInstalling extends Activity { * during an uninstall. */ private void launchFinishBasedOnResult(int statusCode, int legacyStatus, String statusMessage, int serviceId /* ignore */, boolean hasDeveloperVerificationFailure) { int serviceId /* ignore */) { if (statusCode == PackageInstaller.STATUS_SUCCESS) { launchSuccess(); } else { Loading @@ -280,7 +280,7 @@ public class InstallInstalling extends Activity { /** * Send the package to the package installer and then register a event result observer that * will call {@link #launchFinishBasedOnResult(int, int, String, int, boolean)} * will call {@link #launchFinishBasedOnResult(int, int, String, int)} */ private final class InstallingAsyncTask extends AsyncTask<Void, Void, PackageInstaller.Session> { Loading
packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java +2 −3 Original line number Diff line number Diff line Loading @@ -132,7 +132,7 @@ public class UninstallUninstalling extends Activity implements } catch (EventResultPersister.OutOfIdsException | IllegalArgumentException e) { Log.e(LOG_TAG, "Fails to start uninstall", e); onResult(PackageInstaller.STATUS_FAILURE, PackageManager.DELETE_FAILED_INTERNAL_ERROR, null, 0, false); null, 0); } } Loading @@ -149,8 +149,7 @@ public class UninstallUninstalling extends Activity implements } @Override public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure) { public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId) { if (mCallback != null) { // The caller will be informed about the result via a callback mCallback.onUninstallComplete(mAppInfo.packageName, legacyStatus, message); Loading
packages/PackageInstaller/src/com/android/packageinstaller/common/EventResultPersister.java +35 −39 Original line number Diff line number Diff line Loading @@ -20,7 +20,6 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import android.content.Context; import android.content.Intent; import android.content.pm.Flags; import android.content.pm.PackageInstaller; import android.os.AsyncTask; import android.util.AtomicFile; Loading @@ -31,6 +30,8 @@ import android.util.Xml; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.packageinstaller.PackageUtil; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; Loading Loading @@ -98,8 +99,15 @@ public class EventResultPersister { /** * Called when a result is received. */ void onResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure); void onResult(int status, int legacyStatus, @Nullable String message, int serviceId); /** * Return true if the intent is handled by the observer. When the intent is handled, * do not trigger #onResult() and not remove the observer. */ default boolean onHandleIntent(Intent intent) { return false; } } /** Loading Loading @@ -139,19 +147,6 @@ public class EventResultPersister { return parser.getAttributeValue(null, name); } /** * Read a boolean attribute from the current element * * @param parser The parser to read from * @param name The attribute name to read * * @return The value of the attribute */ private static boolean readBooleanAttribute(@NonNull XmlPullParser parser, @NonNull String name) { return Boolean.parseBoolean(parser.getAttributeValue(null, name)); } /** * Read persisted state. * Loading @@ -176,15 +171,13 @@ public class EventResultPersister { int legacyStatus = readIntAttribute(parser, "legacyStatus"); String statusMessage = readStringAttribute(parser, "statusMessage"); int serviceId = readIntAttribute(parser, "serviceId"); boolean hasDeveloperVerificationFailure = Flags.verificationService() && readBooleanAttribute(parser, "hasDeveloperVerificationFailure"); if (mResults.get(id) != null) { throw new Exception("id " + id + " has two results"); } mResults.put(id, new EventResult(status, legacyStatus, statusMessage, serviceId, hasDeveloperVerificationFailure)); serviceId)); } else { throw new Exception("unexpected tag"); } Loading @@ -198,17 +191,22 @@ public class EventResultPersister { } /** * Add a result. If the result is an pending user action, execute the pending user action * directly and do not queue a result. * Add a result. If the result is a pending user action, execute the pending user action * directly and do not queue a result in version one. In version two, call back the * EventResultObserver#onHandleIntent to make sure if the intent is handled first. * * @param context The context the event was received in * @param intent The intent the activity received */ void onEventReceived(@NonNull Context context, @NonNull Intent intent) { int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0); Log.d(LOG_TAG, "Received event with status " + status + ", action = " + intent.getAction()); if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) { Intent intentToStart = intent.getParcelableExtra(Intent.EXTRA_INTENT); // If it is PIA version one, starts the activity directly. if (!PackageUtil.isVersionTwoEnabled(context) && status == PackageInstaller.STATUS_PENDING_USER_ACTION) { Intent intentToStart = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class); intentToStart.addFlags(FLAG_ACTIVITY_NEW_TASK); context.startActivity(intentToStart); Loading @@ -219,27 +217,32 @@ public class EventResultPersister { String statusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE); int legacyStatus = intent.getIntExtra(PackageInstaller.EXTRA_LEGACY_STATUS, 0); int serviceId = intent.getIntExtra(EXTRA_SERVICE_ID, 0); boolean hasDeveloperVerificationFailure = Flags.verificationService() && intent.hasExtra(PackageInstaller.EXTRA_DEVELOPER_VERIFICATION_FAILURE_REASON); EventResultObserver observerToCall = null; boolean isIntentHandled = false; synchronized (mLock) { int numObservers = mObservers.size(); for (int i = 0; i < numObservers; i++) { if (mObservers.keyAt(i) == id) { observerToCall = mObservers.valueAt(i); // If the intent is handled, don't remove the observer, still needs to // receive the later events. isIntentHandled = observerToCall.onHandleIntent(intent); if (!isIntentHandled) { mObservers.removeAt(i); } break; } } if (observerToCall != null) { observerToCall.onResult(status, legacyStatus, statusMessage, serviceId, hasDeveloperVerificationFailure); // If the intent is handled, don't call back the observer#onResult(). if (!isIntentHandled) { observerToCall.onResult(status, legacyStatus, statusMessage, serviceId); } } else { mResults.put(id, new EventResult(status, legacyStatus, statusMessage, serviceId, hasDeveloperVerificationFailure)); mResults.put(id, new EventResult(status, legacyStatus, statusMessage, serviceId)); writeState(); } } Loading Loading @@ -291,10 +294,6 @@ public class EventResultPersister { serializer.attribute(null, "statusMessage", results.valueAt(i).message); } if (results.valueAt(i).hasDeveloperVerificationFailure) { serializer.attribute(null, "hasDeveloperVerificationFailure", "true"); } serializer.attribute(null, "serviceId", Integer.toString(results.valueAt(i).serviceId)); serializer.endTag(null, "result"); Loading Loading @@ -351,7 +350,7 @@ public class EventResultPersister { EventResult result = mResults.valueAt(resultIndex); observer.onResult(result.status, result.legacyStatus, result.message, result.serviceId, result.hasDeveloperVerificationFailure); result.serviceId); mResults.removeAt(resultIndex); writeState(); } else { Loading Loading @@ -382,15 +381,12 @@ public class EventResultPersister { public final int legacyStatus; @Nullable public final String message; public final int serviceId; public final boolean hasDeveloperVerificationFailure; private EventResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure) { private EventResult(int status, int legacyStatus, @Nullable String message, int serviceId) { this.status = status; this.legacyStatus = legacyStatus; this.message = message; this.serviceId = serviceId; this.hasDeveloperVerificationFailure = hasDeveloperVerificationFailure; } } Loading
packages/PackageInstaller/src/com/android/packageinstaller/television/UninstallAppProgress.java +2 −3 Original line number Diff line number Diff line Loading @@ -298,7 +298,7 @@ public class UninstallAppProgress extends Activity implements } catch (EventResultPersister.OutOfIdsException e) { Log.e(TAG, "Fails to start uninstall", e); onResult(PackageInstaller.STATUS_FAILURE, PackageManager.DELETE_FAILED_INTERNAL_ERROR, null, 0, false); null, 0); } mHandler.sendMessageDelayed(mHandler.obtainMessage(UNINSTALL_IS_SLOW), Loading @@ -310,8 +310,7 @@ public class UninstallAppProgress extends Activity implements } @Override public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId, boolean hasDeveloperVerificationFailure) { public void onResult(int status, int legacyStatus, @Nullable String message, int serviceId) { Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE); msg.arg1 = legacyStatus; msg.obj = mAppInfo.packageName; Loading
packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallRepository.kt +75 −32 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.launch @SuppressLint("MissingPermission") class InstallRepository(private val context: Context) { class InstallRepository(private val context: Context) : EventResultPersister.EventResultObserver { private val packageManager: PackageManager = context.packageManager private val packageInstaller: PackageInstaller = packageManager.packageInstaller Loading Loading @@ -137,6 +137,7 @@ class InstallRepository(private val context: Context) { * PackageInfo of the app being installed on device. */ private var newPackageInfo: PackageInfo? = null private var wasUserConfirmationTriggeredByPia = false /** * Extracts information from the incoming install intent, checks caller's permission to install Loading Loading @@ -887,8 +888,16 @@ class InstallRepository(private val context: Context) { packageInstaller.setDeveloperVerificationUserResponse( sessionId, DEVELOPER_VERIFICATION_USER_RESPONSE_INSTALL_ANYWAY ) // If it is triggered by PIA itself, show the installing dialog and wait for the // result from the receiver. Don't need to set the aborted. if (wasUserConfirmationTriggeredByPia) { wasUserConfirmationTriggeredByPia = false return InstallInstalling(appSnippet, isAppUpdating) } else { return InstallAborted( ABORT_REASON_DONE, activityResultCode = Activity.RESULT_OK) ABORT_REASON_DONE, activityResultCode = Activity.RESULT_OK ) } } /** Loading Loading @@ -985,9 +994,16 @@ class InstallRepository(private val context: Context) { if (localLogv) { Log.i(LOG_TAG, "Install permission granted for session $sessionId") } // If it is triggered by PIA itself, show the installing dialog and wait for the // result from the receiver. Don't need to set the aborted. if (wasUserConfirmationTriggeredByPia) { wasUserConfirmationTriggeredByPia = false _installResult.value = InstallInstalling(appSnippet, isAppUpdating) } else { _installResult.value = InstallAborted( ABORT_REASON_DONE, activityResultCode = Activity.RESULT_OK ) } return } val uri = intent.data Loading Loading @@ -1016,13 +1032,10 @@ class InstallRepository(private val context: Context) { try { _installResult.value = InstallInstalling(appSnippet, isAppUpdating) installId = InstallEventReceiver.addObserver( context, EventResultPersister.GENERATE_NEW_ID ) { statusCode: Int, legacyStatus: Int, message: String?, serviceId: Int, hasDeveloperVerificationFailure: Boolean -> setStageBasedOnResult(statusCode, legacyStatus, message, hasDeveloperVerificationFailure context, EventResultPersister.GENERATE_NEW_ID, this ) } } catch (e: OutOfIdsException) { setStageBasedOnResult( PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null Loading Loading @@ -1052,7 +1065,6 @@ class InstallRepository(private val context: Context) { statusCode: Int, legacyStatus: Int, message: String?, hasDeveloperVerificationFailure: Boolean = false ) { if (localLogv) { Log.i( Loading @@ -1071,14 +1083,12 @@ class InstallRepository(private val context: Context) { val intent = packageManager.getLaunchIntentForPackage(newPackageInfo!!.packageName) if (isLauncherActivityEnabled(intent)) intent else null } _installResult.setValue( InstallSuccess( _installResult.value = InstallSuccess( appSnippet, shouldReturnResult, isAppUpdating, resultIntent ) ) } else { // TODO (b/346655018): Use INSTALL_FAILED_ABORTED legacyCode in the condition // statusCode can be STATUS_FAILURE_ABORTED if: Loading @@ -1093,20 +1103,16 @@ class InstallRepository(private val context: Context) { if (shouldReturnResult) { val resultIntent = Intent().putExtra(Intent.EXTRA_INSTALL_RESULT, legacyStatus) _installResult.setValue( InstallFailed( _installResult.value = InstallFailed( legacyCode = legacyStatus, statusCode = statusCode, shouldReturnResult = true, resultIntent = resultIntent ) ) } else if (userDenied) { _installResult.setValue(InstallAborted(ABORT_REASON_INTERNAL_ERROR)) _installResult.value = InstallAborted(ABORT_REASON_INTERNAL_ERROR) } else { _installResult.setValue( InstallFailed(appSnippet, legacyStatus, statusCode, message) ) _installResult.value = InstallFailed(appSnippet, legacyStatus, statusCode, message) } } } Loading Loading @@ -1140,6 +1146,43 @@ class InstallRepository(private val context: Context) { val stagingProgress: LiveData<Int> get() = sessionStager?.progress ?: MutableLiveData(0) /** Override the callback method of the EventResultPersister.EventResultObserver */ override fun onResult( status: Int, legacyStatus: Int, message: String?, serviceId: Int, ) { setStageBasedOnResult(status, legacyStatus, message) } /** Override the callback method of the EventResultPersister.EventResultObserver */ override fun onHandleIntent(intent: Intent): Boolean { val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0) // If the status is pending user action, trigger the user confirmation from PIA. if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) { val intentToStart = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java) // Get the value of should return result from the original intent and add it into // the intentToStart val shouldReturnResult = this.intent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false) intentToStart!!.putExtra(Intent.EXTRA_RETURN_RESULT, shouldReturnResult) // In this case, the caller is PIA itself val stage = performPreInstallChecks( intentToStart!!, CallerInfo(context.packageName, context.applicationInfo.uid)) if (stage.stageCode == InstallStage.STAGE_ABORTED) { _installResult.value = stage return false } wasUserConfirmationTriggeredByPia = true stageForInstall() return true } return false } companion object { const val EXTRA_STAGED_SESSION_ID = "com.android.packageinstaller.extra.STAGED_SESSION_ID" const val SCHEME_PACKAGE = "package" Loading