• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.wifi;
18 
19 import com.android.internal.app.IBatteryStats;
20 import com.android.internal.util.Protocol;
21 
22 import android.support.v4.util.CircularArray;
23 import android.util.Base64;
24 import android.util.LocalLog;
25 import android.util.Log;
26 
27 import java.io.ByteArrayOutputStream;
28 import java.io.FileDescriptor;
29 import java.io.IOException;
30 import java.io.PrintWriter;
31 import java.util.Calendar;
32 import java.util.HashMap;
33 import java.util.zip.Deflater;
34 
35 /**
36  * Tracks various logs for framework
37  */
38 class WifiLogger extends DummyWifiLogger  {
39 
40     private static final String TAG = "WifiLogger";
41     private static final boolean DBG = false;
42 
43     /** log level flags; keep these consistent with wifi_logger.h */
44 
45     /** No logs whatsoever */
46     public static final int VERBOSE_NO_LOG = 0;
47     /** No logs whatsoever */
48     public static final int VERBOSE_NORMAL_LOG = 1;
49     /** Be careful since this one can affect performance and power */
50     public static final int VERBOSE_LOG_WITH_WAKEUP  = 2;
51     /** Be careful since this one can affect performance and power and memory */
52     public static final int VERBOSE_DETAILED_LOG_WITH_WAKEUP  = 3;
53 
54     /** ring buffer flags; keep these consistent with wifi_logger.h */
55     public static final int RING_BUFFER_FLAG_HAS_BINARY_ENTRIES     = 0x00000001;
56     public static final int RING_BUFFER_FLAG_HAS_ASCII_ENTRIES      = 0x00000002;
57     public static final int RING_BUFFER_FLAG_HAS_PER_PACKET_ENTRIES = 0x00000004;
58 
59     /** various reason codes */
60     public static final int REPORT_REASON_NONE                      = 0;
61     public static final int REPORT_REASON_ASSOC_FAILURE             = 1;
62     public static final int REPORT_REASON_AUTH_FAILURE              = 2;
63     public static final int REPORT_REASON_AUTOROAM_FAILURE          = 3;
64     public static final int REPORT_REASON_DHCP_FAILURE              = 4;
65     public static final int REPORT_REASON_UNEXPECTED_DISCONNECT     = 5;
66     public static final int REPORT_REASON_SCAN_FAILURE              = 6;
67     public static final int REPORT_REASON_USER_ACTION               = 7;
68 
69     /** number of ring buffer entries to cache */
70     public static final int MAX_RING_BUFFERS                        = 10;
71 
72     /** number of bug reports to hold */
73     public static final int MAX_BUG_REPORTS                         = 4;
74 
75     /** number of alerts to hold */
76     public static final int MAX_ALERT_REPORTS                       = 1;
77 
78     /** minimum wakeup interval for each of the log levels */
79     private static final int MinWakeupIntervals[] = new int[] { 0, 3600, 60, 10 };
80     /** minimum buffer size for each of the log levels */
81     private static final int MinBufferSizes[] = new int[] { 0, 16384, 16384, 65536 };
82 
83     private int mLogLevel = VERBOSE_NO_LOG;
84     private String mFirmwareVersion;
85     private String mDriverVersion;
86     private int mSupportedFeatureSet;
87     private WifiNative.RingBufferStatus[] mRingBuffers;
88     private WifiNative.RingBufferStatus mPerPacketRingBuffer;
89     private WifiStateMachine mWifiStateMachine;
90 
WifiLogger(WifiStateMachine wifiStateMachine)91     public WifiLogger(WifiStateMachine wifiStateMachine) {
92         mWifiStateMachine = wifiStateMachine;
93     }
94 
95     @Override
startLogging(boolean verboseEnabled)96     public synchronized void startLogging(boolean verboseEnabled) {
97         mFirmwareVersion = WifiNative.getFirmwareVersion();
98         mDriverVersion = WifiNative.getDriverVersion();
99         mSupportedFeatureSet = WifiNative.getSupportedLoggerFeatureSet();
100 
101         if (mLogLevel == VERBOSE_NO_LOG)
102             WifiNative.setLoggingEventHandler(mHandler);
103 
104         if (verboseEnabled) {
105             mLogLevel = VERBOSE_LOG_WITH_WAKEUP;
106         } else {
107             mLogLevel = VERBOSE_NORMAL_LOG;
108         }
109         if (mRingBuffers == null) {
110             if (fetchRingBuffers()) {
111                 startLoggingAllExceptPerPacketBuffers();
112             }
113         }
114     }
115 
116     @Override
startPacketLog()117     public synchronized void startPacketLog() {
118         if (mPerPacketRingBuffer != null) {
119             startLoggingRingBuffer(mPerPacketRingBuffer);
120         } else {
121             if (DBG) Log.d(TAG, "There is no per packet ring buffer");
122         }
123     }
124 
125     @Override
stopPacketLog()126     public synchronized void stopPacketLog() {
127         if (mPerPacketRingBuffer != null) {
128             stopLoggingRingBuffer(mPerPacketRingBuffer);
129         } else {
130             if (DBG) Log.d(TAG, "There is no per packet ring buffer");
131         }
132     }
133 
134     @Override
stopLogging()135     public synchronized void stopLogging() {
136         if (mLogLevel != VERBOSE_NO_LOG) {
137             //resetLogHandler only can be used when you terminate all logging since all handler will
138             //be removed. This also stop alert logging
139             if(!WifiNative.resetLogHandler()) {
140                 Log.e(TAG, "Fail to reset log handler");
141             } else {
142                 if (DBG) Log.d(TAG,"Reset log handler");
143             }
144             stopLoggingAllBuffers();
145             mRingBuffers = null;
146             mLogLevel = VERBOSE_NO_LOG;
147         }
148     }
149 
150     @Override
captureBugReportData(int reason)151     public synchronized void captureBugReportData(int reason) {
152         BugReport report = captureBugreport(reason, true);
153         mLastBugReports.addLast(report);
154     }
155 
156     @Override
captureAlertData(int errorCode, byte[] alertData)157     public synchronized void captureAlertData(int errorCode, byte[] alertData) {
158         BugReport report = captureBugreport(errorCode, /* captureFWDump = */ true);
159         report.alertData = alertData;
160         mLastAlerts.addLast(report);
161     }
162 
163     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)164     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
165         pw.println("Chipset information :-----------------------------------------------");
166         pw.println("FW Version is: " + mFirmwareVersion);
167         pw.println("Driver Version is: " + mDriverVersion);
168         pw.println("Supported Feature set: " + mSupportedFeatureSet);
169 
170         for (int i = 0; i < mLastAlerts.size(); i++) {
171             pw.println("--------------------------------------------------------------------");
172             pw.println("Alert dump " + i);
173             pw.print(mLastAlerts.get(i));
174             pw.println("--------------------------------------------------------------------");
175         }
176 
177         for (int i = 0; i < mLastBugReports.size(); i++) {
178             pw.println("--------------------------------------------------------------------");
179             pw.println("Bug dump " + i);
180             pw.print(mLastBugReports.get(i));
181             pw.println("--------------------------------------------------------------------");
182         }
183 
184         pw.println("--------------------------------------------------------------------");
185     }
186 
187     /* private methods and data */
188     private static class BugReport {
189         long systemTimeMs;
190         long kernelTimeNanos;
191         int errorCode;
192         HashMap<String, byte[][]> ringBuffers = new HashMap();
193         byte[] fwMemoryDump;
194         byte[] alertData;
195 
toString()196         public String toString() {
197             StringBuilder builder = new StringBuilder();
198 
199             Calendar c = Calendar.getInstance();
200             c.setTimeInMillis(systemTimeMs);
201             builder.append("system time = ").append(
202                     String.format("%tm-%td %tH:%tM:%tS.%tL", c, c, c, c, c, c)).append("\n");
203 
204             long kernelTimeMs = kernelTimeNanos/(1000*1000);
205             builder.append("kernel time = ").append(kernelTimeMs/1000).append(".").append
206                     (kernelTimeMs%1000).append("\n");
207 
208             if (alertData == null)
209                 builder.append("reason = ").append(errorCode).append("\n");
210             else {
211                 builder.append("errorCode = ").append(errorCode);
212                 builder.append("data \n");
213                 builder.append(compressToBase64(alertData)).append("\n");
214             }
215 
216             for (HashMap.Entry<String, byte[][]> e : ringBuffers.entrySet()) {
217                 String ringName = e.getKey();
218                 byte[][] buffers = e.getValue();
219                 builder.append("ring-buffer = ").append(ringName).append("\n");
220 
221                 int size = 0;
222                 for (int i = 0; i < buffers.length; i++) {
223                     size += buffers[i].length;
224                 }
225 
226                 byte[] buffer = new byte[size];
227                 int index = 0;
228                 for (int i = 0; i < buffers.length; i++) {
229                     System.arraycopy(buffers[i], 0, buffer, index, buffers[i].length);
230                     index += buffers[i].length;
231                 }
232 
233                 builder.append(compressToBase64(buffer));
234                 builder.append("\n");
235             }
236 
237             if (fwMemoryDump != null) {
238                 builder.append("FW Memory dump \n");
239                 builder.append(compressToBase64(fwMemoryDump));
240             }
241 
242             return builder.toString();
243         }
244     }
245 
246     private static class LimitedCircularArray<E> {
247         private CircularArray<E> mArray;
248         private int mMax;
LimitedCircularArray(int max)249         LimitedCircularArray(int max) {
250             mArray = new CircularArray<E>();
251             mMax = max;
252         }
253 
addLast(E e)254         public final void addLast(E e) {
255             if (mArray.size() >= mMax)
256                 mArray.popFirst();
257             mArray.addLast(e);
258         }
259 
size()260         public final int size() {
261             return mArray.size();
262         }
263 
get(int i)264         public final E get(int i) {
265             return mArray.get(i);
266         }
267     }
268 
269     private final LimitedCircularArray<BugReport> mLastAlerts =
270             new LimitedCircularArray<BugReport>(MAX_ALERT_REPORTS);
271     private final LimitedCircularArray<BugReport> mLastBugReports =
272             new LimitedCircularArray<BugReport>(MAX_BUG_REPORTS);
273     private final HashMap<String, LimitedCircularArray<byte[]>> mRingBufferData = new HashMap();
274 
275     private final WifiNative.WifiLoggerEventHandler mHandler =
276             new WifiNative.WifiLoggerEventHandler() {
277         @Override
278         public void onRingBufferData(WifiNative.RingBufferStatus status, byte[] buffer) {
279             WifiLogger.this.onRingBufferData(status, buffer);
280         }
281 
282         @Override
283         public void onWifiAlert(int errorCode, byte[] buffer) {
284             WifiLogger.this.onWifiAlert(errorCode, buffer);
285         }
286     };
287 
onRingBufferData(WifiNative.RingBufferStatus status, byte[] buffer)288     synchronized void onRingBufferData(WifiNative.RingBufferStatus status, byte[] buffer) {
289         LimitedCircularArray<byte[]> ring = mRingBufferData.get(status.name);
290         if (ring != null) {
291             ring.addLast(buffer);
292         }
293     }
294 
onWifiAlert(int errorCode, byte[] buffer)295     synchronized void onWifiAlert(int errorCode, byte[] buffer) {
296         if (mWifiStateMachine != null) {
297             mWifiStateMachine.sendMessage(
298                     WifiStateMachine.CMD_FIRMWARE_ALERT, errorCode, 0, buffer);
299         }
300     }
301 
fetchRingBuffers()302     private boolean fetchRingBuffers() {
303         if (mRingBuffers != null) return true;
304 
305         mRingBuffers = WifiNative.getRingBufferStatus();
306         if (mRingBuffers != null) {
307             for (WifiNative.RingBufferStatus buffer : mRingBuffers) {
308                 if (DBG) Log.d(TAG, "RingBufferStatus is: \n" + buffer.name);
309                 if (mRingBufferData.containsKey(buffer.name) == false) {
310                     mRingBufferData.put(buffer.name,
311                             new LimitedCircularArray<byte[]>(MAX_RING_BUFFERS));
312                 }
313                 if ((buffer.flag & RING_BUFFER_FLAG_HAS_PER_PACKET_ENTRIES) != 0) {
314                     mPerPacketRingBuffer = buffer;
315                 }
316             }
317         } else {
318             Log.e(TAG, "no ring buffers found");
319         }
320 
321         return mRingBuffers != null;
322     }
323 
startLoggingAllExceptPerPacketBuffers()324     private boolean startLoggingAllExceptPerPacketBuffers() {
325 
326         if (mRingBuffers == null) {
327             if (DBG) Log.d(TAG, "No ring buffers to log anything!");
328             return false;
329         }
330 
331         for (WifiNative.RingBufferStatus buffer : mRingBuffers){
332 
333             if ((buffer.flag & RING_BUFFER_FLAG_HAS_PER_PACKET_ENTRIES) != 0) {
334                 /* skip per-packet-buffer */
335                 if (DBG) Log.d(TAG, "skipped per packet logging ring " + buffer.name);
336                 continue;
337             }
338 
339             startLoggingRingBuffer(buffer);
340         }
341 
342         return true;
343     }
344 
startLoggingRingBuffer(WifiNative.RingBufferStatus buffer)345     private boolean startLoggingRingBuffer(WifiNative.RingBufferStatus buffer) {
346 
347         int minInterval = MinWakeupIntervals[mLogLevel];
348         int minDataSize = MinBufferSizes[mLogLevel];
349 
350         if (WifiNative.startLoggingRingBuffer(
351                 mLogLevel, 0, minInterval, minDataSize, buffer.name) == false) {
352             if (DBG) Log.e(TAG, "Could not start logging ring " + buffer.name);
353             return false;
354         }
355 
356         return true;
357     }
358 
stopLoggingRingBuffer(WifiNative.RingBufferStatus buffer)359     private boolean stopLoggingRingBuffer(WifiNative.RingBufferStatus buffer) {
360         if (WifiNative.startLoggingRingBuffer(0, 0, 0, 0, buffer.name) == false) {
361             if (DBG) Log.e(TAG, "Could not stop logging ring " + buffer.name);
362         }
363         return true;
364     }
365 
stopLoggingAllBuffers()366     private boolean stopLoggingAllBuffers() {
367         if (mRingBuffers != null) {
368             for (WifiNative.RingBufferStatus buffer : mRingBuffers) {
369                 stopLoggingRingBuffer(buffer);
370             }
371         }
372         return true;
373     }
374 
getAllRingBufferData()375     private boolean getAllRingBufferData() {
376         if (mRingBuffers == null) {
377             Log.e(TAG, "Not ring buffers available to collect data!");
378             return false;
379         }
380 
381         for (WifiNative.RingBufferStatus element : mRingBuffers){
382             boolean result = WifiNative.getRingBufferData(element.name);
383             if (!result) {
384                 Log.e(TAG, "Fail to get ring buffer data of: " + element.name);
385                 return false;
386             }
387         }
388 
389         Log.d(TAG, "getAllRingBufferData Successfully!");
390         return true;
391     }
392 
captureBugreport(int errorCode, boolean captureFWDump)393     private BugReport captureBugreport(int errorCode, boolean captureFWDump) {
394         BugReport report = new BugReport();
395         report.errorCode = errorCode;
396         report.systemTimeMs = System.currentTimeMillis();
397         report.kernelTimeNanos = System.nanoTime();
398 
399         if (mRingBuffers != null) {
400             for (WifiNative.RingBufferStatus buffer : mRingBuffers) {
401                 /* this will push data in mRingBuffers */
402                 WifiNative.getRingBufferData(buffer.name);
403                 LimitedCircularArray<byte[]> data = mRingBufferData.get(buffer.name);
404                 byte[][] buffers = new byte[data.size()][];
405                 for (int i = 0; i < data.size(); i++) {
406                     buffers[i] = data.get(i).clone();
407                 }
408                 report.ringBuffers.put(buffer.name, buffers);
409             }
410         }
411 
412         if (captureFWDump) {
413             report.fwMemoryDump = WifiNative.getFwMemoryDump();
414         }
415         return report;
416     }
417 
compressToBase64(byte[] input)418     private static String compressToBase64(byte[] input) {
419         String result;
420         //compress
421         Deflater compressor = new Deflater();
422         compressor.setLevel(Deflater.BEST_COMPRESSION);
423         compressor.setInput(input);
424         compressor.finish();
425         ByteArrayOutputStream bos = new ByteArrayOutputStream(input.length);
426         final byte[] buf = new byte[1024];
427 
428         while (!compressor.finished()) {
429             int count = compressor.deflate(buf);
430             bos.write(buf, 0, count);
431         }
432 
433         try {
434             compressor.end();
435             bos.close();
436         } catch (IOException e) {
437             Log.e(TAG, "ByteArrayOutputStream close error");
438             result =  android.util.Base64.encodeToString(input, Base64.DEFAULT);
439             return result;
440         }
441 
442         byte[] compressed = bos.toByteArray();
443         if (DBG) {
444             Log.d(TAG," length is:" + (compressed == null? "0" : compressed.length));
445         }
446 
447         //encode
448         result = android.util.Base64.encodeToString(
449                 compressed.length < input.length ? compressed : input , Base64.DEFAULT);
450 
451         if (DBG) {
452             Log.d(TAG, "FwMemoryDump length is :" + result.length());
453         }
454 
455         return result;
456     }
457 }
458