Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 896adcd3 authored by Eric Laurent's avatar Eric Laurent
Browse files

audioflinger: send priority request from a thread

When creating a fast AudioTrack, a request is sent to SchedulingPolicyService
to elevate the requesting thread priority. This generates a binder
call into system_server process and to a JAVA service via JNI.
If the thread from which the track was created is in the system_server
process and does not have the "can call java" attribute, a crash occurs because
the binder optimization reuses the same thread to process the returning binder
call and no JNI env is present.

The fix consists in sending the priority change request from the AudioFlinger
mixer thread, not from the binder thread.

This also reverts the workaround in commit 73431968

Bug 7126707.

Change-Id: I3347adf71ffbb56ed8436506d4357eab693078a3
parent 4362f530
Loading
Loading
Loading
Loading
+1 −2
Original line number Original line Diff line number Diff line
@@ -279,8 +279,7 @@ status_t AudioTrack::set(
    mCbf = cbf;
    mCbf = cbf;


    if (cbf != NULL) {
    if (cbf != NULL) {
        //FIXME ignoring threadCanCallJava to work around track recreation issue
        mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
        mAudioTrackThread = new AudioTrackThread(*this, true /*threadCanCallJava*/);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
        mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
    }
    }


+49 −30
Original line number Original line Diff line number Diff line
@@ -1063,11 +1063,11 @@ void AudioFlinger::registerClient(const sp<IAudioFlingerClient>& client)
        // the config change is always sent from playback or record threads to avoid deadlock
        // the config change is always sent from playback or record threads to avoid deadlock
        // with AudioSystem::gLock
        // with AudioSystem::gLock
        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
        for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
            mPlaybackThreads.valueAt(i)->sendConfigEvent(AudioSystem::OUTPUT_OPENED);
            mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AudioSystem::OUTPUT_OPENED);
        }
        }


        for (size_t i = 0; i < mRecordThreads.size(); i++) {
        for (size_t i = 0; i < mRecordThreads.size(); i++) {
            mRecordThreads.valueAt(i)->sendConfigEvent(AudioSystem::INPUT_OPENED);
            mRecordThreads.valueAt(i)->sendIoConfigEvent(AudioSystem::INPUT_OPENED);
        }
        }
    }
    }
}
}
@@ -1202,20 +1202,28 @@ status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
    return status;
    return status;
}
}


void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param)
void AudioFlinger::ThreadBase::sendIoConfigEvent(int event, int param)
{
{
    Mutex::Autolock _l(mLock);
    Mutex::Autolock _l(mLock);
    sendConfigEvent_l(event, param);
    sendIoConfigEvent_l(event, param);
}
}


// sendConfigEvent_l() must be called with ThreadBase::mLock held
// sendIoConfigEvent_l() must be called with ThreadBase::mLock held
void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param)
void AudioFlinger::ThreadBase::sendIoConfigEvent_l(int event, int param)
{
{
    ConfigEvent configEvent;
    IoConfigEvent *ioEvent = new IoConfigEvent(event, param);
    configEvent.mEvent = event;
    mConfigEvents.add(static_cast<ConfigEvent *>(ioEvent));
    configEvent.mParam = param;
    ALOGV("sendIoConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param);
    mConfigEvents.add(configEvent);
    mWaitWorkCV.signal();
    ALOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param);
}

// sendPrioConfigEvent_l() must be called with ThreadBase::mLock held
void AudioFlinger::ThreadBase::sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio)
{
    PrioConfigEvent *prioEvent = new PrioConfigEvent(pid, tid, prio);
    mConfigEvents.add(static_cast<ConfigEvent *>(prioEvent));
    ALOGV("sendPrioConfigEvent_l() num events %d pid %d, tid %d prio %d",
          mConfigEvents.size(), pid, tid, prio);
    mWaitWorkCV.signal();
    mWaitWorkCV.signal();
}
}


