1 /*
2  * Copyright (C) 2023 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.server.net;
18 
19 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.util.IndentingPrintWriter;
24 import android.util.LocalLog;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 
28 import java.lang.annotation.Retention;
29 import java.lang.annotation.RetentionPolicy;
30 
31 /**
32  * Helper class for NetworkStatsService to log events.
33  *
34  * @hide
35  */
36 public class NetworkStatsEventLogger {
37     static final int POLL_REASON_DUMPSYS = 0;
38     static final int POLL_REASON_FORCE_UPDATE = 1;
39     static final int POLL_REASON_GLOBAL_ALERT = 2;
40     static final int POLL_REASON_NETWORK_STATUS_CHANGED = 3;
41     static final int POLL_REASON_OPEN_SESSION = 4;
42     static final int POLL_REASON_PERIODIC = 5;
43     static final int POLL_REASON_RAT_CHANGED = 6;
44     static final int POLL_REASON_REG_CALLBACK = 7;
45     static final int POLL_REASON_REMOVE_UIDS = 8;
46     static final int POLL_REASON_UPSTREAM_CHANGED = 9;
47 
48     @Retention(RetentionPolicy.SOURCE)
49     @IntDef(prefix = { "POLL_REASON_" }, value = {
50             POLL_REASON_DUMPSYS,
51             POLL_REASON_FORCE_UPDATE,
52             POLL_REASON_GLOBAL_ALERT,
53             POLL_REASON_NETWORK_STATUS_CHANGED,
54             POLL_REASON_OPEN_SESSION,
55             POLL_REASON_PERIODIC,
56             POLL_REASON_RAT_CHANGED,
57             POLL_REASON_REMOVE_UIDS,
58             POLL_REASON_REG_CALLBACK,
59             POLL_REASON_UPSTREAM_CHANGED
60     })
61     public @interface PollReason {
62     }
63     static final int MAX_POLL_REASON = POLL_REASON_UPSTREAM_CHANGED;
64 
65     @VisibleForTesting(visibility = PRIVATE)
66     public static final int MAX_EVENTS_LOGS = 50;
67     private final LocalLog mEventChanges = new LocalLog(MAX_EVENTS_LOGS);
68     private final int[] mPollEventCounts = new int[MAX_POLL_REASON + 1];
69 
70     /**
71      * Log a poll event.
72      *
73      * @param flags Flags used when polling. See NetworkStatsService#FLAG_PERSIST_*.
74      * @param event The event of polling to be logged.
75      */
logPollEvent(int flags, @NonNull PollEvent event)76     public void logPollEvent(int flags, @NonNull PollEvent event) {
77         mEventChanges.log("Poll(flags=" + flags + ", " + event + ")");
78         mPollEventCounts[event.reason]++;
79     }
80 
81     /**
82      * Print poll counts per reason into the given stream.
83      */
84     @VisibleForTesting(visibility = PRIVATE)
dumpPollCountsPerReason(@onNull IndentingPrintWriter pw)85     public void dumpPollCountsPerReason(@NonNull IndentingPrintWriter pw) {
86         pw.println("Poll counts per reason:");
87         pw.increaseIndent();
88         for (int i = 0; i <= MAX_POLL_REASON; i++) {
89             pw.println(PollEvent.pollReasonNameOf(i) + ": " + mPollEventCounts[i]);
90         }
91         pw.decreaseIndent();
92         pw.println();
93     }
94 
95     /**
96      * Print recent poll events into the given stream.
97      */
98     @VisibleForTesting(visibility = PRIVATE)
dumpRecentPollEvents(@onNull IndentingPrintWriter pw)99     public void dumpRecentPollEvents(@NonNull IndentingPrintWriter pw) {
100         pw.println("Recent poll events:");
101         pw.increaseIndent();
102         mEventChanges.reverseDump(pw);
103         pw.decreaseIndent();
104         pw.println();
105     }
106 
107     /**
108      * Print the object's state into the given stream.
109      */
dump(@onNull IndentingPrintWriter pw)110     public void dump(@NonNull IndentingPrintWriter pw) {
111         dumpPollCountsPerReason(pw);
112         dumpRecentPollEvents(pw);
113     }
114 
115     public static class PollEvent {
116         public final int reason;
117 
PollEvent(@ollReason int reason)118         public PollEvent(@PollReason int reason) {
119             if (reason < 0 || reason > MAX_POLL_REASON) {
120                 throw new IllegalArgumentException("Unsupported poll reason: " + reason);
121             }
122             this.reason = reason;
123         }
124 
125         @Override
toString()126         public String toString() {
127             return "PollEvent{" + "reason=" + pollReasonNameOf(reason) + "}";
128         }
129 
130         /**
131          * Get the name of the given reason.
132          *
133          * If the reason does not have a String representation, returns its integer representation.
134          */
135         @NonNull
pollReasonNameOf(@ollReason int reason)136         public static String pollReasonNameOf(@PollReason int reason) {
137             switch (reason) {
138                 case POLL_REASON_DUMPSYS:                   return "DUMPSYS";
139                 case POLL_REASON_FORCE_UPDATE:              return "FORCE_UPDATE";
140                 case POLL_REASON_GLOBAL_ALERT:              return "GLOBAL_ALERT";
141                 case POLL_REASON_NETWORK_STATUS_CHANGED:    return "NETWORK_STATUS_CHANGED";
142                 case POLL_REASON_OPEN_SESSION:              return "OPEN_SESSION";
143                 case POLL_REASON_PERIODIC:                  return "PERIODIC";
144                 case POLL_REASON_RAT_CHANGED:               return "RAT_CHANGED";
145                 case POLL_REASON_REMOVE_UIDS:               return "REMOVE_UIDS";
146                 case POLL_REASON_REG_CALLBACK:              return "REG_CALLBACK";
147                 case POLL_REASON_UPSTREAM_CHANGED:          return "UPSTREAM_CHANGED";
148                 default:                                    return Integer.toString(reason);
149             }
150         }
151     }
152 }
153