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

Commit ae80bb06 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Add synchronization to ttlhelper

Because the cancel calls can come from background threads

Test: TimeToLiveHelperTest
Fixes: 347509852
Flag: com.android.server.notification.all_notifs_need_ttl
Change-Id: I447699afa189a9c9dcd8bd476059a66886909cc7
parent 59fa4013
Loading
Loading
Loading
Loading
+40 −23
Original line number Original line Diff line number Diff line
@@ -54,13 +54,17 @@ public class TimeToLiveHelper {
    private final AlarmManager mAm;
    private final AlarmManager mAm;


    @VisibleForTesting
    @VisibleForTesting
    @GuardedBy("mLock")
    final TreeSet<Pair<Long, String>> mKeys;
    final TreeSet<Pair<Long, String>> mKeys;
    final Object mLock = new Object();


    public TimeToLiveHelper(NotificationManagerPrivate nm, Context context) {
    public TimeToLiveHelper(NotificationManagerPrivate nm, Context context) {
        mContext = context;
        mContext = context;
        mNm = nm;
        mNm = nm;
        mAm = context.getSystemService(AlarmManager.class);
        mAm = context.getSystemService(AlarmManager.class);
        synchronized (mLock) {
            mKeys = new TreeSet<>((left, right) -> Long.compare(left.first, right.first));
            mKeys = new TreeSet<>((left, right) -> Long.compare(left.first, right.first));
        }


        IntentFilter timeoutFilter = new IntentFilter(ACTION);
        IntentFilter timeoutFilter = new IntentFilter(ACTION);
        timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
        timeoutFilter.addDataScheme(SCHEME_TIMEOUT);
@@ -73,8 +77,10 @@ public class TimeToLiveHelper {
    }
    }


    void dump(PrintWriter pw, String indent) {
    void dump(PrintWriter pw, String indent) {
        synchronized (mLock) {
            pw.println(indent + "mKeys " + mKeys);
            pw.println(indent + "mKeys " + mKeys);
        }
        }
    }


    private @NonNull PendingIntent getAlarmPendingIntent(String nextKey, int flags) {
    private @NonNull PendingIntent getAlarmPendingIntent(String nextKey, int flags) {
        flags |= PendingIntent.FLAG_IMMUTABLE;
        flags |= PendingIntent.FLAG_IMMUTABLE;
@@ -93,6 +99,7 @@ public class TimeToLiveHelper {


    @VisibleForTesting
    @VisibleForTesting
    void scheduleTimeoutLocked(NotificationRecord record, long currentTime) {
    void scheduleTimeoutLocked(NotificationRecord record, long currentTime) {
        synchronized (mLock) {
            removeMatchingEntry(record.getKey());
            removeMatchingEntry(record.getKey());


            final long timeoutAfter = currentTime + record.getNotification().getTimeoutAfter();
            final long timeoutAfter = currentTime + record.getNotification().getTimeoutAfter();
@@ -111,12 +118,16 @@ public class TimeToLiveHelper {
                }
                }
            }
            }
        }
        }
    }


    @VisibleForTesting
    @VisibleForTesting
    void cancelScheduledTimeoutLocked(NotificationRecord record) {
    void cancelScheduledTimeoutLocked(NotificationRecord record) {
        synchronized (mLock) {
            removeMatchingEntry(record.getKey());
            removeMatchingEntry(record.getKey());
        }
        }
    }


    @GuardedBy("mLock")
    private void removeMatchingEntry(String key) {
    private void removeMatchingEntry(String key) {
        if (!mKeys.isEmpty() && key.equals(mKeys.first().second)) {
        if (!mKeys.isEmpty() && key.equals(mKeys.first().second)) {
            // cancel the first alarm, remove the first entry, maybe schedule the alarm for the new
            // cancel the first alarm, remove the first entry, maybe schedule the alarm for the new
@@ -139,11 +150,13 @@ public class TimeToLiveHelper {
        }
        }
    }
    }


    @GuardedBy("mLock")
    private void cancelFirstAlarm() {
    private void cancelFirstAlarm() {
        final PendingIntent pi = getAlarmPendingIntent(mKeys.first().second, FLAG_CANCEL_CURRENT);
        final PendingIntent pi = getAlarmPendingIntent(mKeys.first().second, FLAG_CANCEL_CURRENT);
        mAm.cancel(pi);
        mAm.cancel(pi);
    }
    }


    @GuardedBy("mLock")
    private void maybeScheduleFirstAlarm() {
    private void maybeScheduleFirstAlarm() {
        if (!mKeys.isEmpty()) {
        if (!mKeys.isEmpty()) {
            final PendingIntent piNewFirst = getAlarmPendingIntent(mKeys.first().second,
            final PendingIntent piNewFirst = getAlarmPendingIntent(mKeys.first().second,
@@ -162,13 +175,17 @@ public class TimeToLiveHelper {
                return;
                return;
            }
            }
            if (ACTION.equals(action)) {
            if (ACTION.equals(action)) {
                String timeoutKey = null;
                synchronized (mLock) {
                    Pair<Long, String> earliest = mKeys.first();
                    Pair<Long, String> earliest = mKeys.first();
                    String key = intent.getStringExtra(EXTRA_KEY);
                    String key = intent.getStringExtra(EXTRA_KEY);
                    if (!earliest.second.equals(key)) {
                    if (!earliest.second.equals(key)) {
                        Slog.wtf(TAG, "Alarm triggered but wasn't the earliest we were tracking");
                        Slog.wtf(TAG, "Alarm triggered but wasn't the earliest we were tracking");
                    }
                    }
                    removeMatchingEntry(key);
                    removeMatchingEntry(key);
                mNm.timeoutNotification(earliest.second);
                    timeoutKey = earliest.second;
                }
                mNm.timeoutNotification(timeoutKey);
            }
            }
        }
        }
    };
    };