Fix issue 4604090: notification sound interrupted.

The problem is that the audio HAL fails to acquire the wake lock when playing the notification.
This is because of a change that removed the mediaserver process form the system group for honeycomb.

The fix consists in requesting the wake lock from PowerManagerService when AudioFlinger mixer
wakes up.

A consequence of this change is that audio HALs or pcm drivers do not have to hold wake locks
anymore as in the past.

Change-Id: I4fb3cc84816c9c408ab7fec75886baf801e1ecb5
This commit is contained in:
Eric Laurent
2011-07-22 09:04:31 -07:00
parent 6c454c3225
commit 6dbdc40e9a
9 changed files with 292 additions and 14 deletions

View File

@@ -20,12 +20,15 @@ package android.os;
import android.os.WorkSource;
/** @hide */
interface IPowerManager
{
// WARNING: changes in acquireWakeLock() signature must be reflected in IPowerManager.cpp/h
void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws);
void updateWakeLockWorkSource(IBinder lock, in WorkSource ws);
void goToSleep(long time);
void goToSleepWithReason(long time, int reason);
// WARNING: changes in releaseWakeLock() signature must be reflected in IPowerManager.cpp/h
void releaseWakeLock(IBinder lock, int flags);
void userActivity(long when, boolean noChangeLights);
void userActivityWithForce(long when, boolean noChangeLights, boolean force);

View File

