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