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

Commit ba629da3 authored by Christopher Tate's avatar Christopher Tate
Browse files

Ensure recipient can be launched before attempting broadcast delivery

User removal or eviction inherently races with broadcast delivery.  This
patch introduces a latest-possible recheck of the availbility of the
target application before attempting to send it a broadcast.

Once the process has actually been spun up the system is essentially
committed to presenting it as a running application, and there is no
later check of the availability of the app: the failure mode for
continuing to attempt delivery is a crash *in the app process*,
and is user-visible.

We now check the app+userid existence of the intended recipient
just prior to committing to launch its process for receipt, and
if it is no longer available we simply skip that receiver and
continue normally.

Bug 11652784
Bug 11272019
Bug 8263020

Change-Id: Ib19ba2af493250890db7371c1a9f853772db1af0
parent a951fa56
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import android.content.IntentSender;
 *  {@hide}
 */
interface IPackageManager {
    boolean isPackageAvailable(String packageName, int userId);
    PackageInfo getPackageInfo(String packageName, int flags, int userId);
    int getPackageUid(String packageName, int userId);
    int[] getPackageGids(String packageName);
+4 −0
Original line number Diff line number Diff line
@@ -282,6 +282,10 @@ public class PackageParser {
                || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
    }

    public static boolean isAvailable(PackageUserState state) {
        return checkUseInstalledOrBlocked(0, state);
    }

    public static PackageInfo generatePackageInfo(PackageParser.Package p,
            int gids[], int flags, long firstInstallTime, long lastUpdateTime,
            HashSet<String> grantedPermissions, PackageUserState state, int userId) {
+21 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.ComponentName;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
@@ -814,6 +815,26 @@ public final class BroadcastQueue {
                        + " to " + r.curApp + ": process crashing");
                skip = true;
            }
            if (!skip) {
                boolean isAvailable = false;
                try {
                    isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
                            info.activityInfo.packageName,
                            UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
                } catch (Exception e) {
                    // all such failures mean we skip this receiver
                    Slog.w(TAG, "Exception getting recipient info for "
                            + info.activityInfo.packageName, e);
                }
                if (!isAvailable) {
                    if (DEBUG_BROADCAST) {
                        Slog.v(TAG, "Skipping delivery to " + info.activityInfo.packageName
                                + " / " + info.activityInfo.applicationInfo.uid
                                + " : package no longer available");
                    }
                    skip = true;
                }
            }

            if (skip) {
                if (DEBUG_BROADCAST)  Slog.v(TAG,
+18 −0
Original line number Diff line number Diff line
@@ -1771,6 +1771,24 @@ public class PackageManagerService extends IPackageManager.Stub {
                state, userId);
    }

    public boolean isPackageAvailable(String packageName, int userId) {
        if (!sUserManager.exists(userId)) return false;
        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "is package available");
        synchronized (mPackages) {
            PackageParser.Package p = mPackages.get(packageName);
            if (p != null) {
                final PackageSetting ps = (PackageSetting) p.mExtras;
                if (ps != null) {
                    final PackageUserState state = ps.readUserState(userId);
                    if (state != null) {
                        return PackageParser.isAvailable(state);
                    }
                }
            }
        }
        return false;
    }

    @Override
    public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
        if (!sUserManager.exists(userId)) return null;