@@ -1224,14 +1232,31 @@ void AudioFlinger::ThreadBase::processConfigEvents()
    mLock.lock();
    mLock.lock();
    while (!mConfigEvents.isEmpty()) {
    while (!mConfigEvents.isEmpty()) {
        ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
        ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
        ConfigEvent configEvent = mConfigEvents[0];
        ConfigEvent *event = mConfigEvents[0];
        mConfigEvents.removeAt(0);
        mConfigEvents.removeAt(0);
        // release mLock before locking AudioFlinger mLock: lock order is always
        // release mLock before locking AudioFlinger mLock: lock order is always
        // AudioFlinger then ThreadBase to avoid cross deadlock
        // AudioFlinger then ThreadBase to avoid cross deadlock
        mLock.unlock();
        mLock.unlock();
        switch(event->type()) {
            case CFG_EVENT_PRIO: {
                PrioConfigEvent *prioEvent = static_cast<PrioConfigEvent *>(event);
                int err = requestPriority(prioEvent->pid(), prioEvent->tid(), prioEvent->prio());
                if (err != 0) {
                    ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
                          prioEvent->prio(), prioEvent->pid(), prioEvent->tid(), err);
                }
            } break;
            case CFG_EVENT_IO: {
                IoConfigEvent *ioEvent = static_cast<IoConfigEvent *>(event);
                mAudioFlinger->mLock.lock();
                mAudioFlinger->mLock.lock();
        audioConfigChanged_l(configEvent.mEvent, configEvent.mParam);
                audioConfigChanged_l(ioEvent->event(), ioEvent->param());
                mAudioFlinger->mLock.unlock();
                mAudioFlinger->mLock.unlock();
            } break;
            default:
                ALOGE("processConfigEvents() unknown event type %d", event->type());
                break;
        }
        delete event;
        mLock.lock();
        mLock.lock();
    }
    }
    mLock.unlock();
    mLock.unlock();
@@ -1281,10 +1306,8 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)


    snprintf(buffer, SIZE, "\n\nPending config events: \n");
    snprintf(buffer, SIZE, "\n\nPending config events: \n");
    result.append(buffer);
    result.append(buffer);
    snprintf(buffer, SIZE, " Index event param\n");
    result.append(buffer);
    for (size_t i = 0; i < mConfigEvents.size(); i++) {
    for (size_t i = 0; i < mConfigEvents.size(); i++) {
        snprintf(buffer, SIZE, " %02d    %02d    %d\n", i, mConfigEvents[i].mEvent, mConfigEvents[i].mParam);
        mConfigEvents[i]->dump(buffer, SIZE);
        result.append(buffer);
        result.append(buffer);
    }
    }
    result.append("\n");
    result.append("\n");
@@ -1819,16 +1842,12 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
            chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
            chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
            chain->incTrackCnt();
            chain->incTrackCnt();
        }
        }
    }


        if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
        if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
            pid_t callingPid = IPCThreadState::self()->getCallingPid();
            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,
            // 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
            // so ask activity manager to do this on our behalf
        int err = requestPriority(callingPid, tid, kPriorityAudioApp);
            sendPrioConfigEvent_l(callingPid, tid, kPriorityAudioApp);
        if (err != 0) {
            ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
                    kPriorityAudioApp, callingPid, tid, err);
        }
        }
    }
    }


@@ -3506,7 +3525,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
                        mTracks[i]->mCblk->sampleRate = 2 * sampleRate();
                        mTracks[i]->mCblk->sampleRate = 2 * sampleRate();
                    }
                    }
                }
                }
                sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
                sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
            }
            }
        }
        }


@@ -3872,7 +3891,7 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
            }
            }
            if (status == NO_ERROR && reconfig) {
            if (status == NO_ERROR && reconfig) {
                readOutputParameters();
                readOutputParameters();
                sendConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
                sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
            }
            }
        }
        }


@@ -6625,7 +6644,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
                }
                }
                if (status == NO_ERROR) {
                if (status == NO_ERROR) {
                    readInputParameters();
                    readInputParameters();
                    sendConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
                    sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
                }
                }
            }
            }
        }
        }
