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

Commit 5aadd492 authored by Yan Zhu's avatar Yan Zhu
Browse files

Fix BroadcastReceiver leaked during user switching

Switch between two users multiple times will not continously increase
number of receivers registered to system, i.e. reach an equilibrium

Bug: 224501318
Test: check with adb:
while true; do adb shell dumpsys activity broadcasts | egrep \
'app=[0-9]+:system' | wc -l; date; sleep 1; done

Change-Id: Ifcf39250c4874cd0b7997c0fcbc4b85cd8a2f4f6
parent 0797d975
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -2116,6 +2116,7 @@ class StorageManagerService extends IStorageManager.Stub
            }
        }

        if (mPackageMonitorsForUser.get(userId) == null) {
            PackageMonitor monitor = new PackageMonitor() {
                @Override
                public void onPackageRemoved(String packageName, int uid) {
@@ -2125,6 +2126,9 @@ class StorageManagerService extends IStorageManager.Stub
            // TODO(b/149391976): Use different handler?
            monitor.register(mContext, user, true, mHandler);
            mPackageMonitorsForUser.put(userId, monitor);
        } else {
            Slog.w(TAG, "PackageMonitor is already registered for: " + userId);
        }
    }

    private static long getLastAccessTime(AppOpsManager manager,
+4 −0
Original line number Diff line number Diff line
@@ -133,6 +133,10 @@ class BluetoothRouteProvider {
                mIntentFilter, null, null);
    }

    public void stop() {
        mContext.unregisterReceiver(mBroadcastReceiver);
    }

    /**
     * Transfers to a given bluetooth route.
     * The dedicated BT device with the route would be activated.
+4 −0
Original line number Diff line number Diff line
@@ -1150,6 +1150,8 @@ class MediaRouter2ServiceImpl {
            if (DEBUG) {
                Slog.d(TAG, userRecord + ": Disposed");
            }
            userRecord.mHandler.sendMessage(
                    obtainMessage(UserHandler::stop, userRecord.mHandler));
            mUserRecords.remove(userRecord.mUserId);
            // Note: User already stopped (by switchUser) so no need to send stop message here.
        }
@@ -1330,6 +1332,7 @@ class MediaRouter2ServiceImpl {
        private void start() {
            if (!mRunning) {
                mRunning = true;
                mSystemProvider.start();
                mWatcher.start();
            }
        }
@@ -1338,6 +1341,7 @@ class MediaRouter2ServiceImpl {
            if (mRunning) {
                mRunning = false;
                mWatcher.stop(); // also stops all providers
                mSystemProvider.stop();
            }
        }

+19 −2
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
    private final IAudioService mAudioService;
    private final Handler mHandler;
    private final Context mContext;
    private final UserHandle mUser;
    private final BluetoothRouteProvider mBtRouteProvider;

    private static ComponentName sComponentName = new ComponentName(
@@ -86,6 +87,9 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
    final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
    int mDeviceVolume;

    private final AudioManagerBroadcastReceiver mAudioReceiver =
            new AudioManagerBroadcastReceiver();

    private final Object mRequestLock = new Object();
    @GuardedBy("mRequestLock")
    private volatile SessionCreationRequest mPendingSessionCreationRequest;
@@ -108,6 +112,7 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {

        mIsSystemRouteProvider = true;
        mContext = context;
        mUser = user;
        mHandler = new Handler(Looper.getMainLooper());

        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@@ -128,21 +133,33 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider {
            }
        });
        updateSessionInfosIfNeeded();
    }

    public void start() {
        IntentFilter intentFilter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
        intentFilter.addAction(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
        mContext.registerReceiverAsUser(new AudioManagerBroadcastReceiver(), user,
        mContext.registerReceiverAsUser(mAudioReceiver, mUser,
                intentFilter, null, null);

        if (mBtRouteProvider != null) {
            mHandler.post(() -> {
                mBtRouteProvider.start(user);
                mBtRouteProvider.start(mUser);
                notifyProviderState();
            });
        }
        updateVolume();
    }

    public void stop() {
        mContext.unregisterReceiver(mAudioReceiver);
        if (mBtRouteProvider != null) {
            mHandler.post(() -> {
                mBtRouteProvider.stop();
                notifyProviderState();
            });
        }
    }

    @Override
    public void setCallback(Callback callback) {
        super.setCallback(callback);
+20 −7
Original line number Diff line number Diff line
@@ -618,10 +618,17 @@ public class DataManager {
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
            intentFilter.addAction(SmsApplication.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);

            if (mBroadcastReceivers.get(userId) == null) {
                BroadcastReceiver broadcastReceiver = new PerUserBroadcastReceiver(userId);
                mBroadcastReceivers.put(userId, broadcastReceiver);
                mContext.registerReceiverAsUser(
                        broadcastReceiver, UserHandle.of(userId), intentFilter, null, null);
            } else {
                // Stopped was not called on this user before setup is called again. This
                // could happen during consecutive rapid user switching.
                if (DEBUG) Log.d(TAG, "PerUserBroadcastReceiver was registered for: " + userId);
            }

            ContentObserver contactsContentObserver = new ContactsContentObserver(
                    BackgroundThread.getHandler());
@@ -639,9 +646,15 @@ public class DataManager {
                // Should never occur for local calls.
            }

            if (mPackageMonitors.get(userId) == null) {
                PackageMonitor packageMonitor = new PerUserPackageMonitor();
                packageMonitor.register(mContext, null, UserHandle.of(userId), true);
                mPackageMonitors.put(userId, packageMonitor);
            } else {
                // Stopped was not called on this user before setup is called again. This
                // could happen during consecutive rapid user switching.
                if (DEBUG) Log.d(TAG, "PerUserPackageMonitor was registered for: " + userId);
            }

            if (userId == UserHandle.USER_SYSTEM) {
                // The call log and MMS/SMS messages are shared across user profiles. So only need