audioflinger: Adjust priority of hal threads

HALs are prohibited from using framework binder, and there is
no equivalent scheduling policy service in hwbinder. Thus, in order
to match priorities of FastCapture / Mixer threads with their
counterparts in the HAL, it is needed to request the priority boost
from audioflinger on behalf of the HAL.

Test done to verify the priority was correctly set.

Bug: 34131400
Change-Id: If8b6b031c0fcba771fae901a5b8e7da89b3a1570
Test: check priority match between audioflinger's and hal's threads
diff --git a/media/libaudiohal/Android.mk b/media/libaudiohal/Android.mk
index 5e00b77..617eb35 100644
--- a/media/libaudiohal/Android.mk
+++ b/media/libaudiohal/Android.mk
@@ -46,7 +46,8 @@
     android.hardware.audio.common@2.0-util \
     android.hardware.audio.effect@2.0      \
     android.hidl.memory@1.0                \
-    libmedia_helper
+    libmedia_helper  \
+    libmediautils
 
 endif  # USE_LEGACY_LOCAL_AUDIO_HAL
 
diff --git a/media/libaudiohal/StreamHalHidl.cpp b/media/libaudiohal/StreamHalHidl.cpp
index 36ea1be..4054aaa 100644
--- a/media/libaudiohal/StreamHalHidl.cpp
+++ b/media/libaudiohal/StreamHalHidl.cpp
@@ -18,6 +18,7 @@
 //#define LOG_NDEBUG 0
 
 #include <android/hardware/audio/2.0/IStreamOutCallback.h>
+#include <mediautils/SchedulingPolicyService.h>
 #include <utils/Log.h>
 
 #include "DeviceHalHidl.h"
@@ -26,6 +27,7 @@
 
 using ::android::hardware::audio::common::V2_0::AudioChannelMask;
 using ::android::hardware::audio::common::V2_0::AudioFormat;
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
 using ::android::hardware::audio::V2_0::AudioDrain;
 using ::android::hardware::audio::V2_0::IStreamOutCallback;
 using ::android::hardware::audio::V2_0::MessageQueueFlagBits;
@@ -33,7 +35,6 @@
 using ::android::hardware::audio::V2_0::MmapPosition;
 using ::android::hardware::audio::V2_0::ParameterValue;
 using ::android::hardware::audio::V2_0::Result;
-using ::android::hardware::audio::V2_0::ThreadPriority;
 using ::android::hardware::audio::V2_0::TimeSpec;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
@@ -44,8 +45,8 @@
 
 StreamHalHidl::StreamHalHidl(IStream *stream)
         : ConversionHelperHidl("Stream"),
