Merge "Fix NULL pointer dereference issues in CryptoHal::toSharedBuffer" into qt-dev
diff --git a/apex/Android.bp b/apex/Android.bp
index ec0efe6..2cc6fcb 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -12,22 +12,27 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-com_android_media_extractors = [
-    "libaacextractor",
-    "libamrextractor",
-    "libflacextractor",
-    "libmidiextractor",
-    "libmkvextractor",
-    "libmp3extractor",
-    "libmp4extractor",
-    "libmpeg2extractor",
-    "liboggextractor",
-    "libwavextractor",
-]
-
 apex_defaults {
     name: "com.android.media-defaults",
     java_libs: ["updatable-media"],
+    multilib: {
+        first: {
+            // Extractor process runs only with the primary ABI.
+            native_shared_libs: [
+                // Extractor plugins
+                "libaacextractor",
+                "libamrextractor",
+                "libflacextractor",
+                "libmidiextractor",
+                "libmkvextractor",
+                "libmp3extractor",
+                "libmp4extractor",
+                "libmpeg2extractor",
+                "liboggextractor",
+                "libwavextractor",
+            ],
+        },
+    },
     key: "com.android.media.key",
     certificate: ":com.android.media.certificate",
 
@@ -39,12 +44,6 @@
     name: "com.android.media",
     manifest: "manifest.json",
     defaults: ["com.android.media-defaults"],
-    multilib: {
-        first: {
-            // Extractor process runs only with the primary ABI.
-            native_shared_libs: com_android_media_extractors,
-        },
-    },
 }
 
 filegroup {
diff --git a/apex/manifest.json b/apex/manifest.json
index cee94e2..03b9dd0 100644
--- a/apex/manifest.json
+++ b/apex/manifest.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.media",
-  "version": 210000000
+  "version": 220000000
 }
diff --git a/apex/manifest_codec.json b/apex/manifest_codec.json
index b83e65a..58ce868 100644
--- a/apex/manifest_codec.json
+++ b/apex/manifest_codec.json
@@ -1,4 +1,4 @@
 {
   "name": "com.android.media.swcodec",
-  "version": 210000000
+  "version": 220000000
 }
diff --git a/apex/testing/Android.bp b/apex/testing/Android.bp
index 297d864..701ced7 100644
--- a/apex/testing/Android.bp
+++ b/apex/testing/Android.bp
@@ -17,13 +17,6 @@
     manifest: "test_manifest.json",
     file_contexts: "com.android.media",
     defaults: ["com.android.media-defaults"],
-    multilib: {
-        both: {
-            // for test apex, built for both ABIs
-            native_shared_libs: com_android_media_extractors,
-        },
-    },
-    compile_multilib: "both",
     installable: false,
 }
 
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index 6fe5970..a58167a 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -20,7 +20,7 @@
     name: "libaacextractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index b26b2d8..4bd933d 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -18,7 +18,7 @@
     name: "libamrextractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/flac/Android.bp b/media/extractors/flac/Android.bp
index 3e83090..3a3d051 100644
--- a/media/extractors/flac/Android.bp
+++ b/media/extractors/flac/Android.bp
@@ -24,7 +24,7 @@
     name: "libflacextractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index 6790dd6..7d42e70 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -19,7 +19,7 @@
     name: "libmidiextractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/mkv/Android.bp b/media/extractors/mkv/Android.bp
index 7c94149..1744d3d 100644
--- a/media/extractors/mkv/Android.bp
+++ b/media/extractors/mkv/Android.bp
@@ -25,7 +25,7 @@
     name: "libmkvextractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/mp3/Android.bp b/media/extractors/mp3/Android.bp
index 168ef68..4e2f248 100644
--- a/media/extractors/mp3/Android.bp
+++ b/media/extractors/mp3/Android.bp
@@ -24,7 +24,7 @@
     name: "libmp3extractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/mp4/Android.bp b/media/extractors/mp4/Android.bp
