• 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.plugins.log.LogBuffer
25 import com.android.systemui.plugins.log.LogLevel.DEBUG
26 import com.android.systemui.plugins.log.LogLevel.ERROR
27 import com.android.systemui.plugins.log.LogLevel.INFO
28 import com.android.systemui.plugins.log.LogLevel.WARNING
29 import com.android.systemui.plugins.log.LogLevel.WTF
30 import com.android.systemui.statusbar.notification.collection.NotifCollection
31 import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason
32 import com.android.systemui.statusbar.notification.collection.NotifCollection.FutureDismissal
33 import com.android.systemui.statusbar.notification.collection.NotificationEntry
34 import com.android.systemui.statusbar.notification.logKey
35 import javax.inject.Inject
36 
cancellationReasonDebugStringnull37 fun cancellationReasonDebugString(@CancellationReason reason: Int) =
38     "$reason:" + when (reason) {
39         -1 -> "REASON_NOT_CANCELED" // NotifCollection.REASON_NOT_CANCELED
40         NotifCollection.REASON_UNKNOWN -> "REASON_UNKNOWN"
41         NotificationListenerService.REASON_CLICK -> "REASON_CLICK"
42         NotificationListenerService.REASON_CANCEL -> "REASON_CANCEL"
43         NotificationListenerService.REASON_CANCEL_ALL -> "REASON_CANCEL_ALL"
44         NotificationListenerService.REASON_ERROR -> "REASON_ERROR"
45         NotificationListenerService.REASON_PACKAGE_CHANGED -> "REASON_PACKAGE_CHANGED"
46         NotificationListenerService.REASON_USER_STOPPED -> "REASON_USER_STOPPED"
47         NotificationListenerService.REASON_PACKAGE_BANNED -> "REASON_PACKAGE_BANNED"
48         NotificationListenerService.REASON_APP_CANCEL -> "REASON_APP_CANCEL"
49         NotificationListenerService.REASON_APP_CANCEL_ALL -> "REASON_APP_CANCEL_ALL"
50         NotificationListenerService.REASON_LISTENER_CANCEL -> "REASON_LISTENER_CANCEL"
51         NotificationListenerService.REASON_LISTENER_CANCEL_ALL -> "REASON_LISTENER_CANCEL_ALL"
52         NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED -> "REASON_GROUP_SUMMARY_CANCELED"
53         NotificationListenerService.REASON_GROUP_OPTIMIZATION -> "REASON_GROUP_OPTIMIZATION"
54         NotificationListenerService.REASON_PACKAGE_SUSPENDED -> "REASON_PACKAGE_SUSPENDED"
55         NotificationListenerService.REASON_PROFILE_TURNED_OFF -> "REASON_PROFILE_TURNED_OFF"
56         NotificationListenerService.REASON_UNAUTOBUNDLED -> "REASON_UNAUTOBUNDLED"
57         NotificationListenerService.REASON_CHANNEL_BANNED -> "REASON_CHANNEL_BANNED"
58         NotificationListenerService.REASON_SNOOZED -> "REASON_SNOOZED"
59         NotificationListenerService.REASON_TIMEOUT -> "REASON_TIMEOUT"
60         NotificationListenerService.REASON_CHANNEL_REMOVED -> "REASON_CHANNEL_REMOVED"
61         NotificationListenerService.REASON_CLEAR_DATA -> "REASON_CLEAR_DATA"
62         NotificationListenerService.REASON_ASSISTANT_CANCEL -> "REASON_ASSISTANT_CANCEL"
63         else -> "unknown"
64     }
65 
66 class NotifCollectionLogger @Inject constructor(
67     @NotificationLog private val buffer: LogBuffer
68 ) {
logNotifPostednull69     fun logNotifPosted(entry: NotificationEntry) {
70         buffer.log(TAG, INFO, {
71             str1 = entry.logKey
72         }, {
73             "POSTED $str1"
74         })
75     }
76 
logNotifGroupPostednull77     fun logNotifGroupPosted(groupKey: String, batchSize: Int) {
78         buffer.log(TAG, INFO, {
79             str1 = logKey(groupKey)
80             int1 = batchSize
81         }, {
82             "POSTED GROUP $str1 ($int1 events)"
83         })
84     }
85 
logNotifUpdatednull86     fun logNotifUpdated(entry: NotificationEntry) {
87         buffer.log(TAG, INFO, {
88             str1 = entry.logKey
89         }, {
90             "UPDATED $str1"
91         })
92     }
93 
logNotifRemovednull94     fun logNotifRemoved(sbn: StatusBarNotification, @CancellationReason reason: Int) {
95         buffer.log(TAG, INFO, {
96             str1 = sbn.logKey
97             int1 = reason
98         }, {
99             "REMOVED $str1 reason=${cancellationReasonDebugString(int1)}"
100         })
101     }
102 
logNotifReleasednull103     fun logNotifReleased(entry: NotificationEntry) {
104         buffer.log(TAG, INFO, {
105             str1 = entry.logKey
106         }, {
107             "RELEASED $str1"
108         })
109     }
110 
logNotifDismissednull111     fun logNotifDismissed(entry: NotificationEntry) {
112         buffer.log(TAG, INFO, {
113             str1 = entry.logKey
114         }, {
115             "DISMISSED $str1"
116         })
117     }
118 
logNonExistentNotifDismissednull119     fun logNonExistentNotifDismissed(entry: NotificationEntry) {
120         buffer.log(TAG, INFO, {
121             str1 = entry.logKey
122         }, {
123             "DISMISSED Non Existent $str1"
124         })
125     }
126 
logChildDismissednull127     fun logChildDismissed(entry: NotificationEntry) {
128         buffer.log(TAG, DEBUG, {
129             str1 = entry.logKey
130         }, {
131             "CHILD DISMISSED (inferred): $str1"
132         })
133     }
134 
logDismissAllnull135     fun logDismissAll(userId: Int) {
136         buffer.log(TAG, INFO, {
137             int1 = userId
138         }, {
139             "DISMISS ALL notifications for user $int1"
140         })
141     }
142 
logDismissOnAlreadyCanceledEntrynull143     fun logDismissOnAlreadyCanceledEntry(entry: NotificationEntry) {
144         buffer.log(TAG, DEBUG, {
145             str1 = entry.logKey
146         }, {
147             "Dismiss on $str1, which was already canceled. Trying to remove..."
148         })
149     }
150 
logNotifDismissedInterceptednull151     fun logNotifDismissedIntercepted(entry: NotificationEntry) {
152         buffer.log(TAG, INFO, {
153             str1 = entry.logKey
154         }, {
155             "DISMISS INTERCEPTED $str1"
156         })
157     }
158 
logNotifClearAllDismissalInterceptednull159     fun logNotifClearAllDismissalIntercepted(entry: NotificationEntry) {
160         buffer.log(TAG, INFO, {
161             str1 = entry.logKey
162         }, {
163             "CLEAR ALL DISMISSAL INTERCEPTED $str1"
164         })
165     }
166 
logNotifInternalUpdatenull167     fun logNotifInternalUpdate(entry: NotificationEntry, name: String, reason: String) {
168         buffer.log(TAG, INFO, {
169             str1 = entry.logKey
170             str2 = name
171             str3 = reason
172         }, {
173             "UPDATED INTERNALLY $str1 BY $str2 BECAUSE $str3"
174         })
175     }
176 
logNotifInternalUpdateFailednull177     fun logNotifInternalUpdateFailed(sbn: StatusBarNotification, name: String, reason: String) {
178         buffer.log(TAG, INFO, {
179             str1 = sbn.logKey
180             str2 = name
181             str3 = reason
182         }, {
183             "FAILED INTERNAL UPDATE $str1 BY $str2 BECAUSE $str3"
184         })
185     }
186 
logNoNotificationToRemoveWithKeynull187     fun logNoNotificationToRemoveWithKey(
188         sbn: StatusBarNotification,
189         @CancellationReason reason: Int
190     ) {
191         buffer.log(TAG, ERROR, {
192             str1 = sbn.logKey
193             int1 = reason
194         }, {
195             "No notification to remove with key $str1 reason=${cancellationReasonDebugString(int1)}"
196         })
197     }
198 
logMissingRankingsnull199     fun logMissingRankings(
200         newlyInconsistentEntries: List<NotificationEntry>,
201         totalInconsistent: Int,
202         rankingMap: RankingMap
203     ) {
204         buffer.log(TAG, WARNING, {
205             int1 = totalInconsistent
206             int2 = newlyInconsistentEntries.size
207             str1 = newlyInconsistentEntries.joinToString { it.logKey ?: "null" }
208         }, {
209             "Ranking update is missing ranking for $int1 entries ($int2 new): $str1"
210         })
211         buffer.log(TAG, DEBUG, {
212             str1 = rankingMap.orderedKeys.map { logKey(it) ?: "null" }.toString()
213         }, {
214             "Ranking map contents: $str1"
215         })
216     }
217 
logRecoveredRankingsnull218     fun logRecoveredRankings(newlyConsistentKeys: List<String>, totalInconsistent: Int) {
219         buffer.log(TAG, INFO, {
220             int1 = totalInconsistent
221             int1 = newlyConsistentKeys.size
222             str1 = newlyConsistentKeys.joinToString { logKey(it) ?: "null" }
223         }, {
224             "Ranking update now contains rankings for $int1 previously inconsistent entries: $str1"
225         })
226     }
227 
logMissingNotificationsnull228     fun logMissingNotifications(
229         newlyMissingKeys: List<String>,
230         totalMissing: Int,
231     ) {
232         buffer.log(TAG, WARNING, {
233             int1 = totalMissing
234             int2 = newlyMissingKeys.size
235             str1 = newlyMissingKeys.joinToString { logKey(it) ?: "null" }
236         }, {
237             "Collection missing $int1 entries in ranking update. Just lost $int2: $str1"
238         })
239     }
240 
logFoundNotificationsnull241     fun logFoundNotifications(
242         newlyFoundKeys: List<String>,
243         totalMissing: Int,
244     ) {
245         buffer.log(TAG, INFO, {
246             int1 = totalMissing
247             int2 = newlyFoundKeys.size
248             str1 = newlyFoundKeys.joinToString { logKey(it) ?: "null" }
249         }, {
250             "Collection missing $int1 entries in ranking update. Just found $int2: $str1"
251         })
252     }
253 
logRemoteExceptionOnNotificationClearnull254     fun logRemoteExceptionOnNotificationClear(entry: NotificationEntry, e: RemoteException) {
255         buffer.log(TAG, WTF, {
256             str1 = entry.logKey
257             str2 = e.toString()
258         }, {
259             "RemoteException while attempting to clear $str1:\n$str2"
260         })
261     }
262 
logRemoteExceptionOnClearAllNotificationsnull263     fun logRemoteExceptionOnClearAllNotifications(e: RemoteException) {
264         buffer.log(TAG, WTF, {
265             str1 = e.toString()
266         }, {
267             "RemoteException while attempting to clear all notifications:\n$str1"
268         })
269     }
270 
logLifetimeExtendednull271     fun logLifetimeExtended(entry: NotificationEntry, extender: NotifLifetimeExtender) {
272         buffer.log(TAG, INFO, {
273             str1 = entry.logKey
274             str2 = extender.name
275         }, {
276             "LIFETIME EXTENDED: $str1 by $str2"
277         })
278     }
279 
logLifetimeExtensionEndednull280     fun logLifetimeExtensionEnded(
281         entry: NotificationEntry,
282         extender: NotifLifetimeExtender,
283         totalExtenders: Int
284     ) {
285         buffer.log(TAG, INFO, {
286             str1 = entry.logKey
287             str2 = extender.name
288             int1 = totalExtenders
289         }, {
290             "LIFETIME EXTENSION ENDED for $str1 by '$str2'; $int1 remaining extensions"
291         })
292     }
293 
logIgnoredErrornull294     fun logIgnoredError(message: String?) {
295         buffer.log(TAG, ERROR, {
296             str1 = message
297         }, {
298             "ERROR suppressed due to initialization forgiveness: $str1"
299         })
300     }
301 
logEntryBeingExtendedNotInCollectionnull302     fun logEntryBeingExtendedNotInCollection(
303         entry: NotificationEntry,
304         extender: NotifLifetimeExtender,
305         collectionEntryIs: String
306     ) {
307         buffer.log(TAG, WARNING, {
308             str1 = entry.logKey
309             str2 = extender.name
310             str3 = collectionEntryIs
311         }, {
312             "While ending lifetime extension by $str2 of $str1, entry in collection is $str3"
313         })
314     }
315 
logFutureDismissalReusednull316     fun logFutureDismissalReused(dismissal: FutureDismissal) {
317         buffer.log(TAG, INFO, {
318             str1 = dismissal.label
319         }, {
320             "Reusing existing registration: $str1"
321         })
322     }
323 
logFutureDismissalRegisterednull324     fun logFutureDismissalRegistered(dismissal: FutureDismissal) {
325         buffer.log(TAG, DEBUG, {
326             str1 = dismissal.label
327         }, {
328             "Registered: $str1"
329         })
330     }
331 
logFutureDismissalDoubleCancelledByServernull332     fun logFutureDismissalDoubleCancelledByServer(dismissal: FutureDismissal) {
333         buffer.log(TAG, WARNING, {
334             str1 = dismissal.label
335         }, {
336             "System server double cancelled: $str1"
337         })
338     }
339 
logFutureDismissalDoubleRunnull340     fun logFutureDismissalDoubleRun(dismissal: FutureDismissal) {
341         buffer.log(TAG, WARNING, {
342             str1 = dismissal.label
343         }, {
344             "Double run: $str1"
345         })
346     }
347 
logFutureDismissalAlreadyCancelledByServernull348     fun logFutureDismissalAlreadyCancelledByServer(dismissal: FutureDismissal) {
349         buffer.log(TAG, DEBUG, {
350             str1 = dismissal.label
351         }, {
352             "Ignoring: entry already cancelled by server: $str1"
353         })
354     }
355 
logFutureDismissalGotSystemServerCancelnull356     fun logFutureDismissalGotSystemServerCancel(
357         dismissal: FutureDismissal,
358         @CancellationReason cancellationReason: Int
359     ) {
360         buffer.log(TAG, DEBUG, {
361             str1 = dismissal.label
362             int1 = cancellationReason
363         }, {
364             "SystemServer cancelled: $str1 reason=${cancellationReasonDebugString(int1)}"
365         })
366     }
367 
logFutureDismissalDismissingnull368     fun logFutureDismissalDismissing(dismissal: FutureDismissal, type: String) {
369         buffer.log(TAG, DEBUG, {
370             str1 = dismissal.label
371             str2 = type
372         }, {
373             "Dismissing $str2 for: $str1"
374         })
375     }
376 
logFutureDismissalMismatchedEntrynull377     fun logFutureDismissalMismatchedEntry(
378         dismissal: FutureDismissal,
379         type: String,
380         latestEntry: NotificationEntry?
381     ) {
382         buffer.log(TAG, WARNING, {
383             str1 = dismissal.label
384             str2 = type
385             str3 = latestEntry.logKey
386         }, {
387             "Mismatch: current $str2 is $str3 for: $str1"
388         })
389     }
390 }
391 
392 private const val TAG = "NotifCollection"
393