-          mHalThreadPriority(static_cast<int>(ThreadPriority::NORMAL)),
-          mStream(stream) {
+          mStream(stream),
+          mHalThreadPriority(HAL_THREAD_PRIORITY_DEFAULT) {
 }
 
 StreamHalHidl::~StreamHalHidl() {
@@ -187,6 +188,19 @@
     return OK;
 }
 
+bool StreamHalHidl::requestHalThreadPriority(pid_t threadPid, pid_t threadId) {
+    if (mHalThreadPriority == HAL_THREAD_PRIORITY_DEFAULT) {
+        return true;
+    }
+    int err = requestPriority(
+            threadPid, threadId,
+            mHalThreadPriority, false /*isForApp*/, true /*asynchronous*/);
+    ALOGE_IF(err, "failed to set priority %d for pid %d tid %d; error %d",
+            mHalThreadPriority, threadPid, threadId, err);
+    // Audio will still work, but latency will be higher and sometimes unacceptable.
+    return err == 0;
+}
+
 namespace {
 
 /* Notes on callback ownership.
@@ -352,12 +366,14 @@
     std::unique_ptr<DataMQ> tempDataMQ;
     std::unique_ptr<StatusMQ> tempStatusMQ;
     Result retval;
+    pid_t halThreadPid, halThreadTid;
     Return<void> ret = mStream->prepareForWriting(
-            1, bufferSize, ThreadPriority(mHalThreadPriority),
+            1, bufferSize,
             [&](Result r,
                     const CommandMQ::Descriptor& commandMQ,
                     const DataMQ::Descriptor& dataMQ,
-                    const StatusMQ::Descriptor& statusMQ) {
+                    const StatusMQ::Descriptor& statusMQ,
+                    const ThreadInfo& halThreadInfo) {
                 retval = r;
                 if (retval == Result::OK) {
                     tempCommandMQ.reset(new CommandMQ(commandMQ));
@@ -366,6 +382,8 @@
                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
                     }
+                    halThreadPid = halThreadInfo.pid;
+                    halThreadTid = halThreadInfo.tid;
                 }
             });
     if (!ret.isOk() || retval != Result::OK) {
@@ -386,6 +404,8 @@
         ALOGE_IF(!mEfGroup, "Event flag creation for writing failed");
         return NO_INIT;
     }
+    requestHalThreadPriority(halThreadPid, halThreadTid);
+
     mCommandMQ = std::move(tempCommandMQ);
     mDataMQ = std::move(tempDataMQ);
     mStatusMQ = std::move(tempStatusMQ);
@@ -605,12 +625,14 @@
     std::unique_ptr<DataMQ> tempDataMQ;
     std::unique_ptr<StatusMQ> tempStatusMQ;
     Result retval;
+    pid_t halThreadPid, halThreadTid;
     Return<void> ret = mStream->prepareForReading(
-            1, bufferSize, ThreadPriority(mHalThreadPriority),
+            1, bufferSize,
             [&](Result r,
                     const CommandMQ::Descriptor& commandMQ,
                     const DataMQ::Descriptor& dataMQ,
-                    const StatusMQ::Descriptor& statusMQ) {
+                    const StatusMQ::Descriptor& statusMQ,
+                    const ThreadInfo& halThreadInfo) {
                 retval = r;
                 if (retval == Result::OK) {
                     tempCommandMQ.reset(new CommandMQ(commandMQ));
@@ -619,6 +641,8 @@
                     if (tempDataMQ->isValid() && tempDataMQ->getEventFlagWord()) {
                         EventFlag::createEventFlag(tempDataMQ->getEventFlagWord(), &mEfGroup);
                     }
+                    halThreadPid = halThreadInfo.pid;
+                    halThreadTid = halThreadInfo.tid;
                 }
             });
     if (!ret.isOk() || retval != Result::OK) {
@@ -639,6 +663,8 @@
         ALOGE_IF(!mEfGroup, "Event flag creation for reading failed");
         return NO_INIT;
     }
+    requestHalThreadPriority(halThreadPid, halThreadTid);
+
     mCommandMQ = std::move(tempCommandMQ);
     mDataMQ = std::move(tempDataMQ);
     mStatusMQ = std::move(tempStatusMQ);
diff --git a/media/libaudiohal/StreamHalHidl.h b/media/libaudiohal/StreamHalHidl.h
index db217a8..a7df276 100644
--- a/media/libaudiohal/StreamHalHidl.h
+++ b/media/libaudiohal/StreamHalHidl.h
@@ -101,10 +101,12 @@
     // The destructor automatically closes the stream.
     virtual ~StreamHalHidl();
 
-    int mHalThreadPriority;
+    bool requestHalThreadPriority(pid_t threadPid, pid_t threadId);
 
   private:
+    const int HAL_THREAD_PRIORITY_DEFAULT = -1;
     IStream *mStream;
+    int mHalThreadPriority;
 };
 
 class StreamOutHalHidl : public StreamOutHalInterface, public StreamHalHidl {
diff --git a/media/utils/ISchedulingPolicyService.cpp b/media/utils/ISchedulingPolicyService.cpp
index f5bfe20..22fbc97 100644
--- a/media/utils/ISchedulingPolicyService.cpp
+++ b/media/utils/ISchedulingPolicyService.cpp
@@ -37,13 +37,15 @@
     {
     }
 
-    virtual int requestPriority(int32_t pid, int32_t tid, int32_t prio, bool asynchronous)
+    virtual int requestPriority(int32_t pid, int32_t tid,
+                                int32_t prio, bool isForApp, bool asynchronous)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISchedulingPolicyService::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeInt32(tid);
         data.writeInt32(prio);
+        data.writeBool(isForApp);
         uint32_t flags = asynchronous ? IBinder::FLAG_ONEWAY : 0;
         status_t status = remote()->transact(REQUEST_PRIORITY_TRANSACTION, data, &reply, flags);
         if (status != NO_ERROR) {
diff --git a/media/utils/ISchedulingPolicyService.h b/media/utils/ISchedulingPolicyService.h
index b94b191..1015677 100644
--- a/media/utils/ISchedulingPolicyService.h
+++ b/media/utils/ISchedulingPolicyService.h
@@ -27,7 +27,7 @@
     DECLARE_META_INTERFACE(SchedulingPolicyService);
 
     virtual int         requestPriority(/*pid_t*/int32_t pid, /*pid_t*/int32_t tid,
-                                                int32_t prio, bool asynchronous) = 0;
+                                        int32_t prio, bool isForApp, bool asynchronous) = 0;
 
 };
 
