Home | History | Annotate | Download | only in audio
      1 <html devsite>
      2   <head>
      3     <title>Audio Debugging</title>
      4     <meta name="project_path" value="/_project.yaml" />
      5     <meta name="book_path" value="/_book.yaml" />
      6   </head>
      7   <body>
      8   <!--
      9       Copyright 2017 The Android Open Source Project
     10 
     11       Licensed under the Apache License, Version 2.0 (the "License");
     12       you may not use this file except in compliance with the License.
     13       You may obtain a copy of the License at
     14 
     15           http://www.apache.org/licenses/LICENSE-2.0
     16 
     17       Unless required by applicable law or agreed to in writing, software
     18       distributed under the License is distributed on an "AS IS" BASIS,
     19       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     20       See the License for the specific language governing permissions and
     21       limitations under the License.
     22   -->
     23 
     24 
     25 
     26 <p>
     27 This article describes some tips and tricks for debugging Android audio.
     28 </p>
     29 
     30 <h2 id="teeSink">Tee Sink</h2>
     31 
     32 <p>
     33 The "tee sink" is
     34 an AudioFlinger debugging feature, available in custom builds only,
     35 for retaining a short fragment of recent audio for later analysis.
     36 This permits comparison between what was actually played or recorded
     37 vs. what was expected.
     38 </p>
     39 
     40 <p>
     41 For privacy the tee sink is disabled by default, at both compile-time and
     42 run-time.  To use the tee sink, you will need to enable it by re-compiling,
     43 and also by setting a property.  Be sure to disable this feature after you are
     44 done debugging; the tee sink should not be left enabled in production builds.
     45 </p>
     46 
     47 <p>
     48 The instructions in the remainder of this section are for Android 5.x and 6.x.
     49 For Android 7.x, replace <code>/data/misc/media</code> with
     50 <code>/data/misc/audioserver</code>.
     51 Additionally, you must use a userdebug or eng build.
     52 If you use a userdebug build, then disable verity with:</p>
     53 
     54 <pre class="devsite-terminal devsite-click-to-copy">
     55 adb root &amp;&amp; adb disable-verity &amp;&amp; adb reboot
     56 </pre>
     57 
     58 <h3 id="compile">Compile-time setup</h3>
     59 
     60 <ol>
     61   <li><code class="devsite-terminal">cd frameworks/av/services/audioflinger</code></li>
     62 <li>Edit <code>Configuration.h</code>.</li>
     63 <li>Uncomment <code>#define TEE_SINK</code>.</li>
     64 <li>Re-build <code>libaudioflinger.so</code>.</li>
     65 <li><code class="devsite-terminal">adb root</code></li>
     66 <li><code class="devsite-terminal">adb remount</code></li>
     67 <li>Push or sync the new <code>libaudioflinger.so</code> to the device's <code>/system/lib</code>.</li>
     68 </ol>
     69 
     70 <h3 id="runtime">Run-time setup</h3>
     71 
     72 <ol>
     73 <li><code class="devsite-terminal">adb shell getprop | grep ro.debuggable</code>
     74 <br />Confirm that the output is: <code>[ro.debuggable]: [1]</code>
     75 </li>
     76 <li><code class="devsite-terminal">adb shell</code></li>
     77 <li><code class="devsite-terminal">ls -ld /data/misc/media</code>
     78 <br />
     79 <p>
     80 Confirm that the output is:
     81 </p>
     82 <pre>
     83 drwx------ media media ... media
     84 </pre>
     85 <p>
     86 If the directory does not exist, create it as follows:
     87 </p>
     88 <pre class="devsite-click-to-copy">
     89 <code class="devsite-terminal">mkdir /data/misc/media</code>
     90 <code class="devsite-terminal">chown media:media /data/misc/media</code>
     91 </pre>
     92 </li>
     93 <li><code class="devsite-terminal">echo af.tee=# &gt; /data/local.prop</code>
     94 <br />Where the <code>af.tee</code> value is a number described below.
     95 </li>
     96 <li><code class="devsite-terminal">chmod 644 /data/local.prop</code></li>
     97 <li><code class="devsite-terminal">reboot</code></li>
     98 </ol>
     99 
    100 <h4>Values for <code>af.tee</code> property</h4>
    101 
    102 <p>
    103 The value of <code>af.tee</code> is a number between 0 and 7, expressing
    104 the sum of several bits, one per feature.
    105 See the code at <code>AudioFlinger::AudioFlinger()</code> in <code>AudioFlinger.cpp</code>
    106 for an explanation of each bit, but briefly:
    107 </p>
    108 <ul>
    109 <li>1 = input</li>
    110 <li>2 = FastMixer output</li>
    111 <li>4 = per-track AudioRecord and AudioTrack</li>
    112 </ul>
    113 
    114 <p>
    115 There is no bit for deep buffer or normal mixer yet,
    116 but you can get similar results using "4."
    117 </p>
    118 
    119 <h3 id="test">Test and acquire data</h3>
    120 
    121 <ol>
    122 <li>Run your audio test.</li>
    123 <li><code class="devsite-terminal">adb shell dumpsys media.audio_flinger</code></li>
    124 <li>Look for a line in dumpsys output such as this:<br />
    125 <code>tee copied to /data/misc/media/20131010101147_2.wav</code>
    126 <br />This is a PCM .wav file.
    127 </li>
    128 <li>Then <code>adb pull</code> any <code>/data/misc/media/*.wav</code> files of interest;
    129 note that track-specific dump filenames do not appear in the dumpsys output,
    130 but are still saved to <code>/data/misc/media</code> upon track closure.
    131 </li>
    132 <li>Review the dump files for privacy concerns before sharing with others.</li>
    133 </ol>
    134 
    135 <h4>Suggestions</h4>
    136 
    137 <p>Try these ideas for more useful results:</p>
    138 
    139 <ul>
    140 <li>Disable touch sounds and key clicks to reduce interruptions in test output.</li>
    141 <li>Maximize all volumes.</li>
    142 <li>Disable apps that make sound or record from microphone,
    143 if they are not of interest to your test.
    144 </li>
    145 <li>Track-specific dumps are only saved when the track is closed;
    146 you may need to force close an app in order to dump its track-specific data
    147 </li>
    148 <li>Do the <code>dumpsys</code> immediately after test;
    149 there is a limited amount of recording space available.</li>
    150 <li>To make sure you don't lose your dump files,
    151 upload them to your host periodically.
    152 Only a limited number of dump files are preserved;
    153 older dumps are removed after that limit is reached.</li>
    154 </ul>
    155 
    156 <h3 id="restore">Restore</h3>
    157 
    158 <p>
    159 As noted above, the tee sink feature should not be left enabled.
    160 Restore your build and device as follows:
    161 </p>
    162 <ol>
    163 <li>Revert the source code changes to <code>Configuration.h</code>.</li>
    164 <li>Re-build <code>libaudioflinger.so</code>.</li>
    165 <li>Push or sync the restored <code>libaudioflinger.so</code>
    166 to the device's <code>/system/lib</code>.
    167 </li>
    168 <li><code class="devsite-terminal">adb shell</code></li>
    169 <li><code class="devsite-terminal">rm /data/local.prop</code></li>
    170 <li><code class="devsite-terminal">rm /data/misc/media/*.wav</code></li>
    171 <li><code class="devsite-terminal">reboot</code></li>
    172 </ol>
    173 
    174 <h2 id="mediaLog">media.log</h2>
    175 
    176 <h3 id="alogx">ALOGx macros</h3>
    177 
    178 <p>
    179 The standard Java language logging API in Android SDK is
    180 <a href="http://developer.android.com/reference/android/util/Log.html">android.util.Log</a>.
    181 </p>
    182 
    183 <p>
    184 The corresponding C language API in Android NDK is
    185 <code>__android_log_print</code>
    186 declared in <code>&lt;android/log.h&gt;</code>.
    187 </p>
    188 
    189 <p>
    190 Within the native portion of Android framework, we
    191 prefer macros named <code>ALOGE</code>, <code>ALOGW</code>,
    192 <code>ALOGI</code>, <code>ALOGV</code>, etc.  They are declared in
    193 <code>&lt;utils/Log.h&gt;</code>, and for the purposes of this article
    194 we'll collectively refer to them as <code>ALOGx</code>.
    195 </p>
    196 
    197 <p>
    198 All of these APIs are easy-to-use and well-understood, so they are pervasive
    199 throughout the Android platform.  In particular the <code>mediaserver</code>
    200 process, which includes the AudioFlinger sound server, uses
    201 <code>ALOGx</code> extensively.
    202 </p>
    203 
    204 <p>
    205 Nevertheless, there are some limitations to <code>ALOGx</code> and friends:
    206 </p>
    207 
    208 <ul>
    209 <li>
    210 They are susceptible to "log spam": the log buffer is a shared resource
    211 so it can easily overflow due to unrelated log entries, resulting in
    212 missed information.  The <code>ALOGV</code> variant is disabled at
    213 compile-time by default.  But of course even it can result in log spam
    214 if it is enabled.
    215 </li>
    216 <li>
    217 The underlying kernel system calls could block, possibly resulting in
    218 priority inversion and consequently measurement disturbances and
    219 inaccuracies.  This is of
    220 special concern to time-critical threads such as <code>FastMixer</code> and <code>FastCapture</code>.
    221 </li>
    222 <li>
    223 If a particular log is disabled to reduce log spam,
    224 then any information that would have been captured by that log is lost.
    225 It is not possible to enable a specific log retroactively,
    226 <i>after</i> it becomes clear that the log would have been interesting.
    227 </li>
    228 </ul>
    229 
    230 <h3 id="nblog">NBLOG, media.log, and MediaLogService</h3>
    231 
    232 <p>
    233 The <code>NBLOG</code> APIs and associated <code>media.log</code>
    234 process and <code>MediaLogService</code>
    235 service together form a newer logging system for media, and are specifically
    236 designed to address the issues above.  We will loosely use the term
    237 "media.log" to refer to all three, but strictly speaking <code>NBLOG</code> is the
    238 C++ logging API, <code>media.log</code> is a Linux process name, and <code>MediaLogService</code>
    239 is an Android binder service for examining the logs.
    240 </p>
    241 
    242 <p>
    243 A <code>media.log</code> "timeline" is a series
    244 of log entries whose relative ordering is preserved.
    245 By convention, each thread should use it's own timeline.
    246 </p>
    247 
    248 <h3 id="benefits">Benefits</h3>
    249 
    250 <p>
    251 The benefits of the <code>media.log</code> system are that it:
    252 </p>
    253 <ul>
    254 <li>Doesn't spam the main log unless and until it is needed.</li>
    255 <li>Can be examined even when <code>mediaserver</code> crashes or hangs.</li>
    256 <li>Is non-blocking per timeline.</li>
    257 <li>Offers less disturbance to performance.
    258 (Of course no form of logging is completely non-intrusive.)
    259 </li>
    260 </ul>
    261 
    262 <h3 id="architecture">Architecture</h3>
    263 
    264 <p>
    265 The diagram below shows the relationship of the <code>mediaserver</code> process
    266 and the <code>init</code> process, before <code>media.log</code> is introduced:
    267 </p>
    268 <img src="images/medialog_before.png" alt="Architecture before media.log" id="figure1" />
    269 <p class="img-caption">
    270   <strong>Figure 1.</strong> Architecture before media.log
    271 </p>
    272 
    273 <p>
    274 Notable points:
    275 </p>
    276 <ul>
    277 <li><code>init</code> forks and execs <code>mediaserver</code>.</li>
    278 <li><code>init</code> detects the death of <code>mediaserver</code>, and re-forks as necessary.</li>
    279 <li><code>ALOGx</code> logging is not shown.</li>
    280 </ul>
    281 
    282 <p>
    283 The diagram below shows the new relationship of the components,
    284 after <code>media.log</code> is added to the architecture:
    285 </p>
    286 <img src="images/medialog_after.png" alt="Architecture after media.log" id="figure2" />
    287 <p class="img-caption">
    288   <strong>Figure 2.</strong> Architecture after media.log
    289 </p>
    290 
    291 <p>
    292 Important changes:
    293 </p>
    294 
    295 <ul>
    296 
    297 <li>
    298 Clients use <code>NBLOG</code> API to construct log entries and append them to
    299 a circular buffer in shared memory.
    300 </li>
    301 
    302 <li>
    303 <code>MediaLogService</code> can dump the contents of the circular buffer at any time.
    304 </li>
    305 
    306 <li>
    307 The circular buffer is designed in such a way that any corruption of the
    308 shared memory will not crash <code>MediaLogService</code>, and it will still be able
    309 to dump as much of the buffer that is not affected by the corruption.
    310 </li>
    311 
    312 <li>
    313 The circular buffer is non-blocking and lock-free for both writing
    314 new entries and reading existing entries.
    315 </li>
    316 
    317 <li>
    318 No kernel system calls are required to write to or read from the circular buffer
    319 (other than optional timestamps).
    320 </li>
    321 
    322 </ul>
    323 
    324 <h4>Where to use</h4>
    325 
    326 <p>
    327 As of Android 4.4, there are only a few log points in AudioFlinger
    328 that use the <code>media.log</code> system.  Though the new APIs are not as
    329 easy to use as <code>ALOGx</code>, they are not extremely difficult either.
    330 We encourage you to learn the new logging system for those
    331 occasions when it is indispensable.
    332 In particular, it is recommended for AudioFlinger threads that must
    333 run frequently, periodically, and without blocking such as the
    334 <code>FastMixer</code> and <code>FastCapture</code> threads.
    335 </p>
    336 
    337 <h3 id="how">How to use</h3>
    338 
    339 <h4>Add logs</h4>
    340 
    341 <p>
    342 First, you need to add logs to your code.
    343 </p>
    344 
    345 <p>
    346 In <code>FastMixer</code> and <code>FastCapture</code> threads, use code such as this:
    347 </p>
    348 <pre class="devsite-click-to-copy">
    349 logWriter-&gt;log("string");
    350 logWriter-&gt;logf("format", parameters);
    351 logWriter-&gt;logTimestamp();
    352 </pre>
    353 <p>
    354 As this <code>NBLog</code> timeline is used only by the <code>FastMixer</code> and
    355 <code>FastCapture</code> threads,
    356 there is no need for mutual exclusion.
    357 </p>
    358 
    359 <p>
    360 In other AudioFlinger threads, use <code>mNBLogWriter</code>:
    361 </p>
    362 <pre class="devsite-click-to-copy">
    363 mNBLogWriter-&gt;log("string");
    364 mNBLogWriter-&gt;logf("format", parameters);
    365 mNBLogWriter-&gt;logTimestamp();
    366 </pre>
    367 <p>
    368 For threads other than <code>FastMixer</code> and <code>FastCapture</code>,
    369 the thread's <code>NBLog</code> timeline can be used by both the thread itself, and
    370 by binder operations.  <code>NBLog::Writer</code> does not provide any
    371 implicit mutual exclusion per timeline, so be sure that all logs occur
    372 within a context where the thread's mutex <code>mLock</code> is held.
    373 </p>
    374 
    375 <p>
    376 After you have added the logs, re-build AudioFlinger.
    377 </p>
    378 
    379 <p class="caution"><strong>Caution:</strong>
    380 A separate <code>NBLog::Writer</code> timeline is required per thread,
    381 to ensure thread safety, since timelines omit mutexes by design.  If you
    382 want more than one thread to use the same timeline, you can protect with an
    383 existing mutex (as described above for <code>mLock</code>).  Or you can
    384 use the <code>NBLog::LockedWriter</code> wrapper instead of <code>NBLog::Writer</code>.
    385 However, this negates a prime benefit of this API: its non-blocking
    386 behavior.
    387 </p>
    388 
    389 <p>
    390 The full <code>NBLog</code> API is at <code>frameworks/av/include/media/nbaio/NBLog.h</code>.
    391 </p>
    392 
    393 <h4>Enable media.log</h4>
    394 
    395 <p>
    396 <code>media.log</code> is disabled by default. It is active only when property
    397 <code>ro.test_harness</code> is <code>1</code>.  You can enable it by:
    398 </p>
    399 
    400 <pre class="devsite-click-to-copy">
    401 <code class="devsite-terminal">adb root</code>
    402 <code class="devsite-terminal">adb shell</code>
    403 <code class="devsite-terminal">echo ro.test_harness=1 > /data/local.prop</code>
    404 <code class="devsite-terminal">chmod 644 /data/local.prop</code>
    405 <code class="devsite-terminal">reboot</code>
    406 </pre>
    407 
    408 <p>
    409 The connection is lost during reboot, so:
    410 </p>
    411 <pre class="devsite-terminal devsite-click-to-copy">
    412 adb shell
    413 </pre>
    414 
    415 The command <code>ps media</code> will now show two processes:
    416 <ul>
    417 <li>media.log</li>
    418 <li>mediaserver</li>
    419 </ul>
    420 <p>
    421 Note the process ID of <code>mediaserver</code> for later.
    422 </p>
    423 
    424 <h4>Displaying the timelines</h4>
    425 
    426 <p>
    427 You can manually request a log dump at any time.
    428 This command shows logs from all the active and recent timelines, and then clears them:
    429 </p>
    430 <pre class="devsite-terminal devsite-click-to-copy">
    431 dumpsys media.log
    432 </pre>
    433 
    434 <p>
    435 Note that by design timelines are independent,
    436 and there is no facility for merging timelines.
    437 </p>
    438 
    439 <h4>Recovering logs after mediaserver death</h4>
    440 
    441 <p>
    442 Now try killing <code>mediaserver</code> process: <code>kill -9 #</code>, where # is
    443 the process ID you noted earlier.  You should see a dump from <code>media.log</code>
    444 in the main <code>logcat</code>, showing all the logs leading up to the crash.
    445 </p>
    446 
    447 <pre class="devsite-terminal devsite-click-to-copy">
    448 dumpsys media.log
    449 </pre>
    450 
    451   </body>
    452 </html>
    453