diff options
-rw-r--r-- | core/java/android/os/IPowerManager.aidl | 3 | ||||
-rw-r--r-- | data/etc/platform.xml | 1 | ||||
-rw-r--r-- | include/powermanager/IPowerManager.h | 41 | ||||
-rw-r--r-- | include/powermanager/PowerManager.h | 29 | ||||
-rw-r--r-- | services/audioflinger/Android.mk | 3 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 114 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 29 | ||||
-rw-r--r-- | services/powermanager/Android.mk | 15 | ||||
-rw-r--r-- | services/powermanager/IPowerManager.cpp | 71 |
9 files changed, 292 insertions, 14 deletions
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 0067e94..9a53d76 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -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); diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 0b8d40f..05bd626 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -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" /> diff --git a/include/powermanager/IPowerManager.h b/include/powermanager/IPowerManager.h new file mode 100644 index 0000000..1723f04 --- /dev/null +++ b/include/powermanager/IPowerManager.h @@ -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 diff --git a/include/powermanager/PowerManager.h b/include/powermanager/PowerManager.h new file mode 100644 index 0000000..4590174 --- /dev/null +++ b/include/powermanager/PowerManager.h @@ -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 diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index a0407b9..fa49592 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -21,7 +21,8 @@ LOCAL_SHARED_LIBRARIES := \ libhardware \ libhardware_legacy \ libeffects \ - libdl + libdl \ + libpowermanager LOCAL_STATIC_LIBRARIES := \ libcpustats \ diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index cb1f921..95b9918 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -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; } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index e2cf946..edd3e2a 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -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 --- diff --git a/services/powermanager/Android.mk b/services/powermanager/Android.mk new file mode 100644 index 0000000..d98b2da --- /dev/null +++ b/services/powermanager/Android.mk @@ -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) diff --git a/services/powermanager/IPowerManager.cpp b/services/powermanager/IPowerManager.cpp new file mode 100644 index 0000000..a0f19d4 --- /dev/null +++ b/services/powermanager/IPowerManager.cpp @@ -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 |