index 9b9c931..1b308aa 100644
--- a/media/extractors/mp4/Android.bp
+++ b/media/extractors/mp4/Android.bp
@@ -32,7 +32,7 @@
     ],
     version_script: "exports.lds",
     relative_install_path: "extractors",
-    compile_multilib: "both",
+    compile_multilib: "first",
 }
 
 cc_library_shared {
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 14f49ae..0f0c72c 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -40,7 +40,7 @@
     name: "libmpeg2extractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/ogg/Android.bp b/media/extractors/ogg/Android.bp
index fd03f64..604ec59 100644
--- a/media/extractors/ogg/Android.bp
+++ b/media/extractors/ogg/Android.bp
@@ -26,7 +26,7 @@
     name: "liboggextractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 15fd796..7e89271 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -21,7 +21,7 @@
     name: "libwavextractor",
     relative_install_path: "extractors",
 
-    compile_multilib: "both",
+    compile_multilib: "first",
 
     cflags: [
         "-Werror",
diff --git a/media/libaaudio/src/binding/IAAudioService.cpp b/media/libaaudio/src/binding/IAAudioService.cpp
index 9b32543..97ad2b0 100644
--- a/media/libaaudio/src/binding/IAAudioService.cpp
+++ b/media/libaaudio/src/binding/IAAudioService.cpp
@@ -251,8 +251,15 @@
             CHECK_INTERFACE(IAAudioService, data, reply);
             sp<IAAudioClient> client = interface_cast<IAAudioClient>(
                     data.readStrongBinder());
-            registerClient(client);
-            return NO_ERROR;
+            // readStrongBinder() can return null
+            if (client.get() == nullptr) {
+                ALOGE("BnAAudioService::%s(REGISTER_CLIENT) client is NULL!", __func__);
+                android_errorWriteLog(0x534e4554, "116230453");
+                return DEAD_OBJECT;
+            } else {
+                registerClient(client);
+                return NO_ERROR;
+            }
         } break;
 
         case OPEN_STREAM: {
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index 4a65fc9..71efc30 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -63,7 +63,9 @@
     // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
-    audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
+    audio_channel_mask_t channelMask = samplesPerFrame <= 2 ?
+                               audio_channel_in_mask_from_count(samplesPerFrame) :
+                               audio_channel_mask_for_index_assignment_from_count(samplesPerFrame);
 
     size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
                         : builder.getBufferCapacity();
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index d628bf7..094cdd1 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -66,7 +66,9 @@
     // Use stereo if unspecified.
     int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                               ? 2 : getSamplesPerFrame();
-    audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
+    audio_channel_mask_t channelMask = samplesPerFrame <= 2 ?
+                            audio_channel_out_mask_from_count(samplesPerFrame) :
+                            audio_channel_mask_for_index_assignment_from_count(samplesPerFrame);
 
     audio_output_flags_t flags;
     aaudio_performance_mode_t perfMode = getPerformanceMode();
diff --git a/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp b/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp
index b80555b..c0e4c51 100644
--- a/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp
+++ b/media/libstagefright/codecs/amrwb/src/deemphasis_32.cpp
@@ -131,7 +131,7 @@
     int16 lo, hi;
 
     L_tmp  = ((int32)x_hi[0]) << 16;
-    L_tmp += ((int32)x_lo[0]) << 4;
+    L_tmp += (((int32)x_lo[0]) << 4) & 0xFFFF;
     L_tmp  = shl_int32(L_tmp, 3);
 
     L_tmp = fxp_mac_16by16(*mem, mu, L_tmp),
@@ -144,7 +144,7 @@
     for (i = 1; i < L - 1; i++)
     {
         L_tmp  = ((int32)hi) << 16;
-        L_tmp += ((int32)lo) << 4;
+        L_tmp += (((int32)lo) << 4) & 0xFFFF;
         L_tmp  = shl_int32(L_tmp, 3);
         L_tmp  = fxp_mac_16by16(y[i - 1], mu, L_tmp),
                  L_tmp  = shl_int32(L_tmp, 1);           /* saturation can occur here */
@@ -153,7 +153,7 @@
         hi     = x_hi[i+1];
     }
     L_tmp  = ((int32)hi) << 16;
-    L_tmp += ((int32)lo) << 4;
+    L_tmp += (((int32)lo) << 4) & 0xFFFF;
     L_tmp  = shl_int32(L_tmp, 3);
     L_tmp  = fxp_mac_16by16(y[i - 1], mu, L_tmp),
              L_tmp  = shl_int32(L_tmp, 1);           /* saturation can occur here */
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a48b733..7daa929 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -3277,6 +3277,7 @@
 
         Vector< sp<EffectChain> > effectChains;
         audio_session_t activeHapticSessionId = AUDIO_SESSION_NONE;
+        std::vector<sp<Track>> activeTracks;
 
         // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
         //
@@ -3563,6 +3564,12 @@
                 }
             }
 
