From 9cae217050aa1347d4ac5053c305754879e3f97f Mon Sep 17 00:00:00 2001 From: Marco Nelissen Date: Mon, 14 Jan 2013 14:12:05 -0800 Subject: Assign blame for playback wakelocks. Set a work source for the playback wakelock, so that playback is counted against the requesting app instead of the media server. Cherrypicked from master. b/9464621 Change-Id: I7329f88a288a95a582a78005a1c3d16a5a611e31 --- services/audioflinger/AudioFlinger.cpp | 9 +++- services/audioflinger/AudioFlinger.h | 1 + services/audioflinger/PlaybackTracks.h | 10 ++-- services/audioflinger/RecordTracks.h | 3 +- services/audioflinger/Threads.cpp | 95 +++++++++++++++++++++++++++------- services/audioflinger/Threads.h | 8 ++- services/audioflinger/TrackBase.h | 3 ++ services/audioflinger/Tracks.cpp | 36 +++++++++---- 8 files changed, 130 insertions(+), 35 deletions(-) (limited to 'services') diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index a9c9b56..6f6c2b6 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -448,6 +448,7 @@ sp AudioFlinger::createTrack( pid_t tid, int *sessionId, String8& name, + int clientUid, status_t *status) { sp track; @@ -483,6 +484,7 @@ sp AudioFlinger::createTrack( } pid_t pid = IPCThreadState::self()->getCallingPid(); + client = registerPid_l(pid); ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); @@ -510,7 +512,7 @@ sp AudioFlinger::createTrack( ALOGV("createTrack() lSessionId: %d", lSessionId); track = thread->createTrack_l(client, streamType, sampleRate, format, - channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, &lStatus); + channelMask, frameCount, sharedBuffer, lSessionId, flags, tid, clientUid, &lStatus); // move effect chain to this output thread if an effect on same session was waiting // for a track to be created @@ -1284,8 +1286,11 @@ sp AudioFlinger::openRecord( } // create new record track. // The record track uses one track in mHardwareMixerThread by convention. + // TODO: the uid should be passed in as a parameter to openRecord recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask, - frameCount, lSessionId, flags, tid, &lStatus); + frameCount, lSessionId, + IPCThreadState::self()->getCallingUid(), + flags, tid, &lStatus); LOG_ALWAYS_FATAL_IF((recordTrack != 0) != (lStatus == NO_ERROR)); } if (lStatus != NO_ERROR) { diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 2aeb263..53e238e 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -109,6 +109,7 @@ public: pid_t tid, int *sessionId, String8& name, + int clientUid, status_t *status); virtual sp openRecord( diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index a2e2511..43b77f3 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -31,6 +31,7 @@ public: size_t frameCount, const sp& sharedBuffer, int sessionId, + int uid, IAudioFlinger::track_flags_t flags); virtual ~Track(); @@ -165,7 +166,8 @@ class TimedTrack : public Track { audio_channel_mask_t channelMask, size_t frameCount, const sp& sharedBuffer, - int sessionId); + int sessionId, + int uid); virtual ~TimedTrack(); class TimedBuffer { @@ -208,7 +210,8 @@ class TimedTrack : public Track { audio_channel_mask_t channelMask, size_t frameCount, const sp& sharedBuffer, - int sessionId); + int sessionId, + int uid); void timedYieldSamples_l(AudioBufferProvider::Buffer* buffer); void timedYieldSilence_l(uint32_t numFrames, @@ -255,7 +258,8 @@ public: uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - size_t frameCount); + size_t frameCount, + int uid); virtual ~OutputTrack(); virtual status_t start(AudioSystem::sync_event_t event = diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index cd8f70c..57de568 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -28,7 +28,8 @@ public: audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, - int sessionId); + int sessionId, + int uid); virtual ~RecordTrack(); virtual status_t start(AudioSystem::sync_event_t event, int triggerSession); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index 9c8fd1f..ae059fb 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -503,17 +503,7 @@ String16 AudioFlinger::ThreadBase::getWakeLockTag() void AudioFlinger::ThreadBase::acquireWakeLock_l(int uid) { - if (mPowerManager == 0) { - // use checkService() to avoid blocking if power service is not up yet - sp binder = - defaultServiceManager()->checkService(String16("power")); - if (binder == 0) { - ALOGW("Thread %s cannot connect to the power manager service", mName); - } else { - mPowerManager = interface_cast(binder); - binder->linkToDeath(mDeathRecipient); - } - } + getPowerManager_l(); if (mPowerManager != 0) { sp binder = new BBinder(); status_t status; @@ -553,6 +543,41 @@ void AudioFlinger::ThreadBase::releaseWakeLock_l() } } +void AudioFlinger::ThreadBase::updateWakeLockUids(const SortedVector &uids) { + Mutex::Autolock _l(mLock); + updateWakeLockUids_l(uids); +} + +void AudioFlinger::ThreadBase::getPowerManager_l() { + + if (mPowerManager == 0) { + // use checkService() to avoid blocking if power service is not up yet + sp binder = + defaultServiceManager()->checkService(String16("power")); + if (binder == 0) { + ALOGW("Thread %s cannot connect to the power manager service", mName); + } else { + mPowerManager = interface_cast(binder); + binder->linkToDeath(mDeathRecipient); + } + } +} + +void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector &uids) { + + getPowerManager_l(); + if (mWakeLockToken == NULL) { + ALOGE("no wake lock to update!"); + return; + } + if (mPowerManager != 0) { + sp binder = new BBinder(); + status_t status; + status = mPowerManager->updateWakeLockUids(mWakeLockToken, uids.size(), uids.array()); + ALOGV("acquireWakeLock_l() %s status %d", mName, status); + } +} + void AudioFlinger::ThreadBase::clearPowerManager() { Mutex::Autolock _l(mLock); @@ -977,6 +1002,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp& audioFlinge : ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type), mNormalFrameCount(0), mMixBuffer(NULL), mAllocMixBuffer(NULL), mSuspended(0), mBytesWritten(0), + mActiveTracksGeneration(0), // mStreamTypes[] initialized in constructor body mOutput(output), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), @@ -1160,6 +1186,7 @@ sp AudioFlinger::PlaybackThread::createTrac int sessionId, IAudioFlinger::track_flags_t *flags, pid_t tid, + int uid, status_t *status) { sp track; @@ -1293,10 +1320,10 @@ sp AudioFlinger::PlaybackThread::createTrac if (!isTimed) { track = new Track(this, client, streamType, sampleRate, format, - channelMask, frameCount, sharedBuffer, sessionId, *flags); + channelMask, frameCount, sharedBuffer, sessionId, uid, *flags); } else { track = TimedTrack::create(this, client, streamType, sampleRate, format, - channelMask, frameCount, sharedBuffer, sessionId); + channelMask, frameCount, sharedBuffer, sessionId, uid); } if (track == 0 || track->getCblk() == NULL || track->name() < 0) { lStatus = NO_MEMORY; @@ -1432,6 +1459,8 @@ status_t AudioFlinger::PlaybackThread::addTrack_l(const sp& track) track->mResetDone = false; track->mPresentationCompleteFrames = 0; mActiveTracks.add(track); + mWakeLockUids.add(track->uid()); + mActiveTracksGeneration++; sp chain = getEffectChain_l(track->sessionId()); if (chain != 0) { ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(), @@ -2127,6 +2156,8 @@ bool AudioFlinger::PlaybackThread::threadLoop() // FIXME could this be made local to while loop? writeFrames = 0; + int lastGeneration = 0; + cacheParameters_l(); sleepTime = idleSleepTime; @@ -2183,6 +2214,8 @@ bool AudioFlinger::PlaybackThread::threadLoop() break; } releaseWakeLock_l(); + mWakeLockUids.clear(); + mActiveTracksGeneration++; ALOGV("wait async completion"); mWaitWorkCV.wait(mLock); ALOGV("async completion/wake"); @@ -2213,6 +2246,8 @@ bool AudioFlinger::PlaybackThread::threadLoop() } releaseWakeLock_l(); + mWakeLockUids.clear(); + mActiveTracksGeneration++; // wait until we have something to do... ALOGV("%s going to sleep", myName.string()); mWaitWorkCV.wait(mLock); @@ -2237,11 +2272,18 @@ bool AudioFlinger::PlaybackThread::threadLoop() // mMixerStatusIgnoringFastTracks is also updated internally mMixerStatus = prepareTracks_l(&tracksToRemove); + // compare with previously applied list + if (lastGeneration != mActiveTracksGeneration) { + // update wakelock + updateWakeLockUids_l(mWakeLockUids); + lastGeneration = mActiveTracksGeneration; + } + // prevent any changes in effect chain list and in each effect chain // during mixing and effect process as the audio buffers could be deleted // or modified if an effect is created or deleted lockEffectChains_l(effectChains); - } + } // mLock scope ends if (mBytesRemaining == 0) { mCurrentWriteLength = 0; @@ -2351,6 +2393,8 @@ if (mType == MIXER) { } releaseWakeLock(); + mWakeLockUids.clear(); + mActiveTracksGeneration++; ALOGV("Thread %p type %d exiting", this, mType); return false; @@ -2364,6 +2408,8 @@ void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp >& tra for (size_t i=0 ; i& track = tracksToRemove.itemAt(i); mActiveTracks.remove(track); + mWakeLockUids.remove(track->uid()); + mActiveTracksGeneration++; ALOGV("removeTracks_l removing track on session %d", track->sessionId()); sp chain = getEffectChain_l(track->sessionId()); if (chain != 0) { @@ -4213,7 +4259,8 @@ void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) mSampleRate, mFormat, mChannelMask, - frameCount); + frameCount, + IPCThreadState::self()->getCallingUid()); if (outputTrack->cblk() != NULL) { thread->setStreamVolume(AUDIO_STREAM_CNT, 1.0f); mOutputTracks.add(outputTrack); @@ -4315,7 +4362,6 @@ AudioFlinger::RecordThread::RecordThread(const sp& audioFlinger, snprintf(mName, kNameLength, "AudioIn_%X", id); readInputParameters(); - mClientUid = IPCThreadState::self()->getCallingUid(); } @@ -4347,7 +4393,11 @@ bool AudioFlinger::RecordThread::threadLoop() nsecs_t lastWarning = 0; inputStandBy(); - acquireWakeLock(mClientUid); + { + Mutex::Autolock _l(mLock); + activeTrack = mActiveTrack; + acquireWakeLock_l(activeTrack != 0 ? activeTrack->uid() : -1); + } // used to verify we've read at least once before evaluating how many bytes were read bool readOnce = false; @@ -4360,6 +4410,12 @@ bool AudioFlinger::RecordThread::threadLoop() { // scope for mLock Mutex::Autolock _l(mLock); checkForNewParameters_l(); + if (mActiveTrack != 0 && activeTrack != mActiveTrack) { + SortedVector tmp; + tmp.add(mActiveTrack->uid()); + updateWakeLockUids_l(tmp); + } + activeTrack = mActiveTrack; if (mActiveTrack == 0 && mConfigEvents.isEmpty()) { standby(); @@ -4372,7 +4428,7 @@ bool AudioFlinger::RecordThread::threadLoop() // go to sleep mWaitWorkCV.wait(mLock); ALOGV("RecordThread: loop starting"); - acquireWakeLock_l(mClientUid); + acquireWakeLock_l(mActiveTrack != 0 ? mActiveTrack->uid() : -1); continue; } if (mActiveTrack != 0) { @@ -4582,6 +4638,7 @@ sp AudioFlinger::RecordThread::createR audio_channel_mask_t channelMask, size_t frameCount, int sessionId, + int uid, IAudioFlinger::track_flags_t *flags, pid_t tid, status_t *status) @@ -4651,7 +4708,7 @@ sp AudioFlinger::RecordThread::createR Mutex::Autolock _l(mLock); track = new RecordTrack(this, client, sampleRate, - format, channelMask, frameCount, sessionId); + format, channelMask, frameCount, sessionId, uid); if (track->getCblk() == 0) { ALOGE("createRecordTrack_l() no control block"); diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index a5d2169..81804c2 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -241,6 +241,9 @@ protected: void acquireWakeLock_l(int uid = -1); void releaseWakeLock(); void releaseWakeLock_l(); + void updateWakeLockUids(const SortedVector &uids); + void updateWakeLockUids_l(const SortedVector &uids); + void getPowerManager_l(); void setEffectSuspended_l(const effect_uuid_t *type, bool suspend, int sessionId); @@ -421,6 +424,7 @@ public: int sessionId, IAudioFlinger::track_flags_t *flags, pid_t tid, + int uid, status_t *status); AudioStreamOut* getOutput() const; @@ -495,6 +499,8 @@ private: void setMasterMute_l(bool muted) { mMasterMute = muted; } protected: SortedVector< wp > mActiveTracks; // FIXME check if this could be sp<> + SortedVector mWakeLockUids; + int mActiveTracksGeneration; // Allocate a track name for a given channel mask. // Returns name >= 0 if successful, -1 on failure. @@ -873,6 +879,7 @@ public: audio_channel_mask_t channelMask, size_t frameCount, int sessionId, + int uid, IAudioFlinger::track_flags_t *flags, pid_t tid, status_t *status); @@ -953,5 +960,4 @@ private: // For dumpsys const sp mTeeSink; - int mClientUid; }; diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index 523e4b2..cd201d9 100644 --- a/services/audioflinger/TrackBase.h +++ b/services/audioflinger/TrackBase.h @@ -45,6 +45,7 @@ public: size_t frameCount, const sp& sharedBuffer, int sessionId, + int uid, bool isOut); virtual ~TrackBase(); @@ -54,6 +55,7 @@ public: sp getCblk() const { return mCblkMemory; } audio_track_cblk_t* cblk() const { return mCblk; } int sessionId() const { return mSessionId; } + int uid() const { return mUid; } virtual status_t setSyncEvent(const sp& event); protected: @@ -132,6 +134,7 @@ protected: // openRecord(), and then adjusted as needed const int mSessionId; + int mUid; Vector < sp >mSyncEvents; const bool mIsOut; ServerProxy* mServerProxy; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 363bc9d..712c5a1 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -68,6 +68,7 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( size_t frameCount, const sp& sharedBuffer, int sessionId, + int clientUid, bool isOut) : RefBase(), mThread(thread), @@ -88,6 +89,18 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( mId(android_atomic_inc(&nextTrackId)), mTerminated(false) { + // if the caller is us, trust the specified uid + if (IPCThreadState::self()->getCallingPid() != getpid_cached || clientUid == -1) { + int newclientUid = IPCThreadState::self()->getCallingUid(); + if (clientUid != -1 && clientUid != newclientUid) { + ALOGW("uid %d tried to pass itself off as %d", newclientUid, clientUid); + } + clientUid = newclientUid; + } + // clientUid contains the uid of the app that is responsible for this track, so we can blame + // battery usage on it. + mUid = clientUid; + // client == 0 implies sharedBuffer == 0 ALOG_ASSERT(!(client == 0 && sharedBuffer != 0)); @@ -313,9 +326,10 @@ AudioFlinger::PlaybackThread::Track::Track( size_t frameCount, const sp& sharedBuffer, int sessionId, + int uid, IAudioFlinger::track_flags_t flags) : TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, - sessionId, true /*isOut*/), + sessionId, uid, true /*isOut*/), mFillingUpStatus(FS_INVALID), // mRetryCount initialized later when needed mSharedBuffer(sharedBuffer), @@ -963,13 +977,14 @@ AudioFlinger::PlaybackThread::TimedTrack::create( audio_channel_mask_t channelMask, size_t frameCount, const sp& sharedBuffer, - int sessionId) { + int sessionId, + int uid) { if (!client->reserveTimedTrack()) return 0; return new TimedTrack( thread, client, streamType, sampleRate, format, channelMask, frameCount, - sharedBuffer, sessionId); + sharedBuffer, sessionId, uid); } AudioFlinger::PlaybackThread::TimedTrack::TimedTrack( @@ -981,9 +996,10 @@ AudioFlinger::PlaybackThread::TimedTrack::TimedTrack( audio_channel_mask_t channelMask, size_t frameCount, const sp& sharedBuffer, - int sessionId) + int sessionId, + int uid) : Track(thread, client, streamType, sampleRate, format, channelMask, - frameCount, sharedBuffer, sessionId, IAudioFlinger::TRACK_TIMED), + frameCount, sharedBuffer, sessionId, uid, IAudioFlinger::TRACK_TIMED), mQueueHeadInFlight(false), mTrimQueueHeadOnRelease(false), mFramesPendingInQueue(0), @@ -1476,9 +1492,10 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, - size_t frameCount) + size_t frameCount, + int uid) : Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, - NULL, 0, IAudioFlinger::TRACK_DEFAULT), + NULL, 0, uid, IAudioFlinger::TRACK_DEFAULT), mActive(false), mSourceThread(sourceThread), mClientProxy(NULL) { @@ -1738,9 +1755,10 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( audio_format_t format, audio_channel_mask_t channelMask, size_t frameCount, - int sessionId) + int sessionId, + int uid) : TrackBase(thread, client, sampleRate, format, - channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, false /*isOut*/), + channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/), mOverflow(false) { ALOGV("RecordTrack constructor"); -- cgit v1.1