• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.statusbar.notification.collection.notifcollection
18 
19 import android.os.RemoteException
20 import android.service.notification.NotificationListenerService
21 import android.service.notification.NotificationListenerService.RankingMap
22 import android.service.notification.StatusBarNotification
23 import com.android.systemui.log.dagger.NotificationLog
24 import com.android.systemui.log.LogBuffer
25 import com.android.systemui.log.core.LogLevel.DEBUG
26 import com.android.systemui.log.core.LogLevel.ERROR
27 import com.android.systemui.log.core.LogLevel.INFO
28 import com.android.systemui.log.core.LogLevel.WARNING
29 import com.android.systemui.log.core.LogLevel.WTF
30 import com.android.systemui.statusbar.notification.collection.GroupEntry
31 import com.android.systemui.statusbar.notification.collection.NotifCollection
32 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason
33 import com.android.systemui.statusbar.notification.collection.NotifCollection.FutureDismissal
34 import com.android.systemui.statusbar.notification.collection.NotificationEntry
35 import com.android.systemui.statusbar.notification.logKey
36 import javax.inject.Inject
37 
cancellationReasonDebugStringnull38 fun cancellationReasonDebugString(@CancellationReason reason: Int) =
39     "$reason:" + when (reason) {
40         -1 -> "REASON_NOT_CANCELED" // NotifCollection.REASON_NOT_CANCELED
41         NotifCollection.REASON_UNKNOWN -> "REASON_UNKNOWN"
42         NotificationListenerService.REASON_CLICK -> "REASON_CLICK"
43         NotificationListenerService.REASON_CANCEL -> "REASON_CANCEL"
44         NotificationListenerService.REASON_CANCEL_ALL -> "REASON_CANCEL_ALL"
45         NotificationListenerService.REASON_ERROR -> "REASON_ERROR"
46         NotificationListenerService.REASON_PACKAGE_CHANGED -> "REASON_PACKAGE_CHANGED"
47         NotificationListenerService.REASON_USER_STOPPED -> "REASON_USER_STOPPED"
48         NotificationListenerService.REASON_PACKAGE_BANNED -> "REASON_PACKAGE_BANNED"
49         NotificationListenerService.REASON_APP_CANCEL -> "REASON_APP_CANCEL"
50         NotificationListenerService.REASON_APP_CANCEL_ALL -> "REASON_APP_CANCEL_ALL"
51         NotificationListenerService.REASON_LISTENER_CANCEL -> "REASON_LISTENER_CANCEL"
52         NotificationListenerService.REASON_LISTENER_CANCEL_ALL -> "REASON_LISTENER_CANCEL_ALL"
53         NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED -> "REASON_GROUP_SUMMARY_CANCELED"
54         NotificationListenerService.REASON_GROUP_OPTIMIZATION -> "REASON_GROUP_OPTIMIZATION"
55         NotificationListenerService.REASON_PACKAGE_SUSPENDED -> "REASON_PACKAGE_SUSPENDED"
56         NotificationListenerService.REASON_PROFILE_TURNED_OFF -> "REASON_PROFILE_TURNED_OFF"
57         NotificationListenerService.REASON_UNAUTOBUNDLED -> "REASON_UNAUTOBUNDLED"
58         NotificationListenerService.REASON_CHANNEL_BANNED -> "REASON_CHANNEL_BANNED"
59         NotificationListenerService.REASON_SNOOZED -> "REASON_SNOOZED"
60         NotificationListenerService.REASON_TIMEOUT -> "REASON_TIMEOUT"
61         NotificationListenerService.REASON_CHANNEL_REMOVED -> "REASON_CHANNEL_REMOVED"
62         NotificationListenerService.REASON_CLEAR_DATA -> "REASON_CLEAR_DATA"
63         NotificationListenerService.REASON_ASSISTANT_CANCEL -> "REASON_ASSISTANT_CANCEL"
64         else -> "unknown"
65     }
66 
67 class NotifCollectionLogger @Inject constructor(
68     @NotificationLog private val buffer: LogBuffer
69 ) {
logNotifPostednull70     fun logNotifPosted(entry: NotificationEntry) {
71         buffer.log(TAG, INFO, {
72             str1 = entry.logKey
73         }, {
74             "POSTED $str1"
75         })
76     }
77 
logNotifGroupPostednull78     fun logNotifGroupPosted(groupKey: String, batchSize: Int) {
79         buffer.log(TAG, INFO, {
80             str1 = logKey(groupKey)
81             int1 = batchSize
82         }, {
83             "POSTED GROUP $str1 ($int1 events)"
84         })
85     }
86 
logNotifUpdatednull87     fun logNotifUpdated(entry: NotificationEntry) {
88         buffer.log(TAG, INFO, {
89             str1 = entry.logKey
90         }, {
91             "UPDATED $str1"
92         })
93     }
94 
logNotifRemovednull95     fun logNotifRemoved(sbn: StatusBarNotification, @CancellationReason reason: Int) {
96         buffer.log(TAG, INFO, {
97             str1 = sbn.logKey
98             int1 = reason
99         }, {
100             "REMOVED $str1 reason=${cancellationReasonDebugString(int1)}"
101         })
102     }
103 
logNotifReleasednull104     fun logNotifReleased(entry: NotificationEntry) {
105         buffer.log(TAG, INFO, {
106             str1 = entry.logKey
107         }, {
108             "RELEASED $str1"
109         })
110     }
111 
logLocallyDismissednull112     fun logLocallyDismissed(entry: NotificationEntry, index: Int, count: Int) {
113         buffer.log(TAG, INFO, {
114             str1 = entry.logKey
115             int1 = index
116             int2 = count
117         }, {
118             "LOCALLY DISMISSED $str1 ($int1/$int2)"
119         })
120     }
121 
logDismissNonExistentNotifnull122     fun logDismissNonExistentNotif(entryKey: String, index: Int, count: Int) {
123         buffer.log(TAG, INFO, {
124             str1 = logKey(entryKey)
125             int1 = index
126             int2 = count
127         }, {
128             "DISMISS Non Existent $str1 ($int1/$int2)"
129         })
130     }
131 
logLocallyDismissedChildnull132     fun logLocallyDismissedChild(
133             child: NotificationEntry,
134             parent: NotificationEntry,
135             parentIndex: Int,
136             parentCount: Int
137     ) {
138         buffer.log(TAG, DEBUG, {
139             str1 = child.logKey
140             str2 = parent.logKey
141             int1 = parentIndex
142             int2 = parentCount
143         }, {
144             "LOCALLY DISMISSED CHILD (inferred): $str1 of parent $str2 ($int1/$int2)"
145         })
146     }
147 
logDismissAllnull148     fun logDismissAll(userId: Int) {
149         buffer.log(TAG, INFO, {
150             int1 = userId
151         }, {
152             "DISMISS ALL notifications for user $int1"
153         })
154     }
155 
logLocallyDismissedAlreadyCanceledEntrynull156     fun logLocallyDismissedAlreadyCanceledEntry(entry: NotificationEntry) {
157         buffer.log(TAG, DEBUG, {
158             str1 = entry.logKey
159         }, {
160             "LOCALLY DISMISSED Already Canceled $str1. Trying to remove."
161         })
162     }
163 
logNotifDismissedInterceptednull164     fun logNotifDismissedIntercepted(entry: NotificationEntry, index: Int, count: Int) {
165         buffer.log(TAG, INFO, {
166             str1 = entry.logKey
167             int1 = index
168             int2 = count
169         }, {
170             "DISMISS INTERCEPTED $str1 ($int1/$int2)"
171         })
172     }
173 
logNotifClearAllDismissalInterceptednull174     fun logNotifClearAllDismissalIntercepted(entry: NotificationEntry, index: Int, count: Int) {
175         buffer.log(TAG, INFO, {
176             str1 = entry.logKey
177             int1 = index
178             int2 = count
179         }, {
180             "CLEAR ALL DISMISSAL INTERCEPTED $str1 ($int1/$int2)"
181         })
182     }
183 
logNotifInternalUpdatenull184     fun logNotifInternalUpdate(entry: NotificationEntry, name: String, reason: String) {
185         buffer.log(TAG, INFO, {
186             str1 = entry.logKey
187             str2 = name
188             str3 = reason
189         }, {
190             "UPDATED INTERNALLY $str1 BY $str2 BECAUSE $str3"
191         })
192     }
193 
logNotifInternalUpdateFailednull194     fun logNotifInternalUpdateFailed(sbn: StatusBarNotification, name: String, reason: String) {
195         buffer.log(TAG, INFO, {
196             str1 = sbn.logKey
197             str2 = name
198             str3 = reason
199         }, {
200             "FAILED INTERNAL UPDATE $str1 BY $str2 BECAUSE $str3"
201         })
202     }
203 
logNoNotificationToRemoveWithKeynull204     fun logNoNotificationToRemoveWithKey(
205         sbn: StatusBarNotification,
206         @CancellationReason reason: Int
207     ) {
208         buffer.log(TAG, ERROR, {
209             str1 = sbn.logKey
210             int1 = reason
211         }, {
212             "No notification to remove with key $str1 reason=${cancellationReasonDebugString(int1)}"
213         })
214     }
215 
logMissingRankingsnull216     fun logMissingRankings(
217         newlyInconsistentEntries: List<NotificationEntry>,
218         totalInconsistent: Int,
219         rankingMap: RankingMap
220     ) {
221         buffer.log(TAG, WARNING, {
222             int1 = totalInconsistent
223             int2 = newlyInconsistentEntries.size
224             str1 = newlyInconsistentEntries.joinToString { it.logKey ?: "null" }
225         }, {
226             "Ranking update is missing ranking for $int1 entries ($int2 new): $str1"
227         })
228         buffer.log(TAG, DEBUG, {
229             str1 = rankingMap.orderedKeys.map { logKey(it) ?: "null" }.toString()
230         }, {
231             "Ranking map contents: $str1"
232         })
233     }
234 
logRecoveredRankingsnull235     fun logRecoveredRankings(newlyConsistentKeys: List<String>, totalInconsistent: Int) {
236         buffer.log(TAG, INFO, {
237             int1 = totalInconsistent
238             int1 = newlyConsistentKeys.size
239             str1 = newlyConsistentKeys.joinToString { logKey(it) ?: "null" }
240         }, {
241             "Ranking update now contains rankings for $int1 previously inconsistent entries: $str1"
242         })
243     }
244 
logMissingNotificationsnull245     fun logMissingNotifications(
246         newlyMissingKeys: List<String>,
247         totalMissing: Int,
248     ) {
249         buffer.log(TAG, WARNING, {
250             int1 = totalMissing
251             int2 = newlyMissingKeys.size
252             str1 = newlyMissingKeys.joinToString { logKey(it) ?: "null" }
253         }, {
254             "Collection missing $int1 entries in ranking update. Just lost $int2: $str1"
255         })
256     }
257 
logFoundNotificationsnull258     fun logFoundNotifications(
259         newlyFoundKeys: List<String>,
260         totalMissing: Int,
261     ) {
262         buffer.log(TAG, INFO, {
263             int1 = totalMissing
264             int2 = newlyFoundKeys.size
265             str1 = newlyFoundKeys.joinToString { logKey(it) ?: "null" }
266         }, {
267             "Collection missing $int1 entries in ranking update. Just found $int2: $str1"
268         })
269     }
270 
logRemoteExceptionOnNotificationClearnull271     fun logRemoteExceptionOnNotificationClear(
272             entry: NotificationEntry,
273             index: Int,
274             count: Int,
275             e: RemoteException
276     ) {
277         buffer.log(TAG, WTF, {
278             str1 = entry.logKey
279             int1 = index
280             int2 = count
281             str2 = e.toString()
282         }, {
283             "RemoteException while attempting to clear $str1 ($int1/$int2):\n$str2"
284         })
285     }
286 
logRemoteExceptionOnClearAllNotificationsnull287     fun logRemoteExceptionOnClearAllNotifications(e: RemoteException) {
288         buffer.log(TAG, WTF, {
289             str1 = e.toString()
290         }, {
291             "RemoteException while attempting to clear all notifications:\n$str1"
292         })
293     }
294 
logLifetimeExtendednull295     fun logLifetimeExtended(entry: NotificationEntry, extender: NotifLifetimeExtender) {
296         buffer.log(TAG, INFO, {
297             str1 = entry.logKey
298             str2 = extender.name
299         }, {
300             "LIFETIME EXTENDED: $str1 by $str2"
301         })
302     }
303 
logLifetimeExtensionEndednull304     fun logLifetimeExtensionEnded(
305         entry: NotificationEntry,
306         extender: NotifLifetimeExtender,
307         totalExtenders: Int
308     ) {
309         buffer.log(TAG, INFO, {
310             str1 = entry.logKey
311             str2 = extender.name
312             int1 = totalExtenders
313         }, {
314             "LIFETIME EXTENSION ENDED for $str1 by '$str2'; $int1 remaining extensions"
315         })
316     }
317 
logIgnoredErrornull318     fun logIgnoredError(message: String?) {
319         buffer.log(TAG, ERROR, {
320             str1 = message
321         }, {
322             "ERROR suppressed due to initialization forgiveness: $str1"
323         })
324     }
325 
logEntryBeingExtendedNotInCollectionnull326     fun logEntryBeingExtendedNotInCollection(
327         entry: NotificationEntry,
328         extender: NotifLifetimeExtender,
329         collectionEntryIs: String
330     ) {
331         buffer.log(TAG, WARNING, {
332             str1 = entry.logKey
333             str2 = extender.name
334             str3 = collectionEntryIs
335         }, {
336             "While ending lifetime extension by $str2 of $str1, entry in collection is $str3"
337         })
338     }
339 
logFutureDismissalReusednull340     fun logFutureDismissalReused(dismissal: FutureDismissal) {
341         buffer.log(TAG, INFO, {
342             str1 = dismissal.label
343         }, {
344             "Reusing existing registration: $str1"
345         })
346     }
347 
logFutureDismissalRegisterednull348     fun logFutureDismissalRegistered(dismissal: FutureDismissal) {
349         buffer.log(TAG, DEBUG, {
350             str1 = dismissal.label
351         }, {
352             "Registered: $str1"
353         })
354     }
355 
logFutureDismissalDoubleCancelledByServernull356     fun logFutureDismissalDoubleCancelledByServer(dismissal: FutureDismissal) {
357         buffer.log(TAG, WARNING, {
358             str1 = dismissal.label
359         }, {
360             "System server double cancelled: $str1"
361         })
362     }
363 
logFutureDismissalDoubleRunnull364     fun logFutureDismissalDoubleRun(dismissal: FutureDismissal) {
365         buffer.log(TAG, WARNING, {
366             str1 = dismissal.label
367         }, {
368             "Double run: $str1"
369         })
370     }
371 
logFutureDismissalAlreadyCancelledByServernull372     fun logFutureDismissalAlreadyCancelledByServer(dismissal: FutureDismissal) {
373         buffer.log(TAG, DEBUG, {
374             str1 = dismissal.label
375         }, {
376             "Ignoring: entry already cancelled by server: $str1"
377         })
378     }
379 
logFutureDismissalGotSystemServerCancelnull380     fun logFutureDismissalGotSystemServerCancel(
381         dismissal: FutureDismissal,
382         @CancellationReason cancellationReason: Int
383     ) {
384         buffer.log(TAG, DEBUG, {
385             str1 = dismissal.label
386             int1 = cancellationReason
387         }, {
388             "SystemServer cancelled: $str1 reason=${cancellationReasonDebugString(int1)}"
389         })
390     }
391 
logFutureDismissalDismissingnull392     fun logFutureDismissalDismissing(dismissal: FutureDismissal, type: String) {
393         buffer.log(TAG, DEBUG, {
394             str1 = dismissal.label
395             str2 = type
396         }, {
397             "Dismissing $str2 for: $str1"
398         })
399     }
400 
logFutureDismissalMismatchedEntrynull401     fun logFutureDismissalMismatchedEntry(
402         dismissal: FutureDismissal,
403         type: String,
404         latestEntry: NotificationEntry?
405     ) {
406         buffer.log(TAG, WARNING, {
407             str1 = dismissal.label
408             str2 = type
409             str3 = latestEntry.logKey
410         }, {
411             "Mismatch: current $str2 is $str3 for: $str1"
412         })
413     }
414 
logDismissAlreadyDismissedNotifnull415     fun logDismissAlreadyDismissedNotif(entry: NotificationEntry, index: Int, count: Int) {
416         buffer.log(TAG, DEBUG, {
417             str1 = entry.logKey
418             int1 = index
419             int2 = count
420         }, {
421             "DISMISS Already Dismissed $str1 ($int1/$int2)"
422         })
423     }
424 
getParentLogKeynull425     private fun getParentLogKey(childEntry: NotificationEntry): String {
426         return if (childEntry.parent is GroupEntry) {
427             (childEntry.parent as? GroupEntry)?.summary?.logKey ?: "(null)"
428         } else {
429             "(null)"
430         }
431     }
432 
logDismissAlreadyParentDismissedNotifnull433     fun logDismissAlreadyParentDismissedNotif(
434             childEntry: NotificationEntry,
435             childIndex: Int,
436             childCount: Int
437     ) {
438         buffer.log(TAG, DEBUG, {
439             str1 = childEntry.logKey
440             int1 = childIndex
441             int2 = childCount
442             str2 = getParentLogKey(childEntry)
443         }, {
444             "DISMISS Already Parent-Dismissed $str1 ($int1/$int2) with summary $str2"
445         })
446     }
447 
logLocallyDismissNonExistentNotifnull448     fun logLocallyDismissNonExistentNotif(entry: NotificationEntry, index: Int, count: Int) {
449         buffer.log(TAG, INFO, {
450             str1 = entry.logKey
451             int1 = index
452             int2 = count
453         }, {
454             "LOCALLY DISMISS Non Existent $str1 ($int1/$int2)"
455         })
456     }
457 
logLocallyDismissMismatchedEntrynull458     fun logLocallyDismissMismatchedEntry(
459             entry: NotificationEntry,
460             index: Int,
461             count: Int,
462             storedEntry: NotificationEntry
463     ) {
464         buffer.log(TAG, INFO, {
465             str1 = entry.logKey
466             int1 = index
467             int2 = count
468             str2 = Integer.toHexString(entry.hashCode())
469             str3 = Integer.toHexString(storedEntry.hashCode())
470         }, {
471             "LOCALLY DISMISS Mismatch $str1 ($int1/$int2): dismissing @$str2 but stored @$str3"
472         })
473     }
474 
logLocallyDismissAlreadyDismissedNotifnull475     fun logLocallyDismissAlreadyDismissedNotif(
476             entry: NotificationEntry,
477             index: Int,
478             count: Int
479     ) {
480         buffer.log(TAG, INFO, {
481             str1 = entry.logKey
482             int1 = index
483             int2 = count
484         }, {
485             "LOCALLY DISMISS Already Dismissed $str1 ($int1/$int2)"
486         })
487     }
488 
logLocallyDismissAlreadyParentDismissedNotifnull489     fun logLocallyDismissAlreadyParentDismissedNotif(
490             entry: NotificationEntry,
491             index: Int,
492             count: Int
493     ) {
494         buffer.log(TAG, INFO, {
495             str1 = entry.logKey
496             int1 = index
497             int2 = count
498         }, {
499             "LOCALLY DISMISS Already Dismissed $str1 ($int1/$int2)"
500         })
501     }
502 
logLocallyDismissAlreadyDismissedChildnull503     fun logLocallyDismissAlreadyDismissedChild(
504             childEntry: NotificationEntry,
505             parentEntry: NotificationEntry,
506             parentIndex: Int,
507             parentCount: Int
508     ) {
509         buffer.log(TAG, INFO, {
510             str1 = childEntry.logKey
511             str2 = parentEntry.logKey
512             int1 = parentIndex
513             int2 = parentCount
514         }, {
515             "LOCALLY DISMISS Already Dismissed Child $str1 of parent $str2 ($int1/$int2)"
516         })
517     }
518 
logLocallyDismissAlreadyParentDismissedChildnull519     fun logLocallyDismissAlreadyParentDismissedChild(
520             childEntry: NotificationEntry,
521             parentEntry: NotificationEntry,
522             parentIndex: Int,
523             parentCount: Int
524     ) {
525         buffer.log(TAG, INFO, {
526             str1 = childEntry.logKey
527             str2 = parentEntry.logKey
528             int1 = parentIndex
529             int2 = parentCount
530         }, {
531             "LOCALLY DISMISS Already Parent-Dismissed Child $str1 of parent $str2 ($int1/$int2)"
532         })
533     }
534 
logCancelLocalDismissalNotDismissedNotifnull535     fun logCancelLocalDismissalNotDismissedNotif(entry: NotificationEntry) {
536         buffer.log(TAG, INFO, {
537             str1 = entry.logKey
538         }, {
539             "CANCEL LOCAL DISMISS Not Dismissed $str1"
540         })
541     }
542 }
543 
544 private const val TAG = "NotifCollection"
545