diff --git a/media/utils/SchedulingPolicyService.cpp b/media/utils/SchedulingPolicyService.cpp
index 17ee9bc..d7055ef 100644
--- a/media/utils/SchedulingPolicyService.cpp
+++ b/media/utils/SchedulingPolicyService.cpp
@@ -28,7 +28,7 @@
 static const String16 _scheduling_policy("scheduling_policy");
 static Mutex sMutex;
 
-int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous)
+int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool isForApp, bool asynchronous)
 {
     // FIXME merge duplicated code related to service lookup, caching, and error recovery
     int ret;
@@ -47,7 +47,7 @@
             sSchedulingPolicyService = sps;
             sMutex.unlock();
         }
-        ret = sps->requestPriority(pid, tid, prio, asynchronous);
+        ret = sps->requestPriority(pid, tid, prio, isForApp, asynchronous);
         if (ret != DEAD_OBJECT) {
             break;
         }
diff --git a/media/utils/include/mediautils/SchedulingPolicyService.h b/media/utils/include/mediautils/SchedulingPolicyService.h
index a9870d4..47d8734 100644
--- a/media/utils/include/mediautils/SchedulingPolicyService.h
+++ b/media/utils/include/mediautils/SchedulingPolicyService.h
@@ -24,7 +24,7 @@
 // The asynchronous parameter should be 'true' to return immediately,
 // after the request is enqueued but not necessarily executed.
 // The default value 'false' means to return after request has been enqueued and executed.
-int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool asynchronous = false);
+int requestPriority(pid_t pid, pid_t tid, int32_t prio, bool isForApp, bool asynchronous = false);
 
 }   // namespace android
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index a1d81f9..a57821b 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -613,16 +613,17 @@
     sendConfigEvent_l(configEvent);
 }
 
-void AudioFlinger::ThreadBase::sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio)
+void AudioFlinger::ThreadBase::sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp)
 {
     Mutex::Autolock _l(mLock);
-    sendPrioConfigEvent_l(pid, tid, prio);
+    sendPrioConfigEvent_l(pid, tid, prio, forApp);
 }
 
 // sendPrioConfigEvent_l() must be called with ThreadBase::mLock held
-void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio)
+void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(
+        pid_t pid, pid_t tid, int32_t prio, bool forApp)
 {
-    sp<ConfigEvent> configEvent = (ConfigEvent *)new PrioConfigEvent(pid, tid, prio);
+    sp<ConfigEvent> configEvent = (ConfigEvent *)new PrioConfigEvent(pid, tid, prio, forApp);
     sendConfigEvent_l(configEvent);
 }
 
