From 6f248bb57a6a0febe8fc0f253acc86289237ace8 Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 23 Jan 2018 14:04:37 -0800 Subject: [PATCH] AudioFlinger: Allocate client memory based on total device memory Test: Debug logging Bug: 64161002 Change-Id: I7156748e5678c3232d1f1672439d11aecf3f458b --- media/libaudioclient/AudioSystem.cpp | 4 +- media/libaudioclient/IAudioFlinger.cpp | 23 ++++++--- .../include/media/AudioSystem.h | 2 +- .../include/media/IAudioFlinger.h | 5 +- services/audioflinger/AudioFlinger.cpp | 51 ++++++++++++++----- services/audioflinger/AudioFlinger.h | 21 ++++---- 6 files changed, 70 insertions(+), 36 deletions(-) diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 50fe385ec8..ba5643fb4f 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -1056,11 +1056,11 @@ size_t AudioSystem::getPrimaryOutputFrameCount() return af->getPrimaryOutputFrameCount(); } -status_t AudioSystem::setLowRamDevice(bool isLowRamDevice) +status_t AudioSystem::setLowRamDevice(bool isLowRamDevice, int64_t totalMemory) { const sp& af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; - return af->setLowRamDevice(isLowRamDevice); + return af->setLowRamDevice(isLowRamDevice, totalMemory); } void AudioSystem::clearAudioConfigCache() diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp index 56ddd4f9e6..0302df61fb 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -697,14 +697,18 @@ public: return reply.readInt64(); } - virtual status_t setLowRamDevice(bool isLowRamDevice) + virtual status_t setLowRamDevice(bool isLowRamDevice, int64_t totalMemory) override { Parcel data, reply; - data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); - data.writeInt32((int) isLowRamDevice); - remote()->transact(SET_LOW_RAM_DEVICE, data, &reply); - return reply.readInt32(); + + static_assert(NO_ERROR == 0, "NO_ERROR must be 0"); + return data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()) + ?: data.writeInt32((int) isLowRamDevice) + ?: data.writeInt64(totalMemory) + ?: remote()->transact(SET_LOW_RAM_DEVICE, data, &reply) + ?: reply.readInt32(); } + virtual status_t listAudioPorts(unsigned int *num_ports, struct audio_port *ports) { @@ -1261,8 +1265,13 @@ status_t BnAudioFlinger::onTransact( } break; case SET_LOW_RAM_DEVICE: { CHECK_INTERFACE(IAudioFlinger, data, reply); - bool isLowRamDevice = data.readInt32() != 0; - reply->writeInt32(setLowRamDevice(isLowRamDevice)); + int32_t isLowRamDevice; + int64_t totalMemory; + const status_t status = + data.readInt32(&isLowRamDevice) ?: + data.readInt64(&totalMemory) ?: + setLowRamDevice(isLowRamDevice != 0, totalMemory); + (void)reply->writeInt32(status); return NO_ERROR; } break; case LIST_AUDIO_PORTS: { diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index 24a6e22ed6..261a7e9372 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -281,7 +281,7 @@ public: static uint32_t getPrimaryOutputSamplingRate(); static size_t getPrimaryOutputFrameCount(); - static status_t setLowRamDevice(bool isLowRamDevice); + static status_t setLowRamDevice(bool isLowRamDevice, int64_t totalMemory); // Check if hw offload is possible for given format, stream type, sample rate, // bit rate, duration, video and streaming or offload property is enabled diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h index 57d9778774..f0417accfe 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -453,8 +453,9 @@ public: // Intended for AudioService to inform AudioFlinger of device's low RAM attribute, // and should be called at most once. For a definition of what "low RAM" means, see - // android.app.ActivityManager.isLowRamDevice(). - virtual status_t setLowRamDevice(bool isLowRamDevice) = 0; + // android.app.ActivityManager.isLowRamDevice(). The totalMemory parameter + // is obtained from android.app.ActivityManager.MemoryInfo.totalMem. + virtual status_t setLowRamDevice(bool isLowRamDevice, int64_t totalMemory) = 0; /* List available audio ports and their attributes */ virtual status_t listAudioPorts(unsigned int *num_ports, diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 2a2f6fc66a..98108f3c5d 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -155,6 +155,8 @@ AudioFlinger::AudioFlinger() mBtNrecIsOff(false), mIsLowRamDevice(true), mIsDeviceTypeKnown(false), + mTotalMemory(0), + mClientSharedHeapSize(kMinimumClientSharedHeapSizeBytes), mGlobalEffectEnableTime(0), mSystemReady(false) { @@ -1497,17 +1499,9 @@ AudioFlinger::Client::Client(const sp& audioFlinger, pid_t pid) mAudioFlinger(audioFlinger), mPid(pid) { - size_t heapSize = property_get_int32("ro.af.client_heap_size_kbyte", 0); - heapSize *= 1024; - if (!heapSize) { - heapSize = kClientSharedHeapSizeBytes; - // Increase heap size on non low ram devices to limit risk of reconnection failure for - // invalidated tracks - if (!audioFlinger->isLowRamDevice()) { - heapSize *= kClientSharedHeapSizeMultiplier; - } - } - mMemoryDealer = new MemoryDealer(heapSize, "AudioFlinger::Client"); + mMemoryDealer = new MemoryDealer( + audioFlinger->getClientSharedHeapSize(), + (std::string("AudioFlinger::Client(") + std::to_string(pid) + ")").c_str()); } // Client destructor must be called with AudioFlinger::mClientLock held @@ -1845,7 +1839,7 @@ size_t AudioFlinger::getPrimaryOutputFrameCount() // ---------------------------------------------------------------------------- -status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice) +status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice, int64_t totalMemory) { uid_t uid = IPCThreadState::self()->getCallingUid(); if (uid != AID_SYSTEM) { @@ -1856,10 +1850,43 @@ status_t AudioFlinger::setLowRamDevice(bool isLowRamDevice) return INVALID_OPERATION; } mIsLowRamDevice = isLowRamDevice; + mTotalMemory = totalMemory; + // mIsLowRamDevice and mTotalMemory are obtained through ActivityManager; + // see ActivityManager.isLowRamDevice() and ActivityManager.getMemoryInfo(). + // mIsLowRamDevice generally represent devices with less than 1GB of memory, + // though actual setting is determined through device configuration. + constexpr int64_t GB = 1024 * 1024 * 1024; + mClientSharedHeapSize = + isLowRamDevice ? kMinimumClientSharedHeapSizeBytes + : mTotalMemory < 2 * GB ? 4 * kMinimumClientSharedHeapSizeBytes + : mTotalMemory < 3 * GB ? 8 * kMinimumClientSharedHeapSizeBytes + : mTotalMemory < 4 * GB ? 16 * kMinimumClientSharedHeapSizeBytes + : 32 * kMinimumClientSharedHeapSizeBytes; mIsDeviceTypeKnown = true; + + // TODO: Cache the client shared heap size in a persistent property. + // It's possible that a native process or Java service or app accesses audioserver + // after it is registered by system server, but before AudioService updates + // the memory info. This would occur immediately after boot or an audioserver + // crash and restore. Before update from AudioService, the client would get the + // minimum heap size. + + ALOGD("isLowRamDevice:%s totalMemory:%lld mClientSharedHeapSize:%zu", + (isLowRamDevice ? "true" : "false"), + (long long)mTotalMemory, + mClientSharedHeapSize.load()); return NO_ERROR; } +size_t AudioFlinger::getClientSharedHeapSize() const +{ + size_t heapSizeInBytes = property_get_int32("ro.af.client_heap_size_kbyte", 0) * 1024; + if (heapSizeInBytes != 0) { // read-only property overrides all. + return heapSizeInBytes; + } + return mClientSharedHeapSize; +} + audio_hw_sync_t AudioFlinger::getAudioHwSyncForSession(audio_session_t sessionId) { Mutex::Autolock _l(mLock); diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 5a64f0bc53..fc8af08feb 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -94,12 +94,6 @@ class ServerProxy; static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3); - -// Max shared memory size for audio tracks and audio records per client process -static const size_t kClientSharedHeapSizeBytes = 1024*1024; -// Shared memory size multiplier for non low ram devices -static const size_t kClientSharedHeapSizeMultiplier = 4; - #define INCLUDING_FROM_AUDIOFLINGER_H class AudioFlinger : @@ -225,7 +219,7 @@ public: virtual uint32_t getPrimaryOutputSamplingRate(); virtual size_t getPrimaryOutputFrameCount(); - virtual status_t setLowRamDevice(bool isLowRamDevice); + virtual status_t setLowRamDevice(bool isLowRamDevice, int64_t totalMemory) override; /* List available audio ports and their attributes */ virtual status_t listAudioPorts(unsigned int *num_ports, @@ -827,15 +821,18 @@ public: static const size_t kTeeSinkTrackFramesDefault = 0x200000; #endif - // This method reads from a variable without mLock, but the variable is updated under mLock. So - // we might read a stale value, or a value that's inconsistent with respect to other variables. - // In this case, it's safe because the return value isn't used for making an important decision. - // The reason we don't want to take mLock is because it could block the caller for a long time. + // These methods read variables atomically without mLock, + // though the variables are updated with mLock. bool isLowRamDevice() const { return mIsLowRamDevice; } + size_t getClientSharedHeapSize() const; private: - bool mIsLowRamDevice; + std::atomic mIsLowRamDevice; bool mIsDeviceTypeKnown; + int64_t mTotalMemory; + std::atomic mClientSharedHeapSize; + static constexpr size_t kMinimumClientSharedHeapSizeBytes = 1024 * 1024; // 1MB + nsecs_t mGlobalEffectEnableTime; // when a global effect was last enabled sp mPatchPanel;