audioflinger: add effect creation probe mode

Add an argument to IAudioFlinger::createEffect() API to
ask AudioFlinger to just run the pre flight checks but not
create the actual audio effect instance and allocate resources.
This is the basis of an API for apps to query if a given
effect can be created without having to allocate the resources
and risk an exception when calling the constructor.

Bug: 150699608
Test: CTS and GTS Tests for audio effects
Change-Id: Ibdda22fd945c88c33e3c7342a7a5ed3e02d399ac
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index a1b141b..c183ab0 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -36,7 +36,7 @@
 // ---------------------------------------------------------------------------
 
 AudioEffect::AudioEffect(const String16& opPackageName)
-    : mStatus(NO_INIT), mOpPackageName(opPackageName)
+    : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
 {
 }
 
@@ -49,12 +49,13 @@
                 void* user,
                 audio_session_t sessionId,
                 audio_io_handle_t io,
-                const AudioDeviceTypeAddr& device
+                const AudioDeviceTypeAddr& device,
+                bool probe
                 )
-    : mStatus(NO_INIT), mOpPackageName(opPackageName)
+    : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
 {
     AutoMutex lock(mConstructLock);
-    mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device);
+    mStatus = set(type, uuid, priority, cbf, user, sessionId, io, device, probe);
 }
 
 AudioEffect::AudioEffect(const char *typeStr,
@@ -65,9 +66,10 @@
                 void* user,
                 audio_session_t sessionId,
                 audio_io_handle_t io,
-                const AudioDeviceTypeAddr& device
+                const AudioDeviceTypeAddr& device,
+                bool probe
                 )
-    : mStatus(NO_INIT), mOpPackageName(opPackageName)
+    : mStatus(NO_INIT), mProbe(false), mOpPackageName(opPackageName)
 {
     effect_uuid_t type;
     effect_uuid_t *pType = NULL;
@@ -89,7 +91,7 @@
     }
 
     AutoMutex lock(mConstructLock);
-    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device);
+    mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io, device, probe);
 }
 
 status_t AudioEffect::set(const effect_uuid_t *type,
@@ -99,7 +101,8 @@
                 void* user,
                 audio_session_t sessionId,
                 audio_io_handle_t io,
-                const AudioDeviceTypeAddr& device)
+                const AudioDeviceTypeAddr& device,
+                bool probe)
 {
     sp<IEffect> iEffect;
     sp<IMemory> cblk;
@@ -126,7 +129,7 @@
         ALOGW("Must specify at least type or uuid");
         return BAD_VALUE;
     }
-
+    mProbe = probe;
     mPriority = priority;
     mCbf = cbf;
     mUserData = user;
@@ -142,15 +145,18 @@
 
     iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor,
             mIEffectClient, priority, io, mSessionId, device, mOpPackageName, mClientPid,
-            &mStatus, &mId, &enabled);
+            probe, &mStatus, &mId, &enabled);
 
-    if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
+    // In probe mode, we stop here and return the status: the IEffect interface to
+    // audio flinger will not be retained. initCheck() will return the creation status
+    // but all other APIs will return invalid operation.
+    if (probe || iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
         char typeBuffer[64], uuidBuffer[64];
         guidToString(type, typeBuffer, sizeof(typeBuffer));
         guidToString(uuid, uuidBuffer, sizeof(uuidBuffer));
-        ALOGE("set(): AudioFlinger could not create effect %s / %s, status: %d",
+        ALOGE_IF(!probe, "set(): AudioFlinger could not create effect %s / %s, status: %d",
                 typeBuffer, uuidBuffer, mStatus);
-        if (iEffect == 0) {
+        if (!probe && iEffect == 0) {
             mStatus = NO_INIT;
         }
         return mStatus;
@@ -191,7 +197,7 @@
 {
     ALOGV("Destructor %p", this);
 
-    if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
+    if (!mProbe && (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS)) {
         if (!audio_is_global_session(mSessionId)) {
             AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
         }
@@ -201,9 +207,9 @@
         }
         mIEffect.clear();
         mCblkMemory.clear();
-        mIEffectClient.clear();
-        IPCThreadState::self()->flushCommands();
     }
+    mIEffectClient.clear();
+    IPCThreadState::self()->flushCommands();
 }
 
 
@@ -226,6 +232,9 @@
 
 status_t AudioEffect::setEnabled(bool enabled)
 {
+    if (mProbe) {
+        return INVALID_OPERATION;
+    }
     if (mStatus != NO_ERROR) {
         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
     }
@@ -254,6 +263,9 @@
                               uint32_t *replySize,
                               void *replyData)
 {
+    if (mProbe) {
+        return INVALID_OPERATION;
+    }
     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
         ALOGV("command() bad status %d", mStatus);
         return mStatus;
@@ -287,6 +299,9 @@
 
 status_t AudioEffect::setParameter(effect_param_t *param)
 {
+    if (mProbe) {
+        return INVALID_OPERATION;
+    }
     if (mStatus != NO_ERROR) {
         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
     }
@@ -307,6 +322,9 @@
 
 status_t AudioEffect::setParameterDeferred(effect_param_t *param)
 {
+    if (mProbe) {
+        return INVALID_OPERATION;
+    }
     if (mStatus != NO_ERROR) {
         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
     }
@@ -333,6 +351,9 @@
 
 status_t AudioEffect::setParameterCommit()
 {
+    if (mProbe) {
+        return INVALID_OPERATION;
+    }
     if (mStatus != NO_ERROR) {
         return (mStatus == ALREADY_EXISTS) ? (status_t) INVALID_OPERATION : mStatus;
     }
@@ -347,6 +368,9 @@
 
 status_t AudioEffect::getParameter(effect_param_t *param)
 {
+    if (mProbe) {
+        return INVALID_OPERATION;
+    }
     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
         return mStatus;
     }