@@ -682,7 +683,7 @@
         case CFG_EVENT_PRIO: {
             PrioConfigEventData *data = (PrioConfigEventData *)event->mData.get();
             // FIXME Need to understand why this has to be done asynchronously
-            int err = requestPriority(data->mPid, data->mTid, data->mPrio,
+            int err = requestPriority(data->mPid, data->mTid, data->mPrio, data->mForApp,
                     true /*asynchronous*/);
             if (err != 0) {
                 ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
@@ -2017,7 +2018,7 @@
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true /*isForApp*/);
         }
     }
 
@@ -3673,7 +3674,7 @@
         // start the fast mixer
         mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastMixer->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastMixer, false);
         stream()->setHalThreadPriority(kPriorityFastMixer);
 
 #ifdef AUDIO_WATCHDOG
@@ -5936,7 +5937,7 @@
         // start the fast capture
         mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
         pid_t tid = mFastCapture->getTid();
-        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture);
+        sendPrioConfigEvent(getpid_cached, tid, kPriorityFastCapture, false);
         stream()->setHalThreadPriority(kPriorityFastCapture);
 #ifdef AUDIO_WATCHDOG
         // FIXME
@@ -6596,7 +6597,7 @@
             pid_t callingPid = IPCThreadState::self()->getCallingPid();
             // we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
             // so ask activity manager to do this on our behalf
-            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp);
+            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp, true);
         }
     }
 
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 3fb0b07..845e38e 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -126,23 +126,25 @@
 
     class PrioConfigEventData : public ConfigEventData {
     public:
-        PrioConfigEventData(pid_t pid, pid_t tid, int32_t prio) :
-            mPid(pid), mTid(tid), mPrio(prio) {}
+        PrioConfigEventData(pid_t pid, pid_t tid, int32_t prio, bool forApp) :
+            mPid(pid), mTid(tid), mPrio(prio), mForApp(forApp) {}
 
         virtual  void dump(char *buffer, size_t size) {
-            snprintf(buffer, size, "Prio event: pid %d, tid %d, prio %d\n", mPid, mTid, mPrio);
+            snprintf(buffer, size, "Prio event: pid %d, tid %d, prio %d, for app? %d\n",
+                    mPid, mTid, mPrio, mForApp);
         }
 
         const pid_t mPid;
         const pid_t mTid;
         const int32_t mPrio;
+        const bool mForApp;
     };
 
     class PrioConfigEvent : public ConfigEvent {
     public:
-        PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
+        PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp) :
             ConfigEvent(CFG_EVENT_PRIO, true) {
-            mData = new PrioConfigEventData(pid, tid, prio);
+            mData = new PrioConfigEventData(pid, tid, prio, forApp);
         }
         virtual ~PrioConfigEvent() {}
     };
@@ -267,8 +269,8 @@
                 status_t    sendConfigEvent_l(sp<ConfigEvent>& event);
                 void        sendIoConfigEvent(audio_io_config_event event, pid_t pid = 0);
                 void        sendIoConfigEvent_l(audio_io_config_event event, pid_t pid = 0);
-                void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio);
-                void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
+                void        sendPrioConfigEvent(pid_t pid, pid_t tid, int32_t prio, bool forApp);
+                void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio, bool forApp);
                 status_t    sendSetParameterConfigEvent_l(const String8& keyValuePair);
                 status_t    sendCreateAudioPatchConfigEvent(const struct audio_patch *patch,
                                                             audio_patch_handle_t *handle);
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 208dcb6..627c5d1 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2368,7 +2368,7 @@
         // Boost priority of request thread to SCHED_FIFO.
         pid_t requestThreadTid = mRequestThread->getTid();
         res = requestPriority(getpid(), requestThreadTid,
-                kRequestThreadPriority, /*asynchronous*/ false);
+                kRequestThreadPriority, /*isForApp*/ false, /*asynchronous*/ false);
         if (res != OK) {
             ALOGW("Can't set realtime priority for request processing thread: %s (%d)",
                     strerror(-res), res);