From 462fd2fa9eef642b0574aa7409de0bde3fec8d43 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. 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 | 96 +++++++++++++++++++++++++++------- services/audioflinger/Threads.h | 8 ++- services/audioflinger/TrackBase.h | 3 ++ services/audioflinger/Tracks.cpp | 36 +++++++++---- 8 files changed, 130 insertions(+), 36 deletions(-) (limited to 'services') diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 8fedc7f..360db4f 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -451,6 +451,7 @@ sp AudioFlinger::createTrack( pid_t tid, int *sessionId, String8& name, + int clientUid, status_t *status) { sp track; @@ -486,6 +487,7 @@ sp AudioFlinger::createTrack( } pid_t pid = IPCThreadState::self()->getCallingPid(); + client = registerPid_l(pid); ALOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); @@ -513,7 +515,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); // we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless // move effect chain to this output thread if an effect on same session was waiting @@ -1289,8 +1291,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)); } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index d6b10f7..d244c14 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 /*non-NULL*/); virtual sp openRecord( diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index ae0aba4..4b6c74d 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(); virtual status_t initCheck() const; @@ -166,7 +167,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 { @@ -209,7 +211,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, @@ -256,7 +259,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 a4e1810..5ef6f58 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 44384b8..ff7ccac 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -521,17 +521,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; @@ -571,6 +561,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); @@ -992,6 +1017,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp& audioFlinge : ThreadBase(audioFlinger, id, device, AUDIO_DEVICE_NONE, type), mNormalFrameCount(0), mMixBuffer(NULL), mSuspended(0), mBytesWritten(0), + mActiveTracksGeneration(0), // mStreamTypes[] initialized in constructor body mOutput(output), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), @@ -1165,6 +1191,7 @@ sp AudioFlinger::PlaybackThread::createTrac int sessionId, IAudioFlinger::track_flags_t *flags, pid_t tid, + int uid, status_t *status) { sp track; @@ -1298,10 +1325,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); } // new Track always returns non-NULL, @@ -1439,6 +1466,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(), @@ -2135,6 +2164,8 @@ bool AudioFlinger::PlaybackThread::threadLoop() // FIXME could this be made local to while loop? writeFrames = 0; + int lastGeneration = 0; + cacheParameters_l(); sleepTime = idleSleepTime; @@ -2191,6 +2222,8 @@ bool AudioFlinger::PlaybackThread::threadLoop() break; } releaseWakeLock_l(); + mWakeLockUids.clear(); + mActiveTracksGeneration++; ALOGV("wait async completion"); mWaitWorkCV.wait(mLock); ALOGV("async completion/wake"); @@ -2221,6 +2254,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); @@ -2245,11 +2280,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; @@ -2359,6 +2401,8 @@ if (mType == MIXER) { } releaseWakeLock(); + mWakeLockUids.clear(); + mActiveTracksGeneration++; ALOGV("Thread %p type %d exiting", this, mType); return false; @@ -2372,6 +2416,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) { @@ -4223,7 +4269,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); @@ -4325,7 +4372,6 @@ AudioFlinger::RecordThread::RecordThread(const sp& audioFlinger, snprintf(mName, kNameLength, "AudioIn_%X", id); readInputParameters(); - mClientUid = IPCThreadState::self()->getCallingUid(); } @@ -4348,7 +4394,12 @@ bool AudioFlinger::RecordThread::threadLoop() nsecs_t lastWarning = 0; inputStandBy(); - acquireWakeLock(mClientUid); + sp activeTrack; + { + 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; @@ -4358,7 +4409,6 @@ bool AudioFlinger::RecordThread::threadLoop() // start recording for (;;) { - sp activeTrack; TrackBase::track_state activeTrackState; Vector< sp > effectChains; @@ -4376,6 +4426,11 @@ bool AudioFlinger::RecordThread::threadLoop() processConfigEvents_l(); // return value 'reconfig' is currently unused bool reconfig = checkForNewParameters_l(); + if (mActiveTrack != 0 && activeTrack != mActiveTrack) { + SortedVector tmp; + tmp.add(mActiveTrack->uid()); + updateWakeLockUids_l(tmp); + } // make a stable copy of mActiveTrack activeTrack = mActiveTrack; if (activeTrack == 0) { @@ -4386,7 +4441,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; } @@ -4614,6 +4669,7 @@ sp AudioFlinger::RecordThread::createRe audio_channel_mask_t channelMask, size_t frameCount, int sessionId, + int uid, IAudioFlinger::track_flags_t *flags, pid_t tid, status_t *status) @@ -4683,7 +4739,7 @@ sp AudioFlinger::RecordThread::createRe Mutex::Autolock _l(mLock); track = new RecordTrack(this, client, sampleRate, - format, channelMask, frameCount, sessionId); + format, channelMask, frameCount, sessionId, uid); lStatus = track->initCheck(); if (lStatus != NO_ERROR) { diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h index 4ccbb10..2b4c9fd 100644 --- a/services/audioflinger/Threads.h +++ b/services/audioflinger/Threads.h @@ -244,6 +244,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); @@ -424,6 +427,7 @@ public: int sessionId, IAudioFlinger::track_flags_t *flags, pid_t tid, + int uid, status_t *status /*non-NULL*/); AudioStreamOut* getOutput() const; @@ -497,6 +501,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. @@ -875,6 +881,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 /*non-NULL*/); @@ -954,5 +961,4 @@ private: // For dumpsys const sp mTeeSink; - int mClientUid; }; diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index 00a91b7..05fde7c 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(); virtual status_t initCheck() const { return getCblk() != 0 ? NO_ERROR : NO_MEMORY; } @@ -55,6 +56,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: @@ -124,6 +126,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 656dfbb..9152ea3 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), @@ -972,13 +986,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( @@ -990,9 +1005,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), @@ -1487,9 +1503,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) { @@ -1749,9 +1766,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