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:
@@ -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);
|
||||
|
||||
@@ -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" />
|
||||
|
||||
|
||||
41
include/powermanager/IPowerManager.h
Normal file
41
include/powermanager/IPowerManager.h
Normal 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
|
||||
29
include/powermanager/PowerManager.h
Normal file
29
include/powermanager/PowerManager.h
Normal 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
|
||||
@@ -21,7 +21,8 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
libhardware \
|
||||
libhardware_legacy \
|
||||
libeffects \
|
||||
libdl
|
||||
libdl \
|
||||
libpowermanager
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcpustats \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
15
services/powermanager/Android.mk
Normal file
15
services/powermanager/Android.mk
Normal 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)
|
||||
71
services/powermanager/IPowerManager.cpp
Normal file
71
services/powermanager/IPowerManager.cpp
Normal 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
|
||||
Reference in New Issue
Block a user