summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2012-09-13 11:18:23 -0700
committerEric Laurent <elaurent@google.com>2012-09-13 17:03:00 -0700
commit896adcd3ae6a1c7010e526327eff54e16179987b (patch)
tree8c999b21698b1b7b45ac1d290ef3c64c808f380d
parent4362f5300162ed55f56cf167eccf7f2e5b89d435 (diff)
downloadframeworks_av-896adcd3ae6a1c7010e526327eff54e16179987b.zip
frameworks_av-896adcd3ae6a1c7010e526327eff54e16179987b.tar.gz
frameworks_av-896adcd3ae6a1c7010e526327eff54e16179987b.tar.bz2
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
-rw-r--r--media/libmedia/AudioTrack.cpp3
-rw-r--r--services/audioflinger/AudioFlinger.cpp79
-rw-r--r--services/audioflinger/AudioFlinger.h62
3 files changed, 106 insertions, 38 deletions
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index d9d8aee..362d022 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -279,8 +279,7 @@ status_t AudioTrack::set(
mCbf = cbf;
if (cbf != NULL) {
- //FIXME ignoring threadCanCallJava to work around track recreation issue
- mAudioTrackThread = new AudioTrackThread(*this, true /*threadCanCallJava*/);
+ mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/);
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 582ab65..de116a9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -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
// with AudioSystem::gLock
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++) {
- 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;
}
-void AudioFlinger::ThreadBase::sendConfigEvent(int event, int param)
+void AudioFlinger::ThreadBase::sendIoConfigEvent(int event, int param)
{
Mutex::Autolock _l(mLock);
- sendConfigEvent_l(event, param);
+ sendIoConfigEvent_l(event, param);
}
-// sendConfigEvent_l() must be called with ThreadBase::mLock held
-void AudioFlinger::ThreadBase::sendConfigEvent_l(int event, int param)
+// sendIoConfigEvent_l() must be called with ThreadBase::mLock held
+void AudioFlinger::ThreadBase::sendIoConfigEvent_l(int event, int param)
{
- ConfigEvent configEvent;
- configEvent.mEvent = event;
- configEvent.mParam = param;
- mConfigEvents.add(configEvent);
- ALOGV("sendConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param);
+ IoConfigEvent *ioEvent = new IoConfigEvent(event, param);
+ mConfigEvents.add(static_cast<ConfigEvent *>(ioEvent));
+ ALOGV("sendIoConfigEvent() num events %d event %d, param %d", mConfigEvents.size(), event, param);
+ mWaitWorkCV.signal();
+}
+
+// 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();
}
@@ -1224,14 +1232,31 @@ void AudioFlinger::ThreadBase::processConfigEvents()
mLock.lock();
while (!mConfigEvents.isEmpty()) {
ALOGV("processConfigEvents() remaining events %d", mConfigEvents.size());
- ConfigEvent configEvent = mConfigEvents[0];
+ ConfigEvent *event = mConfigEvents[0];
mConfigEvents.removeAt(0);
// release mLock before locking AudioFlinger mLock: lock order is always
// AudioFlinger then ThreadBase to avoid cross deadlock
mLock.unlock();
- mAudioFlinger->mLock.lock();
- audioConfigChanged_l(configEvent.mEvent, configEvent.mParam);
- mAudioFlinger->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();
+ audioConfigChanged_l(ioEvent->event(), ioEvent->param());
+ mAudioFlinger->mLock.unlock();
+ } break;
+ default:
+ ALOGE("processConfigEvents() unknown event type %d", event->type());
+ break;
+ }
+ delete event;
mLock.lock();
}
mLock.unlock();
@@ -1281,10 +1306,8 @@ void AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args)
snprintf(buffer, SIZE, "\n\nPending config events: \n");
result.append(buffer);
- snprintf(buffer, SIZE, " Index event param\n");
- result.append(buffer);
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("\n");
@@ -1819,16 +1842,12 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTrac
chain->setStrategy(AudioSystem::getStrategyForStream(track->streamType()));
chain->incTrackCnt();
}
- }
- if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
- 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
- int err = requestPriority(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);
+ if ((flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
+ 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);
}
}
@@ -3506,7 +3525,7 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l()
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) {
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) {
readInputParameters();
- sendConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
+ sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
}
}
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index c956861..8a020fa 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -471,14 +471,63 @@ private:
Vector < sp<SyncEvent> >mSyncEvents;
};
+ enum {
+ CFG_EVENT_IO,
+ CFG_EVENT_PRIO
+ };
+
class ConfigEvent {
public:
- ConfigEvent() : mEvent(0), mParam(0) {}
+ ConfigEvent(int type) : mType(type) {}
+ virtual ~ConfigEvent() {}
+
+ int type() const { return mType; }
+
+ virtual void dump(char *buffer, size_t size) = 0;
+
+ 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() {}
- int mEvent;
- int mParam;
+ 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 {
public:
PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
@@ -516,8 +565,9 @@ private:
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys) = 0;
virtual void audioConfigChanged_l(int event, int param = 0) = 0;
- void sendConfigEvent(int event, int param = 0);
- void sendConfigEvent_l(int event, int param = 0);
+ void sendIoConfigEvent(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();
// see note at declaration of mStandby, mOutDevice and mInDevice
@@ -666,7 +716,7 @@ private:
Vector<String8> mNewParameters;
status_t mParamStatus;
- Vector<ConfigEvent> mConfigEvents;
+ Vector<ConfigEvent *> mConfigEvents;
// 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()