+56 −6
Original line number Original line Diff line number Diff line
@@ -471,14 +471,63 @@ private:
            Vector < sp<SyncEvent> >mSyncEvents;
            Vector < sp<SyncEvent> >mSyncEvents;
        };
        };


        enum {
            CFG_EVENT_IO,
            CFG_EVENT_PRIO
        };

        class ConfigEvent {
        class ConfigEvent {
        public:
        public:
            ConfigEvent() : mEvent(0), mParam(0) {}
            ConfigEvent(int type) : mType(type) {}
            virtual ~ConfigEvent() {}

                     int type() const { return mType; }


            int mEvent;
            virtual  void dump(char *buffer, size_t size) = 0;
            int mParam;

        private:
            const int mType;
        };
        };


        class IoConfigEvent : public ConfigEvent {
        public:
            IoConfigEvent(int event, int param) :
                ConfigEvent(CFG_EVENT_IO), mEvent(event), mParam(event) {}
            virtual ~IoConfigEvent() {}

                    int event() const { return mEvent; }
                    int param() const { return mParam; }

            virtual  void dump(char *buffer, size_t size) {
                snprintf(buffer, size, "IO event: event %d, param %d\n", mEvent, mParam);
            }

        private:
            const int mEvent;
            const int mParam;
        };

        class PrioConfigEvent : public ConfigEvent {
        public:
            PrioConfigEvent(pid_t pid, pid_t tid, int32_t prio) :
                ConfigEvent(CFG_EVENT_PRIO), mPid(pid), mTid(tid), mPrio(prio) {}
            virtual ~PrioConfigEvent() {}

                    pid_t pid() const { return mPid; }
                    pid_t tid() const { return mTid; }
                    int32_t prio() const { return mPrio; }

            virtual  void dump(char *buffer, size_t size) {
                snprintf(buffer, size, "Prio event: pid %d, tid %d, prio %d\n", mPid, mTid, mPrio);
            }

        private:
            const pid_t mPid;
            const pid_t mTid;
            const int32_t mPrio;
        };


        class PMDeathRecipient : public IBinder::DeathRecipient {
        class PMDeathRecipient : public IBinder::DeathRecipient {
        public:
        public:
                        PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
                        PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
@@ -516,8 +565,9 @@ private:
        virtual     status_t    setParameters(const String8& keyValuePairs);
        virtual     status_t    setParameters(const String8& keyValuePairs);
        virtual     String8     getParameters(const String8& keys) = 0;
        virtual     String8     getParameters(const String8& keys) = 0;
        virtual     void        audioConfigChanged_l(int event, int param = 0) = 0;
        virtual     void        audioConfigChanged_l(int event, int param = 0) = 0;
                    void        sendConfigEvent(int event, int param = 0);
                    void        sendIoConfigEvent(int event, int param = 0);
                    void        sendConfigEvent_l(int event, int param = 0);
                    void        sendIoConfigEvent_l(int event, int param = 0);
                    void        sendPrioConfigEvent_l(pid_t pid, pid_t tid, int32_t prio);
                    void        processConfigEvents();
                    void        processConfigEvents();


                    // see note at declaration of mStandby, mOutDevice and mInDevice
                    // see note at declaration of mStandby, mOutDevice and mInDevice
@@ -666,7 +716,7 @@ private:
                    Vector<String8>         mNewParameters;
                    Vector<String8>         mNewParameters;
                    status_t                mParamStatus;
                    status_t                mParamStatus;


                    Vector<ConfigEvent>     mConfigEvents;
                    Vector<ConfigEvent *>     mConfigEvents;


                    // These fields are written and read by thread itself without lock or barrier,
                    // These fields are written and read by thread itself without lock or barrier,
                    // and read by other threads without lock or barrier via standby() , outDevice()
                    // and read by other threads without lock or barrier via standby() , outDevice()