diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 7969ed0005..3bb09d2d9d 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -1059,11 +1059,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 6507a5cf4c..ae9c96fe72 100644 --- a/media/libaudioclient/IAudioFlinger.cpp +++ b/media/libaudioclient/IAudioFlinger.cpp @@ -707,14 +707,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) { @@ -1281,8 +1285,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 e4528371b6..f7c3d039be 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -285,7 +285,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 472a3daa67..e8d405b42d 100644 --- a/media/libaudioclient/include/media/IAudioFlinger.h +++ b/media/libaudioclient/include/media/IAudioFlinger.h @@ -454,8 +454,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 686e3e3798..e362530e7b 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) { @@ -1512,17 +1514,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 @@ -1860,7 +1854,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) { @@ -1871,10 +1865,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 a1c3f360b4..296f0924f9 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 : @@ -227,7 +221,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, @@ -829,15 +823,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;