Prevent dumping sound models when max reached

There are currently cases when SoundTriggerHelper may get out of sync 
with SoundTriggerHwService, specifically which and how many sound models
are loaded.

If SoundTriggerHelper attempts to load a sound model and it would be 
exceeding the maximum allowable number of sound models:

1) If the new sound model is not a KeyphraseSoundModel:
	Throw an error
2) If the new sound model is a KeyphraseSoundModel:
	See if there is an existing KeyphraseSoundModel to unload
	Failing that, unload the first SoundModel in the index


BUG: 27225762
BUG: 22860713

Change-Id: I74db1be36bbc5887f5bf4751c3138de102976722
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index c891fd6..66310b5 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -544,19 +544,39 @@
     AutoMutex lock(mLock);
 
     if (mModels.size() >= mDescriptor.properties.max_sound_models) {
+        /* Make space for a keyphrase sound model by first trying to swap out a previously loaded
+         * keyphrase sound model, or if needed, another sound model. This decision would optimally
+         * happen in SoundTriggerHelper, but is happening here because state tracking isn't good
+         * enough in SoundTriggerHelper to ensure that state is consistent between it and the HAL,
+         * nor does sufficient error handling exist to recover from inconsistencies.
+         * Once that exists:
+         * TODO: we should return an error instead of unloading a previous sound model here.
+         */
         if (mModels.size() == 0) {
             return INVALID_OPERATION;
         }
-        ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
-              mDescriptor.properties.max_sound_models);
-        unloadSoundModel_l(mModels.valueAt(0)->mHandle);
+        if (sound_model->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+            ALOGW("loadSoundModel() max number of models exceeded %d making room for a new one",
+                  mDescriptor.properties.max_sound_models);
+            sound_model_handle_t unload_handle = mModels.valueAt(0)->mHandle;
+            for (size_t i = 0; i < mModels.size(); i++) {
+                if (mModels.valueAt(i)->mType == SOUND_MODEL_TYPE_KEYPHRASE) {
+                    unload_handle = mModels.keyAt(i);
+                    break;
+                }
+            }
+            unloadSoundModel_l(unload_handle);
+        } else {
+            ALOGW("loadSoundModel(): Not loading, max number of models (%d) would be exceeded",
+                  mDescriptor.properties.max_sound_models);
+            return INVALID_OPERATION;
+        }
     }
 
-    status_t status = mHwDevice->load_sound_model(mHwDevice,
-                                                  sound_model,
+    status_t status = mHwDevice->load_sound_model(mHwDevice, sound_model,
                                                   SoundTriggerHwService::soundModelCallback,
-                                                  this,
-                                                  handle);
+                                                  this, handle);
+
     if (status != NO_ERROR) {
         return status;
     }