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