+            // Acquire a local copy of active tracks with lock (release w/o lock).
+            //
+            // Control methods on the track acquire the ThreadBase lock (e.g. start()
+            // stop(), pause(), etc.), but the threadLoop is entitled to call audio
+            // data / buffer methods on tracks from activeTracks without the ThreadBase lock.
+            activeTracks.insert(activeTracks.end(), mActiveTracks.begin(), mActiveTracks.end());
         } // mLock scope ends
 
         if (mBytesRemaining == 0) {
@@ -3577,6 +3584,13 @@
                 threadLoop_sleepTime();
                 if (mSleepTimeUs == 0) {
                     mCurrentWriteLength = mSinkBufferSize;
+
+                    // Tally underrun frames as we are inserting 0s here.
+                    for (const auto& track : activeTracks) {
+                        if (track->mFillingUpStatus == Track::FS_ACTIVE) {
+                            track->mAudioTrackServerProxy->tallyUnderrunFrames(mNormalFrameCount);
+                        }
+                    }
                 }
             }
             // Either threadLoop_mix() or threadLoop_sleepTime() should have set
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 2d182bd..d906f11 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -112,6 +112,9 @@
     static bool isBetterFormatMatch(audio_format_t newFormat,
                                         audio_format_t currentFormat,
                                         audio_format_t targetFormat);
+    static uint32_t formatDistance(audio_format_t format1,
+                                   audio_format_t format2);
+    static const uint32_t kFormatDistanceMax = 4;
 
     audio_module_handle_t getModuleHandle() const;
     uint32_t getModuleVersionMajor() const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index a66c695..c11490a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -282,30 +282,25 @@
     return index1 - index2;
 }
 
+uint32_t AudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
+{
+    if (format1 == format2) {
+        return 0;
+    }
+    if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
+        return kFormatDistanceMax;
+    }
+    int diffBytes = (int)audio_bytes_per_sample(format1) -
+            audio_bytes_per_sample(format2);
+
+    return abs(diffBytes);
+}
+
 bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
                                     audio_format_t currentFormat,
                                     audio_format_t targetFormat)
 {
-    if (newFormat == currentFormat) {
-        return false;
-    }
-    if (currentFormat == AUDIO_FORMAT_INVALID) {
-        return true;
-    }
-    if (newFormat == targetFormat) {
-        return true;
-    }
-    int currentDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
-            audio_bytes_per_sample(currentFormat);
-    int newDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
-            audio_bytes_per_sample(newFormat);
-
-    if (abs(newDiffBytes) < abs(currentDiffBytes)) {
-        return true;
-    } else if (abs(newDiffBytes) == abs(currentDiffBytes)) {
-        return (newDiffBytes >= 0);
-    }
-    return false;
+    return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
 }
 
 void AudioPort::pickAudioProfile(uint32_t &samplingRate,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index c0ca440..2dc7cad 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -36,12 +36,12 @@
 #define AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME \
         "audio_policy_configuration_bluetooth_legacy_hal.xml"
 
+#include <algorithm>
 #include <inttypes.h>
 #include <math.h>
 #include <set>
 #include <unordered_set>
 #include <vector>
-
 #include <AudioPolicyManagerInterface.h>
 #include <AudioPolicyEngineInstance.h>
 #include <cutils/properties.h>
@@ -592,7 +592,7 @@
                     AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT);
     SortedVector<audio_io_handle_t> outputs =
             getOutputsForDevices(DeviceVector(outputDevice), mOutputs);
