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 Original line Diff line number Diff line
@@ -531,6 +531,28 @@ public class IntentFilter implements Parcelable {
        mInstantAppVisibility = o.mInstantAppVisibility;
        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.
     * Modify priority of this filter.  This only affects receiver filters.
     * The priority of activity filters are set in XML and cannot be changed
     * The priority of activity filters are set in XML and cannot be changed
+11 −0
Original line number Original line Diff line number Diff line
@@ -157,11 +157,16 @@ public abstract class RegisteredServicesCache<V> {


        migrateIfNecessaryLocked();
        migrateIfNecessaryLocked();


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

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


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


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

    static final IntentFilter sNonDataFilt = new IntentFilter();
    final IntentFilter mPackageFilt;
    static final IntentFilter sExternalFilt = new IntentFilter();
    final IntentFilter mNonDataFilt;

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


    @UnsupportedAppUsage
    @UnsupportedAppUsage
    public PackageMonitor() {
    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
    @UnsupportedAppUsage
@@ -97,17 +111,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
        mRegisteredContext = context;
        mRegisteredContext = context;
        mRegisteredHandler = Objects.requireNonNull(handler);
        mRegisteredHandler = Objects.requireNonNull(handler);
        if (user != null) {
        if (user != null) {
            context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
            context.registerReceiverAsUser(this, user, mPackageFilt, null, mRegisteredHandler);
            context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
            context.registerReceiverAsUser(this, user, mNonDataFilt, null, mRegisteredHandler);
            if (externalStorage) {
            if (externalStorage) {
                context.registerReceiverAsUser(this, user, sExternalFilt, null,
                context.registerReceiverAsUser(this, user, mExternalFilt, null,
                        mRegisteredHandler);
                        mRegisteredHandler);
            }
            }
        } else {
        } else {
            context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
            context.registerReceiver(this, mPackageFilt, null, mRegisteredHandler);
            context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
            context.registerReceiver(this, mNonDataFilt, null, mRegisteredHandler);
            if (externalStorage) {
            if (externalStorage) {
                context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
                context.registerReceiver(this, mExternalFilt, null, mRegisteredHandler);
            }
            }
        }
        }
    }
    }
+34 −0
Original line number Original line Diff line number Diff line
@@ -13624,6 +13624,40 @@ public class ActivityManagerService extends IActivityManager.Stub
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
                    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();
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                ArrayList<String> noAction = new ArrayList<String>(1);
+1 −1
Original line number Original line Diff line number Diff line
@@ -690,7 +690,7 @@ public class SyncManager {
        context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
        context.registerReceiver(mConnectivityIntentReceiver, intentFilter);


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


        intentFilter = new IntentFilter();
        intentFilter = new IntentFilter();
Loading