1 /* 2 * Copyright (C) 2006 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 android.util; 18 19 import android.compat.annotation.UnsupportedAppUsage; 20 import android.os.Build; 21 import android.os.SystemClock; 22 23 import java.io.FileDescriptor; 24 import java.io.PrintWriter; 25 import java.time.Duration; 26 import java.time.Instant; 27 import java.time.LocalDateTime; 28 import java.util.ArrayDeque; 29 import java.util.Deque; 30 import java.util.Iterator; 31 32 /** 33 * @hide 34 */ 35 // Exported to Mainline modules; cannot use annotations 36 // @android.ravenwood.annotation.RavenwoodKeepWholeClass 37 public final class LocalLog { 38 39 private final Deque<String> mLog; 40 private final int mMaxLines; 41 42 /** 43 * {@code true} to use log timestamps expressed in local date/time, {@code false} to use log 44 * timestamped expressed with the elapsed realtime clock and UTC system clock. {@code false} is 45 * useful when logging behavior that modifies device time zone or system clock. 46 */ 47 private final boolean mUseLocalTimestamps; 48 49 @UnsupportedAppUsage LocalLog(int maxLines)50 public LocalLog(int maxLines) { 51 this(maxLines, true /* useLocalTimestamps */); 52 } 53 LocalLog(int maxLines, boolean useLocalTimestamps)54 public LocalLog(int maxLines, boolean useLocalTimestamps) { 55 mMaxLines = Math.max(0, maxLines); 56 mLog = new ArrayDeque<>(mMaxLines); 57 mUseLocalTimestamps = useLocalTimestamps; 58 } 59 60 @UnsupportedAppUsage log(String msg)61 public void log(String msg) { 62 if (mMaxLines <= 0) { 63 return; 64 } 65 final String logLine; 66 if (mUseLocalTimestamps) { 67 logLine = LocalDateTime.now() + " - " + msg; 68 } else { 69 logLine = Duration.ofMillis(SystemClock.elapsedRealtime()) 70 + " / " + Instant.now() + " - " + msg; 71 } 72 append(logLine); 73 } 74 append(String logLine)75 private synchronized void append(String logLine) { 76 while (mLog.size() >= mMaxLines) { 77 mLog.remove(); 78 } 79 mLog.add(logLine); 80 } 81 82 @UnsupportedAppUsage dump(FileDescriptor fd, PrintWriter pw, String[] args)83 public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 84 dump(pw); 85 } 86 dump(PrintWriter pw)87 public synchronized void dump(PrintWriter pw) { 88 dump("", pw); 89 } 90 91 /** 92 * Dumps the content of local log to print writer with each log entry predeced with indent 93 * 94 * @param indent indent that precedes each log entry 95 * @param pw printer writer to write into 96 */ dump(String indent, PrintWriter pw)97 public synchronized void dump(String indent, PrintWriter pw) { 98 Iterator<String> itr = mLog.iterator(); 99 while (itr.hasNext()) { 100 pw.printf("%s%s\n", indent, itr.next()); 101 } 102 } 103 reverseDump(FileDescriptor fd, PrintWriter pw, String[] args)104 public synchronized void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) { 105 reverseDump(pw); 106 } 107 reverseDump(PrintWriter pw)108 public synchronized void reverseDump(PrintWriter pw) { 109 Iterator<String> itr = mLog.descendingIterator(); 110 while (itr.hasNext()) { 111 pw.println(itr.next()); 112 } 113 } 114 115 public static class ReadOnlyLocalLog { 116 private final LocalLog mLog; ReadOnlyLocalLog(LocalLog log)117 ReadOnlyLocalLog(LocalLog log) { 118 mLog = log; 119 } 120 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dump(FileDescriptor fd, PrintWriter pw, String[] args)121 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 122 mLog.dump(pw); 123 } dump(PrintWriter pw)124 public void dump(PrintWriter pw) { 125 mLog.dump(pw); 126 } reverseDump(FileDescriptor fd, PrintWriter pw, String[] args)127 public void reverseDump(FileDescriptor fd, PrintWriter pw, String[] args) { 128 mLog.reverseDump(pw); 129 } reverseDump(PrintWriter pw)130 public void reverseDump(PrintWriter pw) { 131 mLog.reverseDump(pw); 132 } 133 } 134 135 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) readOnlyLocalLog()136 public ReadOnlyLocalLog readOnlyLocalLog() { 137 return new ReadOnlyLocalLog(this); 138 } 139 } 140