-    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+    const audio_io_handle_t output = selectOutput(outputs);
     // request to reuse existing output stream if one is already opened to reach the target device
     if (output != AUDIO_IO_HANDLE_NONE) {
         sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
@@ -883,7 +883,7 @@
     // and AudioSystem::getOutputSamplingRate().
 
     SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
-    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+    const audio_io_handle_t output = selectOutput(outputs);
 
     ALOGV("getOutput() stream %d selected devices %s, output %d", stream,
           devices.toString().c_str(), output);
@@ -1430,108 +1430,125 @@
                                                        audio_channel_mask_t channelMask,
                                                        uint32_t samplingRate)
 {
+    LOG_ALWAYS_FATAL_IF(!(format == AUDIO_FORMAT_INVALID || audio_is_linear_pcm(format)),
+        "%s called with format %#x", __func__, format);
+
+    // Flags disqualifying an output: the match must happen before calling selectOutput()
+    static const audio_output_flags_t kExcludedFlags = (audio_output_flags_t)
+        (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+
+    // Flags expressing a functional request: must be honored in priority over
+    // other criteria
+    static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
+        (AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
+            AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
+    // Flags expressing a performance request: have lower priority than serving
+    // requested sampling rate or channel mask
+    static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
+        (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER |
+            AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_SYNC);
+
+    const audio_output_flags_t functionalFlags =
+        (audio_output_flags_t)(flags & kFunctionalFlags);
+    const audio_output_flags_t performanceFlags =
+        (audio_output_flags_t)(flags & kPerformanceFlags);
+
+    audio_io_handle_t bestOutput = (outputs.size() == 0) ? AUDIO_IO_HANDLE_NONE : outputs[0];
+
     // select one output among several that provide a path to a particular device or set of
     // devices (the list was previously build by getOutputsForDevices()).
     // The priority is as follows:
     // 1: the output supporting haptic playback when requesting haptic playback
-    // 2: the output with the highest number of requested policy flags
-    // 3: the output with the bit depth the closest to the requested one
-    // 4: the primary output
-    // 5: the first output in the list
+    // 2: the output with the highest number of requested functional flags
+    // 3: the output supporting the exact channel mask
+    // 4: the output with a higher channel count than requested
+    // 5: the output with a higher sampling rate than requested
+    // 6: the output with the highest number of requested performance flags
+    // 7: the output with the bit depth the closest to the requested one
+    // 8: the primary output
+    // 9: the first output in the list
 
-    if (outputs.size() == 0) {
-        return AUDIO_IO_HANDLE_NONE;
-    }
-    if (outputs.size() == 1) {
-        return outputs[0];
-    }
+    // matching criteria values in priority order for best matching output so far
+    std::vector<uint32_t> bestMatchCriteria(8, 0);
 
-    int maxCommonFlags = 0;
-    const size_t hapticChannelCount = audio_channel_count_from_out_mask(
-            channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
-    audio_io_handle_t outputForFlags = AUDIO_IO_HANDLE_NONE;
-    audio_io_handle_t outputForPrimary = AUDIO_IO_HANDLE_NONE;
-    audio_io_handle_t outputForFormat = AUDIO_IO_HANDLE_NONE;
-    audio_format_t bestFormat = AUDIO_FORMAT_INVALID;
-    audio_format_t bestFormatForFlags = AUDIO_FORMAT_INVALID;
-
-    // Flags which must be present on both the request and the selected output
-    static const audio_output_flags_t kMandatedFlags = (audio_output_flags_t)
-        (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
+    const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
+    const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
+        channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
 
     for (audio_io_handle_t output : outputs) {
         sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
-        if (!outputDesc->isDuplicated()) {
-            if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
-                continue;
-            }
-            // If haptic channel is specified, use the haptic output if present.
-            // When using haptic output, same audio format and sample rate are required.
-            if (hapticChannelCount > 0) {
-                // If haptic channel is specified, use the first output that
-                // support haptic playback.
-                if (audio_channel_count_from_out_mask(
-                        outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) >= hapticChannelCount
-                        && format == outputDesc->mFormat
-                        && samplingRate == outputDesc->mSamplingRate) {
-                    return output;
-                }
-            } else {
-                // When haptic channel is not specified, skip haptic output.
-                if (outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) {
-                    continue;
-                }
-            }
-            if ((kMandatedFlags & flags) !=
-                (kMandatedFlags & outputDesc->mProfile->getFlags())) {
-                continue;
-            }
+        // matching criteria values in priority order for current output
+        std::vector<uint32_t> currentMatchCriteria(8, 0);
 
-            // if a valid format is specified, skip output if not compatible
-            if (format != AUDIO_FORMAT_INVALID) {
-                if (!audio_is_linear_pcm(format)) {
-                    continue;
-                }
-                if (AudioPort::isBetterFormatMatch(
-                        outputDesc->mFormat, bestFormat, format)) {
-                    outputForFormat = output;
-                    bestFormat = outputDesc->mFormat;
-                }
-            }
+        if (outputDesc->isDuplicated()) {
+            continue;
+        }
+        if ((kExcludedFlags & outputDesc->mFlags) != 0) {
+            continue;
+        }
 
-            int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
-            if (commonFlags >= maxCommonFlags) {
-                if (commonFlags == maxCommonFlags) {
-                    if (format != AUDIO_FORMAT_INVALID
-                            && AudioPort::isBetterFormatMatch(
-                                    outputDesc->mFormat, bestFormatForFlags, format)) {
-                        outputForFlags = output;
-                        bestFormatForFlags = outputDesc->mFormat;
-                    }
-                } else {
-                    outputForFlags = output;
-                    maxCommonFlags = commonFlags;
-                    bestFormatForFlags = outputDesc->mFormat;
-                }
-                ALOGV("selectOutput() commonFlags for output %d, %04x", output, commonFlags);
+        // If haptic channel is specified, use the haptic output if present.
+        // When using haptic output, same audio format and sample rate are required.
+        const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
+            outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
+        if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
+            continue;
+        }
+        if (outputHapticChannelCount >= hapticChannelCount
+            && format == outputDesc->mFormat
+            && samplingRate == outputDesc->mSamplingRate) {
+                currentMatchCriteria[0] = outputHapticChannelCount;
+        }
+
+        // functional flags match
+        currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);
+
+        // channel mask and channel count match
+        uint32_t outputChannelCount = audio_channel_count_from_out_mask(outputDesc->mChannelMask);
+        if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
+            channelCount <= outputChannelCount) {
+            if ((audio_channel_mask_get_representation(channelMask) ==
+                    audio_channel_mask_get_representation(outputDesc->mChannelMask)) &&
+                    ((channelMask & outputDesc->mChannelMask) == channelMask)) {
+                currentMatchCriteria[2] = outputChannelCount;
             }
-            if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
-                outputForPrimary = output;
-            }
+            currentMatchCriteria[3] = outputChannelCount;
+        }
+
+        // sampling rate match
+        if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
+                samplingRate <= outputDesc->mSamplingRate) {
+            currentMatchCriteria[4] = outputDesc->mSamplingRate;
+        }
+
+        // performance flags match
+        currentMatchCriteria[5] = popcount(outputDesc->mFlags & performanceFlags);
+
+        // format match
+        if (format != AUDIO_FORMAT_INVALID) {
+            currentMatchCriteria[6] =
+                AudioPort::kFormatDistanceMax -
+                AudioPort::formatDistance(format, outputDesc->mFormat);
+        }
+
+        // primary output match
+        currentMatchCriteria[7] = outputDesc->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY;
+
+        // compare match criteria by priority then value
+        if (std::lexicographical_compare(bestMatchCriteria.begin(), bestMatchCriteria.end(),
+                currentMatchCriteria.begin(), currentMatchCriteria.end())) {
+            bestMatchCriteria = currentMatchCriteria;
+            bestOutput = output;
+
+            std::stringstream result;
+            std::copy(bestMatchCriteria.begin(), bestMatchCriteria.end(),
+                std::ostream_iterator<int>(result, " "));
+            ALOGV("%s new bestOutput %d criteria %s",
+                __func__, bestOutput, result.str().c_str());
         }
     }
 
-    if (outputForFlags != AUDIO_IO_HANDLE_NONE) {
-        return outputForFlags;
-    }
-    if (outputForFormat != AUDIO_IO_HANDLE_NONE) {
-        return outputForFormat;
-    }
-    if (outputForPrimary != AUDIO_IO_HANDLE_NONE) {
-        return outputForPrimary;
-    }
-
-    return outputs[0];
+    return bestOutput;
 }
 
 status_t AudioPolicyManager::startOutput(audio_port_handle_t portId)
