1/* 2 * Copyright (C) 2016 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 17package com.android.server.wifi; 18 19import android.util.Log; 20 21import com.android.internal.annotations.Immutable; 22 23import javax.annotation.concurrent.ThreadSafe; 24 25/** 26 * Provides a WifiLog implementation which uses logd as the 27 * logging backend. 28 * 29 * This class is trivially thread-safe, as instances are immutable. 30 * Note, however, that LogMessage instances are _not_ thread-safe. 31 */ 32@ThreadSafe 33@Immutable 34class LogcatLog implements WifiLog { 35 private final String mTag; 36 private static volatile boolean sVerboseLogging = false; 37 38 LogcatLog(String tag) { 39 mTag = tag; 40 } 41 42 public static void enableVerboseLogging(int verboseMode) { 43 if (verboseMode > 0) { 44 sVerboseLogging = true; 45 } else { 46 sVerboseLogging = false; 47 } 48 } 49 50 /* New-style methods */ 51 @Override 52 public LogMessage err(String format) { 53 return makeLogMessage(Log.ERROR, format); 54 } 55 56 @Override 57 public LogMessage warn(String format) { 58 return makeLogMessage(Log.WARN, format); 59 } 60 61 @Override 62 public LogMessage info(String format) { 63 return makeLogMessage(Log.INFO, format); 64 } 65 66 @Override 67 public LogMessage trace(String format) { 68 return makeLogMessage(Log.DEBUG, format); 69 } 70 71 @Override 72 public LogMessage dump(String format) { 73 return makeLogMessage(Log.VERBOSE, format); 74 } 75 76 @Override 77 public void eC(String msg) { 78 Log.e(mTag, msg); 79 } 80 81 @Override 82 public void wC(String msg) { 83 Log.w(mTag, msg); 84 } 85 86 @Override 87 public void iC(String msg) { 88 Log.i(mTag, msg); 89 } 90 91 @Override 92 public void tC(String msg) { 93 Log.d(mTag, msg); 94 } 95 96 /* Legacy methods */ 97 @Override 98 public void e(String msg) { 99 Log.e(mTag, msg); 100 } 101 102 @Override 103 public void w(String msg) { 104 Log.w(mTag, msg); 105 } 106 107 @Override 108 public void i(String msg) { 109 Log.i(mTag, msg); 110 } 111 112 @Override 113 public void d(String msg) { 114 Log.d(mTag, msg); 115 } 116 117 @Override 118 public void v(String msg) { 119 Log.v(mTag, msg); 120 } 121 122 /* Internal details */ 123 private static class RealLogMessage implements WifiLog.LogMessage { 124 private final int mLogLevel; 125 private final String mTag; 126 private final String mFormat; 127 private final StringBuilder mStringBuilder; 128 private int mNextFormatCharPos; 129 130 RealLogMessage(int logLevel, String tag, String format) { 131 mLogLevel = logLevel; 132 mTag = tag; 133 mFormat = format; 134 mStringBuilder = new StringBuilder(); 135 mNextFormatCharPos = 0; 136 } 137 138 @Override 139 public WifiLog.LogMessage r(String value) { 140 // Since the logcat back-end is just transitional, we don't attempt to tag sensitive 141 // information in it. 142 return c(value); 143 } 144 145 @Override 146 public WifiLog.LogMessage c(String value) { 147 copyUntilPlaceholder(); 148 if (mNextFormatCharPos < mFormat.length()) { 149 mStringBuilder.append(value); 150 ++mNextFormatCharPos; 151 } 152 return this; 153 } 154 155 @Override 156 public WifiLog.LogMessage c(long value) { 157 copyUntilPlaceholder(); 158 if (mNextFormatCharPos < mFormat.length()) { 159 mStringBuilder.append(value); 160 ++mNextFormatCharPos; 161 } 162 return this; 163 } 164 165 @Override 166 public WifiLog.LogMessage c(char value) { 167 copyUntilPlaceholder(); 168 if (mNextFormatCharPos < mFormat.length()) { 169 mStringBuilder.append(value); 170 ++mNextFormatCharPos; 171 } 172 return this; 173 } 174 175 @Override 176 public WifiLog.LogMessage c(boolean value) { 177 copyUntilPlaceholder(); 178 if (mNextFormatCharPos < mFormat.length()) { 179 mStringBuilder.append(value); 180 ++mNextFormatCharPos; 181 } 182 return this; 183 } 184 185 @Override 186 public void flush() { 187 if (mNextFormatCharPos < mFormat.length()) { 188 mStringBuilder.append(mFormat, mNextFormatCharPos, mFormat.length()); 189 } 190 if (sVerboseLogging || mLogLevel > Log.DEBUG) { 191 Log.println(mLogLevel, mTag, mStringBuilder.toString()); 192 } 193 } 194 195 /* Should generally not be used; implemented primarily to aid in testing. */ 196 public String toString() { 197 return mStringBuilder.toString(); 198 } 199 200 private void copyUntilPlaceholder() { 201 if (mNextFormatCharPos >= mFormat.length()) { 202 return; 203 } 204 205 int placeholderPos = mFormat.indexOf(WifiLog.PLACEHOLDER, mNextFormatCharPos); 206 if (placeholderPos == -1) { 207 placeholderPos = mFormat.length(); 208 } 209 210 mStringBuilder.append(mFormat, mNextFormatCharPos, placeholderPos); 211 mNextFormatCharPos = placeholderPos; 212 } 213 } 214 215 private LogMessage makeLogMessage(int logLevel, String format) { 216 // TODO(b/30737821): Consider adding an isLoggable() check. 217 return new RealLogMessage(logLevel, mTag, format); 218 } 219} 220