@@ -159,6 +159,7 @@
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="graphics" />

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_IPOWERMANAGER_H
#define ANDROID_IPOWERMANAGER_H
#include <utils/Errors.h>
#include <binder/IInterface.h>
namespace android {
// ----------------------------------------------------------------------------
// must be kept in sync with interface defined in IPowerManager.aidl
class IPowerManager : public IInterface
{
public:
DECLARE_META_INTERFACE(PowerManager);
virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag) = 0;
virtual status_t releaseWakeLock(const sp<IBinder>& lock, int flags) = 0;
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_IPOWERMANAGER_H

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_POWERMANAGER_H
#define ANDROID_POWERMANAGER_H
namespace android {
// must be kept in sync with definitions in PowerManager.java
enum {
POWERMANAGER_PARTIAL_WAKE_LOCK = 1, // equals PowerManager.PARTIAL_WAKE_LOCK constant
};
}; // namespace android
#endif // ANDROID_POWERMANAGER_H

View File

@@ -21,7 +21,8 @@ LOCAL_SHARED_LIBRARIES := \
libhardware \
libhardware_legacy \
libeffects \
libdl
libdl \
libpowermanager
LOCAL_STATIC_LIBRARIES := \
libcpustats \

View File

@@ -53,6 +53,7 @@
#include <audio_effects/effect_visualizer.h>
#include <cpustats/ThreadCpuUsage.h>
#include <powermanager/PowerManager.h>
// #define DEBUG_CPU_USAGE 10 // log statistics every n wall clock seconds
// ----------------------------------------------------------------------------
@@ -887,14 +888,18 @@ void AudioFlinger::removeClient_l(pid_t pid)
AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device)
: Thread(false),
mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false), mDevice(device)
mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false),
mDevice(device)
{
mDeathRecipient = new PMDeathRecipient(this);
}
AudioFlinger::ThreadBase::~ThreadBase()
{
mParamCond.broadcast();
mNewParameters.clear();
// do not lock the mutex in destructor
releaseWakeLock_l();
}
void AudioFlinger::ThreadBase::exit()
@@ -1061,6 +1066,69 @@ status_t AudioFlinger::ThreadBase::dumpEffectChains(int fd, const Vector<String1
return NO_ERROR;
}
void AudioFlinger::ThreadBase::acquireWakeLock()
{
Mutex::Autolock _l(mLock);
acquireWakeLock_l();
}
void AudioFlinger::ThreadBase::acquireWakeLock_l()
{
if (mPowerManager == 0) {
// use checkService() to avoid blocking if power service is not up yet
sp<IBinder> binder =
defaultServiceManager()->checkService(String16("power"));
if (binder == 0) {
LOGW("Thread %s cannot connect to the power manager service", mName);
} else {
mPowerManager = interface_cast<IPowerManager>(binder);
binder->linkToDeath(mDeathRecipient);
}
}
if (mPowerManager != 0) {
sp<IBinder> binder = new BBinder();
status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
binder,
String16(mName));
if (status == NO_ERROR) {
mWakeLockToken = binder;
}
LOGV("acquireWakeLock_l() %s status %d", mName, status);
}
}
void AudioFlinger::ThreadBase::releaseWakeLock()
{
Mutex::Autolock _l(mLock);
releaseWakeLock();
}
void AudioFlinger::ThreadBase::releaseWakeLock_l()
{
if (mWakeLockToken != 0) {
LOGV("releaseWakeLock_l() %s", mName);
if (mPowerManager != 0) {
mPowerManager->releaseWakeLock(mWakeLockToken, 0);
}
mWakeLockToken.clear();
}
}
void AudioFlinger::ThreadBase::clearPowerManager()
{
Mutex::Autolock _l(mLock);
releaseWakeLock_l();
mPowerManager.clear();
}
void AudioFlinger::ThreadBase::PMDeathRecipient::binderDied(const wp<IBinder>& who)
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
thread->clearPowerManager();
}
LOGW("power manager service died !!!");
}
// ----------------------------------------------------------------------------
@@ -1072,6 +1140,8 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
{
snprintf(mName, kNameLength, "AudioOut_%d", id);
readOutputParameters();
mMasterVolume = mAudioFlinger->masterVolume();
@@ -1170,12 +1240,7 @@ status_t AudioFlinger::PlaybackThread::readyToRun()
void AudioFlinger::PlaybackThread::onFirstRef()
{
const size_t SIZE = 256;
char buffer[SIZE];
snprintf(buffer, SIZE, "Playback Thread %p", this);
run(buffer, ANDROID_PRIORITY_URGENT_AUDIO);
run(mName, ANDROID_PRIORITY_URGENT_AUDIO);
}
// PlaybackThread::createTrack_l() must be called with AudioFlinger::mLock held
@@ -1522,6 +1587,8 @@ bool AudioFlinger::MixerThread::threadLoop()
const CentralTendencyStatistics& stats = cpu.statistics();
#endif
acquireWakeLock();
while (!exitPending())
{
#ifdef DEBUG_CPU_USAGE
@@ -1585,10 +1652,12 @@ bool AudioFlinger::MixerThread::threadLoop()
if (exitPending()) break;
releaseWakeLock_l();
// wait until we have something to do...
LOGV("MixerThread %p TID %d going to sleep\n", this, gettid());
mWaitWorkCV.wait(mLock);
LOGV("MixerThread %p TID %d waking up\n", this, gettid());
acquireWakeLock_l();
if (mMasterMute == false) {
char value[PROPERTY_VALUE_MAX];
@@ -1689,6 +1758,8 @@ bool AudioFlinger::MixerThread::threadLoop()
mOutput->stream->common.standby(&mOutput->stream->common);
}
releaseWakeLock();
LOGV("MixerThread %p exiting", this);
return false;
}
@@ -2176,6 +2247,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
// hardware resources as soon as possible
nsecs_t standbyDelay = microseconds(activeSleepTime*2);
acquireWakeLock();
while (!exitPending())
{
bool rampVolume;
@@ -2215,9 +2288,11 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
if (exitPending()) break;
releaseWakeLock_l();
LOGV("DirectOutputThread %p TID %d going to sleep\n", this, gettid());
mWaitWorkCV.wait(mLock);
LOGV("DirectOutputThread %p TID %d waking up in active mode\n", this, gettid());
acquireWakeLock_l();
if (mMasterMute == false) {
char value[PROPERTY_VALUE_MAX];
@@ -2436,6 +2511,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
mOutput->stream->common.standby(&mOutput->stream->common);
}
releaseWakeLock();
LOGV("DirectOutputThread %p exiting", this);
return false;
}
@@ -2561,6 +2638,8 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
uint32_t sleepTime = idleSleepTime;
Vector< sp<EffectChain> > effectChains;
acquireWakeLock();
while (!exitPending())
{
processConfigEvents();
@@ -2601,9 +2680,12 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
if (exitPending()) break;
releaseWakeLock_l();
LOGV("DuplicatingThread %p TID %d going to sleep\n", this, gettid());
mWaitWorkCV.wait(mLock);
LOGV("DuplicatingThread %p TID %d waking up\n", this, gettid());
acquireWakeLock_l();
if (mMasterMute == false) {
char value[PROPERTY_VALUE_MAX];
property_get("ro.audio.silent", value, "0");
@@ -2690,6 +2772,8 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
effectChains.clear();
}
releaseWakeLock();
return false;
}
@@ -3814,6 +3898,9 @@ AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
mInput(input), mTrack(NULL), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
{
mType = ThreadBase::RECORD;
snprintf(mName, kNameLength, "AudioIn_%d", id);
mReqChannelCount = popcount(channels);
mReqSampleRate = sampleRate;
readInputParameters();
@@ -3831,12 +3918,7 @@ AudioFlinger::RecordThread::~RecordThread()
void AudioFlinger::RecordThread::onFirstRef()
{
const size_t SIZE = 256;
char buffer[SIZE];
snprintf(buffer, SIZE, "Record Thread %p", this);
run(buffer, PRIORITY_URGENT_AUDIO);
run(mName, PRIORITY_URGENT_AUDIO);
}
bool AudioFlinger::RecordThread::threadLoop()
@@ -3847,6 +3929,8 @@ bool AudioFlinger::RecordThread::threadLoop()
nsecs_t lastWarning = 0;
acquireWakeLock();
// start recording
while (!exitPending()) {
@@ -3863,10 +3947,12 @@ bool AudioFlinger::RecordThread::threadLoop()
if (exitPending()) break;
releaseWakeLock_l();
LOGV("RecordThread: loop stopping");
// go to sleep
mWaitWorkCV.wait(mLock);
LOGV("RecordThread: loop starting");
acquireWakeLock_l();
continue;
}
if (mActiveTrack != 0) {
@@ -4021,6 +4107,8 @@ bool AudioFlinger::RecordThread::threadLoop()
mStartStopCond.broadcast();
releaseWakeLock();
LOGV("RecordThread %p exiting", this);
return false;
}

View File

@@ -43,6 +43,8 @@
#include "AudioBufferProvider.h"
#include <powermanager/IPowerManager.h>
namespace android {
class audio_track_cblk_t;
@@ -287,6 +289,8 @@ private:
status_t dumpBase(int fd, const Vector<String16>& args);
status_t dumpEffectChains(int fd, const Vector<String16>& args);
void clearPowerManager();
// base for record and playback
class TrackBase : public AudioBufferProvider, public RefBase {
@@ -386,6 +390,21 @@ private:
int mParam;
};
class PMDeathRecipient : public IBinder::DeathRecipient {
public:
PMDeathRecipient(const wp<ThreadBase>& thread) : mThread(thread) {}
virtual ~PMDeathRecipient() {}
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
private:
PMDeathRecipient(const PMDeathRecipient&);
PMDeathRecipient& operator = (const PMDeathRecipient&);
wp<ThreadBase> mThread;
};
virtual status_t initCheck() const = 0;
int type() const { return mType; }
uint32_t sampleRate() const;
@@ -462,6 +481,11 @@ private:
protected:
void acquireWakeLock();
void acquireWakeLock_l();
void releaseWakeLock();
void releaseWakeLock_l();
friend class Track;
friend class TrackBase;
friend class PlaybackThread;
@@ -490,6 +514,11 @@ private:
Vector< sp<EffectChain> > mEffectChains;
uint32_t mDevice; // output device for PlaybackThread
// input + output devices for RecordThread
static const int kNameLength = 32;
char mName[kNameLength];
sp<IPowerManager> mPowerManager;
sp<IBinder> mWakeLockToken;
sp<PMDeathRecipient> mDeathRecipient;
};
// --- PlaybackThread ---

View File

@@ -0,0 +1,15 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
IPowerManager.cpp
LOCAL_SHARED_LIBRARIES := \
libutils \
libbinder
LOCAL_MODULE:= libpowermanager
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "IPowerManager"
//#define LOG_NDEBUG 0
#include <utils/Log.h>
#include <stdint.h>
#include <sys/types.h>
#include <binder/Parcel.h>
#include <powermanager/IPowerManager.h>
namespace android {
// must be kept in sync with IPowerManager.aidl
enum {
ACQUIRE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION,
RELEASE_WAKE_LOCK = IBinder::FIRST_CALL_TRANSACTION + 4,
};
class BpPowerManager : public BpInterface<IPowerManager>
{
public:
BpPowerManager(const sp<IBinder>& impl)
: BpInterface<IPowerManager>(impl)
{
}
virtual status_t acquireWakeLock(int flags, const sp<IBinder>& lock, const String16& tag)
{
Parcel data, reply;
data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
data.writeInt32(flags);
data.writeStrongBinder(lock);
data.writeString16(tag);
// no WorkSource passed
data.writeInt32(0);
return remote()->transact(ACQUIRE_WAKE_LOCK, data, &reply);
}
virtual status_t releaseWakeLock(const sp<IBinder>& lock, int flags)
{
Parcel data, reply;
data.writeInterfaceToken(IPowerManager::getInterfaceDescriptor());
data.writeStrongBinder(lock);
data.writeInt32(flags);
return remote()->transact(RELEASE_WAKE_LOCK, data, &reply);
}
};
IMPLEMENT_META_INTERFACE(PowerManager, "android.os.IPowerManager");
// ----------------------------------------------------------------------------
}; // namespace android