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

Commit 26ff1c4e authored by Joanne Chung's avatar Joanne Chung
Browse files

Use PendingIntent instead of using in-memory intent sender object

The current implementation uses an in-memory intent sender object,
this only works if the caller’s process remains alive. This change
changes the implementation to use PendingIntent intent sender, this
can wake up the caller's process if needed.

Bug: 281798465
Test: atest InstallConstraintsTest
Change-Id: Ib460d1a614936d17f0b08658d5e97dcd818df710
parent 029c69c8
Loading
Loading
Loading
Loading
+67 −30
Original line number Diff line number Diff line
@@ -46,10 +46,12 @@ import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageManager.DeleteFlags;
import android.content.pm.PackageManager.InstallReason;
@@ -62,11 +64,9 @@ import android.graphics.Bitmap;
import android.icu.util.ULocale;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.FileBridge;
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -148,6 +148,9 @@ import java.util.function.Consumer;
public class PackageInstaller {
    private static final String TAG = "PackageInstaller";

    private static final String ACTION_WAIT_INSTALL_CONSTRAINTS =
            "android.content.pm.action.WAIT_INSTALL_CONSTRAINTS";

    /** {@hide} */
    public static final boolean ENABLE_REVOCABLE_FD =
            SystemProperties.getBoolean("fw.revocable_fd", false);
@@ -1073,34 +1076,68 @@ public class PackageInstaller {
            var session = mInstaller.openSession(sessionId);
            session.seal();
            var packageNames = session.fetchPackageNames();
            var intentSender = new IntentSender((IIntentSender) new IIntentSender.Stub() {
            var context = ActivityThread.currentApplication();
            var localIntentSender = new LocalIntentSender(context, sessionId, session,
                    statusReceiver);
            waitForInstallConstraints(packageNames, constraints,
                    localIntentSender.getIntentSender(), timeoutMillis);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    private static final class LocalIntentSender extends BroadcastReceiver {

        private final Context mContext;
        private final IntentSender mStatusReceiver;
        private final int mSessionId;
        private final IPackageInstallerSession mSession;

        LocalIntentSender(Context context, int sessionId, IPackageInstallerSession session,
                IntentSender statusReceiver) {
            mContext = context;
            mSessionId = sessionId;
            mSession = session;
            mStatusReceiver = statusReceiver;
        }

        private IntentSender getIntentSender() {
            Intent intent = new Intent(ACTION_WAIT_INSTALL_CONSTRAINTS).setPackage(
                    mContext.getPackageName());
            mContext.registerReceiver(this, new IntentFilter(ACTION_WAIT_INSTALL_CONSTRAINTS),
                    Context.RECEIVER_EXPORTED);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent,
                    PendingIntent.FLAG_MUTABLE);
            return pendingIntent.getIntentSender();
        }

        @Override
                public void send(int code, Intent intent, String resolvedType,
                        IBinder allowlistToken, IIntentReceiver finishedReceiver,
                        String requiredPermission, Bundle options)  {
                    var result = intent.getParcelableExtra(
        public void onReceive(Context context, Intent intent) {
            InstallConstraintsResult result = intent.getParcelableExtra(
                    PackageInstaller.EXTRA_INSTALL_CONSTRAINTS_RESULT,
                    InstallConstraintsResult.class);
            try {
                if (result.areAllConstraintsSatisfied()) {
                            session.commit(statusReceiver, false);
                    mSession.commit(mStatusReceiver, false);
                } else {
                    // timeout
                    final Intent fillIn = new Intent();
                            fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
                    fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);
                    fillIn.putExtra(PackageInstaller.EXTRA_STATUS, STATUS_FAILURE_TIMEOUT);
                    fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
                            "Install constraints not satisfied within timeout");
                            statusReceiver.sendIntent(
                                    ActivityThread.currentApplication(), 0, fillIn, null, null);
                    mStatusReceiver.sendIntent(ActivityThread.currentApplication(), 0, fillIn, null,
                            null);
                }
            } catch (Exception ignore) {
                // no-op
            } finally {
                unregisterReceiver();
            }
        }
            });
            waitForInstallConstraints(packageNames, constraints, intentSender, timeoutMillis);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();

        private void unregisterReceiver() {
            mContext.unregisterReceiver(this);
        }
    }