@@ -3003,22 +3020,11 @@
 
 status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) {
     ALOGV("%s() uid=%d", __FUNCTION__, uid);
-    Vector<AudioDeviceTypeAddr> devices;
-    status_t res =  mPolicyMixes.getDevicesForUid(uid, devices);
-    if (res == NO_ERROR) {
-        // reevaluate outputs for all found devices
-        for (size_t i = 0; i < devices.size(); i++) {
-            sp<DeviceDescriptor> devDesc = mHwModules.getDeviceDescriptor(
-                    devices[i].mType, devices[i].mAddress, String8(),
-                    AUDIO_FORMAT_DEFAULT);
-            SortedVector<audio_io_handle_t> outputs;
-            if (checkOutputsForDevice(devDesc, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
-                    outputs) != NO_ERROR) {
-                ALOGE("%s() error in checkOutputsForDevice for device=%08x addr=%s",
-                        __FUNCTION__, devices[i].mType, devices[i].mAddress.string());
-                return INVALID_OPERATION;
-            }
-        }
+    status_t res = mPolicyMixes.removeUidDeviceAffinities(uid);
+    if (res != NO_ERROR) {
+        ALOGE("%s() Could not remove all device affinities fo uid = %d",
+            __FUNCTION__, uid);
+        return INVALID_OPERATION;
     }
 
     return res;
@@ -3485,7 +3491,7 @@
                             getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
                     // if the sink device is reachable via an opened output stream, request to go via
                     // this output stream by adding a second source to the patch description
-                    audio_io_handle_t output = selectOutput(outputs);
+                    const audio_io_handle_t output = selectOutput(outputs);
                     if (output != AUDIO_IO_HANDLE_NONE) {
                         sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
                         if (outputDesc->isDuplicated()) {
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 83704ba..8572561 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -67,6 +67,12 @@
                                          const sp<IAAudioClient>& client) {
     ALOGV("registerClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
 
+    if (client.get() == nullptr) {
+        ALOGE("AAudioClientTracker::%s() client is NULL!", __func__);
+        android_errorWriteLog(0x534e4554, "116230453");
+        return AAUDIO_ERROR_NULL;
+    }
+
     std::lock_guard<std::mutex> lock(mLock);
     if (mNotificationClients.count(pid) == 0) {
         sp<NotificationClient> notificationClient = new NotificationClient(pid);