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

Commit 803b8bf2 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Ensure system internals hear broadcasts first.

Since the modern broadcast queue can dispatch to multiple apps in
parallel, we could end up telling third-party apps about events like
PACKAGE_ADDED before system internals have handled it, causing
developer confusion when calling into an inconsistent service.

This change ensures that all system internals handle PACKAGE_
and USER_ style broadcasts first before apps; if any internals want
to defer until after third-party apps, they can choose to register
themselves with SYSTEM_LOW_PRIORITY.

Bug: 269168765
Test: TH
Change-Id: I567d7dbb542d39de6cc6268fd568a9bd7046c34e
parent 9e717f1b
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -531,6 +531,28 @@ public class IntentFilter implements Parcelable {
        mInstantAppVisibility = o.mInstantAppVisibility;
    }

    /** {@inheritDoc} */
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        sb.append("IntentFilter {");
        sb.append(" pri=");
        sb.append(mPriority);
        if (countActions() > 0) {
            sb.append(" act=");
            sb.append(mActions.toString());
        }
        if (countCategories() > 0) {
            sb.append(" cat=");
            sb.append(mCategories.toString());
        }
        if (countDataSchemes() > 0) {
            sb.append(" sch=");
            sb.append(mDataSchemes.toString());
        }
        sb.append(" }");
        return sb.toString();
    }

    /**
     * Modify priority of this filter.  This only affects receiver filters.
     * The priority of activity filters are set in XML and cannot be changed
+11 −0
Original line number Diff line number Diff line
@@ -157,11 +157,16 @@ public abstract class RegisteredServicesCache<V> {

        migrateIfNecessaryLocked();

        final boolean isCore = UserHandle.isCore(android.os.Process.myUid());

        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        intentFilter.addDataScheme("package");
        if (isCore) {
            intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        }
        Handler handler = BackgroundThread.getHandler();
        mContext.registerReceiverAsUser(
                mPackageReceiver, UserHandle.ALL, intentFilter, null, handler);
@@ -170,11 +175,17 @@ public abstract class RegisteredServicesCache<V> {
        IntentFilter sdFilter = new IntentFilter();
        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
        if (isCore) {
            sdFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        }
        mContext.registerReceiver(mExternalReceiver, sdFilter, null, handler);

        // Register for user-related events
        IntentFilter userFilter = new IntentFilter();
        userFilter.addAction(Intent.ACTION_USER_REMOVED);
        if (isCore) {
            userFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        }
        mContext.registerReceiver(mUserRemovedReceiver, userFilter, null, handler);
    }

+40 −26
Original line number Diff line number Diff line
@@ -39,25 +39,10 @@ import java.util.Objects;
 */
public abstract class PackageMonitor extends android.content.BroadcastReceiver {
    static final String TAG = "PackageMonitor";
    static final IntentFilter sPackageFilt = new IntentFilter();
    static final IntentFilter sNonDataFilt = new IntentFilter();
    static final IntentFilter sExternalFilt = new IntentFilter();

    static {
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
        sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
        sPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
        sPackageFilt.addDataScheme("package");
        sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
        sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
        sNonDataFilt.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
        sNonDataFilt.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
        sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
        sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
    }

    final IntentFilter mPackageFilt;
    final IntentFilter mNonDataFilt;
    final IntentFilter mExternalFilt;

    final HashSet<String> mUpdatingPackages = new HashSet<String>();
    
@@ -75,6 +60,35 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {

    @UnsupportedAppUsage
    public PackageMonitor() {
        final boolean isCore = UserHandle.isCore(android.os.Process.myUid());

        mPackageFilt = new IntentFilter();
        mPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
        mPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
        mPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
        mPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
        mPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
        mPackageFilt.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
        mPackageFilt.addDataScheme("package");
        if (isCore) {
            mPackageFilt.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        }

        mNonDataFilt = new IntentFilter();
        mNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
        mNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
        mNonDataFilt.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
        mNonDataFilt.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
        if (isCore) {
            mNonDataFilt.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        }

        mExternalFilt = new IntentFilter();
        mExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
        mExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
        if (isCore) {
            mExternalFilt.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        }
    }

    @UnsupportedAppUsage
@@ -97,17 +111,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
        mRegisteredContext = context;
        mRegisteredHandler = Objects.requireNonNull(handler);
        if (user != null) {
            context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
            context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
            context.registerReceiverAsUser(this, user, mPackageFilt, null, mRegisteredHandler);
            context.registerReceiverAsUser(this, user, mNonDataFilt, null, mRegisteredHandler);
            if (externalStorage) {
                context.registerReceiverAsUser(this, user, sExternalFilt, null,
                context.registerReceiverAsUser(this, user, mExternalFilt, null,
                        mRegisteredHandler);
            }
        } else {
            context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
            context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
            context.registerReceiver(this, mPackageFilt, null, mRegisteredHandler);
            context.registerReceiver(this, mNonDataFilt, null, mRegisteredHandler);
            if (externalStorage) {
                context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
                context.registerReceiver(this, mExternalFilt, null, mRegisteredHandler);
            }
        }
    }
+34 −0
Original line number Diff line number Diff line
@@ -13624,6 +13624,40 @@ public class ActivityManagerService extends IActivityManager.Stub
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
            // Warn if system internals are registering for important broadcasts
            // without also using a priority to ensure they process the event
            // before normal apps hear about it
            if (UserHandle.isCore(callingUid)) {
                final int priority = filter.getPriority();
                final boolean systemPriority = (priority >= IntentFilter.SYSTEM_HIGH_PRIORITY)
                        || (priority <= IntentFilter.SYSTEM_LOW_PRIORITY);
                if (!systemPriority) {
                    final int N = filter.countActions();
                    for (int i = 0; i < N; i++) {
                        // TODO: expand to additional important broadcasts over time
                        final String action = filter.getAction(i);
                        if (action.startsWith("android.intent.action.USER_")
                                || action.startsWith("android.intent.action.PACKAGE_")
                                || action.startsWith("android.intent.action.UID_")
                                || action.startsWith("android.intent.action.EXTERNAL_")) {
                            if (DEBUG_BROADCAST) {
                                Slog.wtf(TAG, "System internals registering for " + filter
                                        + " with app priority; this will race with apps!",
                                        new Throwable());
                            }
                            // When undefined, assume that system internals need
                            // to hear about the event first; they can use
                            // SYSTEM_LOW_PRIORITY if they need to hear last
                            if (priority == 0) {
                                filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
                            }
                            break;
                        }
                    }
                }
            }
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
+1 −1
Original line number Diff line number Diff line
@@ -690,7 +690,7 @@ public class SyncManager {
        context.registerReceiver(mConnectivityIntentReceiver, intentFilter);

        intentFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
        intentFilter.setPriority(100);
        intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        context.registerReceiver(mShutdownIntentReceiver, intentFilter);

        intentFilter = new IntentFilter();
Loading