Merge "Release AudioTrackCallback when the track is removed."
diff --git a/apex/TEST_MAPPING b/apex/TEST_MAPPING
index f036516..09c46d6 100644
--- a/apex/TEST_MAPPING
+++ b/apex/TEST_MAPPING
@@ -14,17 +14,9 @@
},
{
"include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
- }
- ]
- },
- {
- "name": "GtsExoPlayerTestCases",
- "options" : [
- {
- "include-annotation": "android.platform.test.annotations.SocPresubmit"
},
{
- "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+ "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
}
]
}
diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING
index 2595e3e..9f6a532 100644
--- a/drm/TEST_MAPPING
+++ b/drm/TEST_MAPPING
@@ -9,17 +9,9 @@
},
{
"include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
- }
- ]
- },
- {
- "name": "GtsExoPlayerTestCases",
- "options" : [
- {
- "include-annotation": "android.platform.test.annotations.SocPresubmit"
},
{
- "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+ "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
}
]
}
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 9a32cc5..74e3223 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -99,13 +99,13 @@
}
default:
{
- ALOGW("Unrecognized message type: %zd", msg->what());
+ ALOGW("Unrecognized message type: %u", msg->what());
}
}
}
int64_t DrmManager::getMetricsFlushPeriodUs() {
- return 1000 * 1000 * std::max(1ll, property_get_int64("drmmanager.metrics.period", 86400));
+ return 1000 * 1000 * std::max(1ll, (long long)property_get_int64("drmmanager.metrics.period", 86400));
}
void DrmManager::recordEngineMetrics(
diff --git a/include/drm/TEST_MAPPING b/include/drm/TEST_MAPPING
index 28e432e..512e844 100644
--- a/include/drm/TEST_MAPPING
+++ b/include/drm/TEST_MAPPING
@@ -8,17 +8,9 @@
},
{
"include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
- }
- ]
- },
- {
- "name": "GtsExoPlayerTestCases",
- "options" : [
- {
- "include-annotation": "android.platform.test.annotations.SocPresubmit"
},
{
- "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+ "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
}
]
}
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index b006f38..50facfb 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -26,17 +26,9 @@
},
{
"include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
- }
- ]
- },
- {
- "name": "GtsExoPlayerTestCases",
- "options" : [
- {
- "include-annotation": "android.platform.test.annotations.SocPresubmit"
},
{
- "include-filter": "com.google.android.exoplayer.gts.DashTest#testWidevine23FpsH264Fixed"
+ "include-filter": "com.google.android.media.gts.WidevineYouTubePerformanceTests"
}
]
}
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index c49a16c..3c99bf6 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -91,7 +91,9 @@
newFormat->setInt32(KEY_STRIDE, stride);
ALOGD("[%s] updating stride = %d", mName, stride);
if (img->mNumPlanes > 1 && stride > 0) {
- int32_t vstride = (img->mPlane[1].mOffset - img->mPlane[0].mOffset) / stride;
+ int64_t offsetDelta =
+ (int64_t)img->mPlane[1].mOffset - (int64_t)img->mPlane[0].mOffset;
+ int32_t vstride = int32_t(offsetDelta / stride);
newFormat->setInt32(KEY_SLICE_HEIGHT, vstride);
ALOGD("[%s] updating vstride = %d", mName, vstride);
}
diff --git a/media/libmedia/MediaResource.cpp b/media/libmedia/MediaResource.cpp
index fe86d27..ec52a49 100644
--- a/media/libmedia/MediaResource.cpp
+++ b/media/libmedia/MediaResource.cpp
@@ -43,11 +43,11 @@
}
//static
-MediaResource MediaResource::CodecResource(bool secure, bool video) {
+MediaResource MediaResource::CodecResource(bool secure, bool video, int64_t instanceCount) {
return MediaResource(
secure ? Type::kSecureCodec : Type::kNonSecureCodec,
video ? SubType::kVideoCodec : SubType::kAudioCodec,
- 1);
+ instanceCount);
}
//static
diff --git a/media/libmedia/include/media/MediaResource.h b/media/libmedia/include/media/MediaResource.h
index 4927d28..4712528 100644
--- a/media/libmedia/include/media/MediaResource.h
+++ b/media/libmedia/include/media/MediaResource.h
@@ -37,7 +37,7 @@
MediaResource(Type type, SubType subType, int64_t value);
MediaResource(Type type, const std::vector<uint8_t> &id, int64_t value);
- static MediaResource CodecResource(bool secure, bool video);
+ static MediaResource CodecResource(bool secure, bool video, int64_t instanceCount = 1);
static MediaResource GraphicMemoryResource(int64_t value);
static MediaResource CpuBoostResource();
static MediaResource VideoBatteryResource();
diff --git a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
index fbed5c2..4730be3 100644
--- a/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
+++ b/media/libmediatranscoding/transcoder/MediaTranscoder.cpp
@@ -282,7 +282,7 @@
format = std::shared_ptr<AMediaFormat>(mergedFormat, &AMediaFormat_delete);
}
- transcoder->configure(mSampleReader, trackIndex, format);
+ status = transcoder->configure(mSampleReader, trackIndex, format);
if (status != AMEDIA_OK) {
LOG(ERROR) << "Configure track transcoder for track #" << trackIndex << " returned error "
<< status;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 382491e..d2f347c 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -2238,6 +2238,12 @@
}
err = setupG711Codec(encoder, sampleRate, numChannels);
}
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_OPUS)) {
+ int32_t numChannels = 1, sampleRate = 48000;
+ if (msg->findInt32("channel-count", &numChannels) &&
+ msg->findInt32("sample-rate", &sampleRate)) {
+ err = setupOpusCodec(encoder, sampleRate, numChannels);
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
// numChannels needs to be set to properly communicate PCM values.
int32_t numChannels = 2, sampleRate = 44100, compressionLevel = -1;
@@ -3117,6 +3123,26 @@
kPortIndexInput, sampleRate, numChannels);
}
+status_t ACodec::setupOpusCodec(bool encoder, int32_t sampleRate, int32_t numChannels) {
+ if (encoder) {
+ return INVALID_OPERATION;
+ }
+ OMX_AUDIO_PARAM_ANDROID_OPUSTYPE def;
+ InitOMXParams(&def);
+ def.nPortIndex = kPortIndexInput;
+ status_t err = mOMXNode->getParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus, &def, sizeof(def));
+ if (err != OK) {
+ ALOGE("setupOpusCodec(): Error %d getting OMX_IndexParamAudioAndroidOpus parameter", err);
+ return err;
+ }
+ def.nSampleRate = sampleRate;
+ def.nChannels = numChannels;
+ err = mOMXNode->setParameter(
+ (OMX_INDEXTYPE)OMX_IndexParamAudioAndroidOpus, &def, sizeof(def));
+ return err;
+}
+
status_t ACodec::setupFlacCodec(
bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
AudioEncoding encoding) {
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index 4f61aa8..5bb1879 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -58,6 +58,8 @@
mInputBufferCount(0),
mDecoder(NULL),
mHeader(NULL),
+ mNumChannels(1),
+ mSamplingRate(kRate),
mCodecDelay(0),
mSeekPreRoll(0),
mAnchorTimeUs(0),
@@ -169,11 +171,11 @@
}
opusParams->nAudioBandWidth = 0;
- opusParams->nSampleRate = kRate;
+ opusParams->nSampleRate = mSamplingRate;
opusParams->nBitRate = 0;
if (!isConfigured()) {
- opusParams->nChannels = 1;
+ opusParams->nChannels = mNumChannels;
} else {
opusParams->nChannels = mHeader->channels;
}
@@ -274,7 +276,8 @@
if (opusParams->nPortIndex != 0) {
return OMX_ErrorUndefined;
}
-
+ mNumChannels = opusParams->nChannels;
+ mSamplingRate = opusParams->nSampleRate;
return OMX_ErrorNone;
}
@@ -496,6 +499,8 @@
*(reinterpret_cast<int64_t*>(inHeader->pBuffer +
inHeader->nOffset)),
kRate);
+ mSamplingRate = kRate;
+ mNumChannels = mHeader->channels;
notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
mOutputPortSettingsChange = AWAITING_DISABLED;
}
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.h b/media/libstagefright/codecs/opus/dec/SoftOpus.h
index 91cafa1..00058c8 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.h
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.h
@@ -70,6 +70,8 @@
OpusMSDecoder *mDecoder;
OpusHeader *mHeader;
+ int32_t mNumChannels;
+ int32_t mSamplingRate;
int64_t mCodecDelay;
int64_t mSeekPreRoll;
int64_t mSamplesToDiscard;
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index cc40f76..797ba31 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -500,6 +500,7 @@
status_t setupAMRCodec(bool encoder, bool isWAMR, int32_t bitRate);
status_t setupG711Codec(bool encoder, int32_t sampleRate, int32_t numChannels);
+ status_t setupOpusCodec(bool encoder, int32_t sampleRate, int32_t numChannels);
status_t setupFlacCodec(
bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel,
AudioEncoding encoding);
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index b28381b..dcdc035 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -91,7 +91,7 @@
<!-- Output devices declaration, i.e. Sink DEVICE PORT -->
<devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
- samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
</devicePort>
<devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
diff --git a/services/audiopolicy/config/audio_policy_configuration_7_0.xml b/services/audiopolicy/config/audio_policy_configuration_7_0.xml
index 6087bf2..a9ecff3 100644
--- a/services/audiopolicy/config/audio_policy_configuration_7_0.xml
+++ b/services/audiopolicy/config/audio_policy_configuration_7_0.xml
@@ -91,7 +91,7 @@
<!-- Output devices declaration, i.e. Sink DEVICE PORT -->
<devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
- samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/>
</devicePort>
<devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address="">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 346ee52..96f2108 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -11,6 +11,19 @@
path: "aidl",
}
+filegroup {
+ name: "resourceobserver_aidl",
+ srcs: [
+ "aidl/android/media/IResourceObserver.aidl",
+ "aidl/android/media/IResourceObserverService.aidl",
+ "aidl/android/media/MediaObservableEvent.aidl",
+ "aidl/android/media/MediaObservableFilter.aidl",
+ "aidl/android/media/MediaObservableType.aidl",
+ "aidl/android/media/MediaObservableParcel.aidl",
+ ],
+ path: "aidl",
+}
+
aidl_interface {
name: "resourcemanager_aidl_interface",
unstable: true,
@@ -20,11 +33,21 @@
],
}
+aidl_interface {
+ name: "resourceobserver_aidl_interface",
+ unstable: true,
+ local_include_dir: "aidl",
+ srcs: [
+ ":resourceobserver_aidl",
+ ],
+}
+
cc_library {
name: "libresourcemanagerservice",
srcs: [
"ResourceManagerService.cpp",
+ "ResourceObserverService.cpp",
"ServiceLog.cpp",
],
@@ -35,6 +58,7 @@
"libbinder_ndk",
"libutils",
"liblog",
+ "resourceobserver_aidl_interface-ndk_platform",
],
include_dirs: ["frameworks/av/include"],
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 3d36f8e..7ee52c5 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -36,6 +36,7 @@
#include <unistd.h>
#include "ResourceManagerService.h"
+#include "ResourceObserverService.h"
#include "ServiceLog.h"
namespace android {
@@ -267,6 +268,13 @@
if (status != STATUS_OK) {
return;
}
+
+ std::shared_ptr<ResourceObserverService> observerService =
+ ResourceObserverService::instantiate();
+
+ if (observerService != nullptr) {
+ service->setObserverService(observerService);
+ }
// TODO: mediaserver main() is already starting the thread pool,
// move this to mediaserver main() when other services in mediaserver
// are converted to ndk-platform aidl.
@@ -275,6 +283,11 @@
ResourceManagerService::~ResourceManagerService() {}
+void ResourceManagerService::setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService) {
+ mObserverService = observerService;
+}
+
Status ResourceManagerService::config(const std::vector<MediaResourcePolicyParcel>& policies) {
String8 log = String8::format("config(%s)", getString(policies).string());
mServiceLog->add(log);
@@ -358,6 +371,7 @@
}
ResourceInfos& infos = getResourceInfosForEdit(pid, mMap);
ResourceInfo& info = getResourceInfoForEdit(uid, clientId, client, infos);
+ ResourceList resourceAdded;
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
@@ -379,12 +393,22 @@
} else {
mergeResources(info.resources[resType], res);
}
+ // Add it to the list of added resources for observers.
+ auto it = resourceAdded.find(resType);
+ if (it == resourceAdded.end()) {
+ resourceAdded[resType] = res;
+ } else {
+ mergeResources(it->second, res);
+ }
}
if (info.deathNotifier == nullptr && client != nullptr) {
info.deathNotifier = new DeathNotifier(ref<ResourceManagerService>(), pid, clientId);
AIBinder_linkToDeath(client->asBinder().get(),
mDeathRecipient.get(), info.deathNotifier.get());
}
+ if (mObserverService != nullptr && !resourceAdded.empty()) {
+ mObserverService->onResourceAdded(uid, pid, resourceAdded);
+ }
notifyResourceGranted(pid, resources);
return Status::ok();
}
@@ -415,7 +439,7 @@
}
ResourceInfo &info = infos.editValueAt(index);
-
+ ResourceList resourceRemoved;
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
const auto resType = std::tuple(res.type, res.subType, res.id);
@@ -427,14 +451,27 @@
// ignore if we don't have it
if (info.resources.find(resType) != info.resources.end()) {
MediaResourceParcel &resource = info.resources[resType];
+ MediaResourceParcel actualRemoved = res;
if (resource.value > res.value) {
resource.value -= res.value;
} else {
onLastRemoved(res, info);
info.resources.erase(resType);
+ actualRemoved.value = resource.value;
+ }
+
+ // Add it to the list of removed resources for observers.
+ auto it = resourceRemoved.find(resType);
+ if (it == resourceRemoved.end()) {
+ resourceRemoved[resType] = actualRemoved;
+ } else {
+ mergeResources(it->second, actualRemoved);
}
}
}
+ if (mObserverService != nullptr && !resourceRemoved.empty()) {
+ mObserverService->onResourceRemoved(info.uid, pid, resourceRemoved);
+ }
return Status::ok();
}
@@ -475,6 +512,10 @@
AIBinder_unlinkToDeath(info.client->asBinder().get(),
mDeathRecipient.get(), info.deathNotifier.get());
+ if (mObserverService != nullptr && !info.resources.empty()) {
+ mObserverService->onResourceRemoved(info.uid, pid, info.resources);
+ }
+
infos.removeItemsAt(index);
return Status::ok();
}
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 49c247e..2b3dab3 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -33,6 +33,7 @@
class DeathNotifier;
class ResourceManagerService;
+class ResourceObserverService;
class ServiceLog;
struct ProcessInfoInterface;
@@ -95,6 +96,8 @@
const sp<ProcessInfoInterface> &processInfo,
const sp<SystemCallbackInterface> &systemResource);
virtual ~ResourceManagerService();
+ void setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService);
// IResourceManagerService interface
Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
@@ -180,6 +183,7 @@
int32_t mCpuBoostCount;
::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
std::map<int, int> mOverridePidMap;
+ std::shared_ptr<ResourceObserverService> mObserverService;
};
// ----------------------------------------------------------------------------
diff --git a/services/mediaresourcemanager/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
new file mode 100644
index 0000000..7c4c875
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -0,0 +1,312 @@
+/**
+ *
+ * Copyright 2020, 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_NDEBUG 0
+#define LOG_TAG "ResourceObserverService"
+#include <utils/Log.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <binder/IServiceManager.h>
+#include <utils/String16.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+
+#include "ResourceObserverService.h"
+
+namespace aidl {
+namespace android {
+namespace media {
+bool operator<(const MediaObservableFilter& lhs, const MediaObservableFilter &rhs) {
+ return lhs.type < rhs.type || (lhs.type == rhs.type && lhs.eventFilter < rhs.eventFilter);
+}
+}}} // namespace ::aidl::android::media
+
+namespace android {
+
+using ::aidl::android::media::MediaResourceParcel;
+using ::aidl::android::media::MediaObservableEvent;
+
+// MediaObservableEvent will be used as uint64_t flags.
+static_assert(sizeof(MediaObservableEvent) == sizeof(uint64_t));
+
+static std::vector<MediaObservableEvent> sEvents = {
+ MediaObservableEvent::kBusy,
+ MediaObservableEvent::kIdle,
+};
+
+static MediaObservableType getObservableType(const MediaResourceParcel& res) {
+ if (res.subType == MediaResourceSubType::kVideoCodec) {
+ if (res.type == MediaResourceType::kNonSecureCodec) {
+ return MediaObservableType::kVideoNonSecureCodec;
+ }
+ if (res.type == MediaResourceType::kSecureCodec) {
+ return MediaObservableType::kVideoSecureCodec;
+ }
+ }
+ return MediaObservableType::kInvalid;
+}
+
+//static
+std::mutex ResourceObserverService::sDeathRecipientLock;
+//static
+std::map<uintptr_t, std::shared_ptr<ResourceObserverService::DeathRecipient> >
+ResourceObserverService::sDeathRecipientMap;
+
+struct ResourceObserverService::DeathRecipient {
+ DeathRecipient(ResourceObserverService* _service,
+ const std::shared_ptr<IResourceObserver>& _observer)
+ : service(_service), observer(_observer) {}
+ ~DeathRecipient() {}
+
+ void binderDied() {
+ if (service != nullptr) {
+ service->unregisterObserver(observer);
+ }
+ }
+
+ ResourceObserverService* service;
+ std::shared_ptr<IResourceObserver> observer;
+};
+
+// static
+void ResourceObserverService::BinderDiedCallback(void* cookie) {
+ uintptr_t id = reinterpret_cast<uintptr_t>(cookie);
+
+ ALOGW("Observer %lld is dead", (long long)id);
+
+ std::shared_ptr<DeathRecipient> recipient;
+
+ {
+ std::scoped_lock lock{sDeathRecipientLock};
+
+ auto it = sDeathRecipientMap.find(id);
+ if (it != sDeathRecipientMap.end()) {
+ recipient = it->second;
+ }
+ }
+
+ if (recipient != nullptr) {
+ recipient->binderDied();
+ }
+}
+
+//static
+std::shared_ptr<ResourceObserverService> ResourceObserverService::instantiate() {
+ std::shared_ptr<ResourceObserverService> observerService =
+ ::ndk::SharedRefBase::make<ResourceObserverService>();
+ binder_status_t status = AServiceManager_addService(observerService->asBinder().get(),
+ ResourceObserverService::getServiceName());
+ if (status != STATUS_OK) {
+ return nullptr;
+ }
+ return observerService;
+}
+
+ResourceObserverService::ResourceObserverService()
+ : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {}
+
+binder_status_t ResourceObserverService::dump(
+ int fd, const char** /*args*/, uint32_t /*numArgs*/) {
+ String8 result;
+
+ if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+ result.format("Permission Denial: "
+ "can't dump ResourceManagerService from pid=%d, uid=%d\n",
+ AIBinder_getCallingPid(),
+ AIBinder_getCallingUid());
+ write(fd, result.string(), result.size());
+ return PERMISSION_DENIED;
+ }
+
+ result.appendFormat("ResourceObserverService: %p\n", this);
+ result.appendFormat(" Registered Observers: %zu\n", mObserverInfoMap.size());
+
+ {
+ std::scoped_lock lock{mObserverLock};
+
+ for (auto &observer : mObserverInfoMap) {
+ result.appendFormat(" Observer %p:\n", observer.second.binder.get());
+ for (auto &observable : observer.second.filters) {
+ String8 enabledEventsStr;
+ for (auto &event : sEvents) {
+ if (((uint64_t)observable.eventFilter & (uint64_t)event) != 0) {
+ if (!enabledEventsStr.isEmpty()) {
+ enabledEventsStr.append("|");
+ }
+ enabledEventsStr.append(toString(event).c_str());
+ }
+ }
+ result.appendFormat(" %s: %s\n",
+ toString(observable.type).c_str(), enabledEventsStr.c_str());
+ }
+ }
+ }
+
+ write(fd, result.string(), result.size());
+ return OK;
+}
+
+Status ResourceObserverService::registerObserver(
+ const std::shared_ptr<IResourceObserver>& in_observer,
+ const std::vector<MediaObservableFilter>& in_filters) {
+ // TODO(chz): Guard this by a permission.
+
+ ::ndk::SpAIBinder binder = in_observer->asBinder();
+
+ {
+ std::scoped_lock lock{mObserverLock};
+
+ if (mObserverInfoMap.find((uintptr_t)binder.get()) != mObserverInfoMap.end()) {
+ return Status::fromServiceSpecificError(ALREADY_EXISTS);
+ }
+
+ if (in_filters.empty()) {
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+
+ // Add observer info.
+ mObserverInfoMap.emplace((uintptr_t)binder.get(),
+ ObserverInfo{binder, in_observer, in_filters});
+
+ // Add observer to observable->subscribers map.
+ for (auto &filter : in_filters) {
+ for (auto &event : sEvents) {
+ if (!((uint64_t)filter.eventFilter & (uint64_t)event)) {
+ continue;
+ }
+ MediaObservableFilter key{filter.type, event};
+ mObservableToSubscribersMap[key].emplace((uintptr_t)binder.get(), in_observer);
+ }
+ }
+ }
+
+ // Add death binder and link.
+ uintptr_t cookie = (uintptr_t)binder.get();
+ {
+ std::scoped_lock lock{sDeathRecipientLock};
+ sDeathRecipientMap.emplace(
+ cookie, std::make_shared<DeathRecipient>(this, in_observer));
+ }
+
+ AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(),
+ reinterpret_cast<void*>(cookie));
+
+ return Status::ok();
+}
+
+Status ResourceObserverService::unregisterObserver(
+ const std::shared_ptr<IResourceObserver>& in_observer) {
+ // TODO(chz): Guard this by a permission.
+
+ ::ndk::SpAIBinder binder = in_observer->asBinder();
+
+ {
+ std::scoped_lock lock{mObserverLock};
+
+ auto it = mObserverInfoMap.find((uintptr_t)binder.get());
+ if (it == mObserverInfoMap.end()) {
+ return Status::fromServiceSpecificError(NAME_NOT_FOUND);
+ }
+
+ // Remove observer from observable->subscribers map.
+ for (auto &filter : it->second.filters) {
+ for (auto &event : sEvents) {
+ if (!((uint64_t)filter.eventFilter & (uint64_t)event)) {
+ continue;
+ }
+ MediaObservableFilter key{filter.type, event};
+ mObservableToSubscribersMap[key].erase((uintptr_t)binder.get());
+
+ //Remove the entry if there's no more subscribers.
+ if (mObservableToSubscribersMap[key].empty()) {
+ mObservableToSubscribersMap.erase(key);
+ }
+ }
+ }
+
+ // Remove observer info.
+ mObserverInfoMap.erase(it);
+ }
+
+ // Unlink and remove death binder.
+ uintptr_t cookie = (uintptr_t)binder.get();
+ AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(),
+ reinterpret_cast<void*>(cookie));
+
+ {
+ std::scoped_lock lock{sDeathRecipientLock};
+ sDeathRecipientMap.erase(cookie);
+ }
+
+ return Status::ok();
+}
+
+void ResourceObserverService::notifyObservers(
+ MediaObservableEvent event, int uid, int pid, const ResourceList &resources) {
+ struct CalleeInfo {
+ std::shared_ptr<IResourceObserver> observer;
+ std::vector<MediaObservableParcel> monitors;
+ };
+ // Build a consolidated list of observers to call with their respective observables.
+ std::map<uintptr_t, CalleeInfo> calleeList;
+
+ {
+ std::scoped_lock lock{mObserverLock};
+
+ for (auto &res : resources) {
+ // Skip if this resource doesn't map to any observable type.
+ MediaObservableType observableType = getObservableType(res.second);
+ if (observableType == MediaObservableType::kInvalid) {
+ continue;
+ }
+ MediaObservableFilter key{observableType, event};
+ // Skip if no one subscribed to this observable.
+ auto observableIt = mObservableToSubscribersMap.find(key);
+ if (observableIt == mObservableToSubscribersMap.end()) {
+ continue;
+ }
+ // Loop through all subsribers.
+ for (auto &subscriber : observableIt->second) {
+ auto calleeIt = calleeList.find(subscriber.first);
+ if (calleeIt == calleeList.end()) {
+ calleeList.emplace(subscriber.first, CalleeInfo{
+ subscriber.second, {{observableType, res.second.value}}});
+ } else {
+ calleeIt->second.monitors.push_back({observableType, res.second.value});
+ }
+ }
+ }
+ }
+
+ // Finally call the observers about the status change.
+ for (auto &calleeInfo : calleeList) {
+ calleeInfo.second.observer->onStatusChanged(
+ event, uid, pid, calleeInfo.second.monitors);
+ }
+}
+
+void ResourceObserverService::onResourceAdded(
+ int uid, int pid, const ResourceList &resources) {
+ notifyObservers(MediaObservableEvent::kBusy, uid, pid, resources);
+}
+
+void ResourceObserverService::onResourceRemoved(
+ int uid, int pid, const ResourceList &resources) {
+ notifyObservers(MediaObservableEvent::kIdle, uid, pid, resources);
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceObserverService.h b/services/mediaresourcemanager/ResourceObserverService.h
new file mode 100644
index 0000000..46bc5fb
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceObserverService.h
@@ -0,0 +1,95 @@
+/**
+ *
+ * Copyright 2020, 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_MEDIA_RESOURCE_OBSERVER_SERVICE_H
+#define ANDROID_MEDIA_RESOURCE_OBSERVER_SERVICE_H
+
+#include <map>
+
+#include <aidl/android/media/BnResourceObserverService.h>
+#include "ResourceManagerService.h"
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceObserverService;
+using ::aidl::android::media::IResourceObserver;
+using ::aidl::android::media::MediaObservableFilter;
+using ::aidl::android::media::MediaObservableParcel;
+using ::aidl::android::media::MediaObservableType;
+using ::aidl::android::media::MediaObservableEvent;
+
+class ResourceObserverService : public BnResourceObserverService {
+public:
+
+ static char const *getServiceName() { return "media.resource_observer"; }
+ static std::shared_ptr<ResourceObserverService> instantiate();
+
+ virtual inline binder_status_t dump(
+ int /*fd*/, const char** /*args*/, uint32_t /*numArgs*/);
+
+ ResourceObserverService();
+ virtual ~ResourceObserverService() {}
+
+ // IResourceObserverService interface
+ Status registerObserver(const std::shared_ptr<IResourceObserver>& in_observer,
+ const std::vector<MediaObservableFilter>& in_filters) override;
+
+ Status unregisterObserver(const std::shared_ptr<IResourceObserver>& in_observer) override;
+ // ~IResourceObserverService interface
+
+ // Called by ResourceManagerService when resources are added.
+ void onResourceAdded(int uid, int pid, const ResourceList &resources);
+
+ // Called by ResourceManagerService when resources are removed.
+ void onResourceRemoved(int uid, int pid, const ResourceList &resources);
+
+private:
+ struct ObserverInfo {
+ ::ndk::SpAIBinder binder;
+ std::shared_ptr<IResourceObserver> observer;
+ std::vector<MediaObservableFilter> filters;
+ };
+ struct DeathRecipient;
+
+ // Below maps are all keyed on the observer's binder ptr value.
+ using ObserverInfoMap = std::map<uintptr_t, ObserverInfo>;
+ using SubscriberMap = std::map<uintptr_t, std::shared_ptr<IResourceObserver>>;
+
+ std::mutex mObserverLock;
+ // Binder->ObserverInfo
+ ObserverInfoMap mObserverInfoMap GUARDED_BY(mObserverLock);
+ // Observable(<type,event>)->Subscribers
+ std::map<MediaObservableFilter, SubscriberMap> mObservableToSubscribersMap
+ GUARDED_BY(mObserverLock);
+
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ // Binder death handling.
+ static std::mutex sDeathRecipientLock;
+ static std::map<uintptr_t, std::shared_ptr<DeathRecipient>> sDeathRecipientMap
+ GUARDED_BY(sDeathRecipientLock);
+ static void BinderDiedCallback(void* cookie);
+
+ void notifyObservers(MediaObservableEvent event,
+ int uid, int pid, const ResourceList &resources);
+};
+
+// ----------------------------------------------------------------------------
+} // namespace android
+
+#endif // ANDROID_MEDIA_RESOURCE_OBSERVER_SERVICE_H
diff --git a/services/mediaresourcemanager/TEST_MAPPING b/services/mediaresourcemanager/TEST_MAPPING
index 418b159..52ad441 100644
--- a/services/mediaresourcemanager/TEST_MAPPING
+++ b/services/mediaresourcemanager/TEST_MAPPING
@@ -5,6 +5,9 @@
},
{
"name": "ServiceLog_test"
+ },
+ {
+ "name": "ResourceObserverService_test"
}
]
}
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceObserver.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceObserver.aidl
new file mode 100644
index 0000000..462009a
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceObserver.aidl
@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.MediaObservableEvent;
+import android.media.MediaObservableParcel;
+
+/**
+ * IResourceObserver interface for receiving observable resource updates
+ * from IResourceObserverService.
+ *
+ * {@hide}
+ */
+interface IResourceObserver {
+ /**
+ * Called when an observed resource is granted to a client.
+ *
+ * @param event the status change that happened to the resource.
+ * @param uid uid to which the resource is associated.
+ * @param pid pid to which the resource is associated.
+ * @param observables the resources whose status has changed.
+ */
+ oneway void onStatusChanged(MediaObservableEvent event,
+ int uid, int pid, in MediaObservableParcel[] observables);
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/IResourceObserverService.aidl b/services/mediaresourcemanager/aidl/android/media/IResourceObserverService.aidl
new file mode 100644
index 0000000..08f4ca0
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/IResourceObserverService.aidl
@@ -0,0 +1,49 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.IResourceObserver;
+import android.media.MediaObservableFilter;
+
+/**
+ * IResourceObserverService interface for registering an IResourceObserver
+ * callback to receive status updates about observable media resources.
+ *
+ * {@hide}
+ */
+interface IResourceObserverService {
+
+ /**
+ * Register an observer on the IResourceObserverService to receive
+ * status updates for observable resources.
+ *
+ * @param observer the observer to register.
+ * @param filters an array of filters for resources and events to receive
+ * updates for.
+ */
+ void registerObserver(
+ IResourceObserver observer,
+ in MediaObservableFilter[] filters);
+
+ /**
+ * Unregister an observer from the IResourceObserverService.
+ * The observer will stop receiving the status updates.
+ *
+ * @param observer the observer to unregister.
+ */
+ void unregisterObserver(IResourceObserver observer);
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableEvent.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableEvent.aidl
new file mode 100644
index 0000000..56ab24d
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableEvent.aidl
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+/**
+ * Enums for media observable events.
+ *
+ * These values are used as bitmasks to indicate the events that the
+ * observer is interested in in the MediaObservableFilter objects passed to
+ * IResourceObserverService::registerObserver().
+ *
+ * {@hide}
+ */
+@Backing(type="long")
+enum MediaObservableEvent {
+ /**
+ * A media resource is granted to a client and becomes busy.
+ */
+ kBusy = 1,
+
+ /**
+ * A media resource is released by a client and becomes idle.
+ */
+ kIdle = 2,
+
+ /**
+ * A bitmask that covers all observable events defined.
+ */
+ kAll = ~0,
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableFilter.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableFilter.aidl
new file mode 100644
index 0000000..38f7e39
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableFilter.aidl
@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.MediaObservableType;
+import android.media.MediaObservableEvent;
+
+/**
+ * Description of an observable resource and its associated events that the
+ * observer is interested in.
+ *
+ * {@hide}
+ */
+parcelable MediaObservableFilter {
+ /**
+ * Type of the observable media resource.
+ */
+ MediaObservableType type;
+
+ /**
+ * Events that the observer is interested in.
+ *
+ * This field is a bitwise-OR of the events in MediaObservableEvent. If a
+ * particular event's bit is set, it means that updates should be sent for
+ * that event. For example, if the observer is only interested in receiving
+ * updates when a resource becomes available, it should only set 'kIdle'.
+ */
+ MediaObservableEvent eventFilter;
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableParcel.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableParcel.aidl
new file mode 100644
index 0000000..c4233e1
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableParcel.aidl
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+import android.media.MediaObservableType;
+
+/**
+ * Description of an observable resource whose status has changed.
+ *
+ * {@hide}
+ */
+parcelable MediaObservableParcel {
+ /**
+ * Type of the observable media resource.
+ */
+ MediaObservableType type;// = MediaObservableType::kInvalid;
+
+ /**
+ * Number of units of the observable resource (number of codecs, bytes of
+ * graphic memory, etc.).
+ */
+ long value = 0;
+}
diff --git a/services/mediaresourcemanager/aidl/android/media/MediaObservableType.aidl b/services/mediaresourcemanager/aidl/android/media/MediaObservableType.aidl
new file mode 100644
index 0000000..ed202da
--- /dev/null
+++ b/services/mediaresourcemanager/aidl/android/media/MediaObservableType.aidl
@@ -0,0 +1,35 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media;
+
+/**
+ * Type enums of observable media resources.
+ *
+ * {@hide}
+ */
+@Backing(type="int")
+enum MediaObservableType {
+ kInvalid = 0,
+
+ //kVideoStart = 1000,
+ kVideoSecureCodec = 1000,
+ kVideoNonSecureCodec = 1001,
+
+ //kAudioStart = 2000,
+
+ //kGraphicMemory = 3000,
+}
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index 6b2ef69..7bdfc6f 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -40,3 +40,26 @@
"-Wall",
],
}
+
+cc_test {
+ name: "ResourceObserverService_test",
+ srcs: ["ResourceObserverService_test.cpp"],
+ test_suites: ["device-tests"],
+ static_libs: ["libresourcemanagerservice"],
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ "liblog",
+ "libmedia",
+ "libutils",
+ "resourceobserver_aidl_interface-ndk_platform",
+ ],
+ include_dirs: [
+ "frameworks/av/include",
+ "frameworks/av/services/mediaresourcemanager",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
new file mode 100644
index 0000000..84c320d
--- /dev/null
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2015 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "ResourceManagerService.h"
+#include <aidl/android/media/BnResourceManagerClient.h>
+#include <media/MediaResource.h>
+#include <media/MediaResourcePolicy.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/ProcessInfoInterface.h>
+
+namespace aidl {
+namespace android {
+namespace media {
+bool operator== (const MediaResourceParcel& lhs, const MediaResourceParcel& rhs) {
+ return lhs.type == rhs.type && lhs.subType == rhs.subType &&
+ lhs.id == rhs.id && lhs.value == rhs.value;
+}
+}}}
+
+namespace android {
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::BnResourceManagerClient;
+using ::aidl::android::media::IResourceManagerService;
+using ::aidl::android::media::IResourceManagerClient;
+using ::aidl::android::media::MediaResourceParcel;
+
+static int64_t getId(const std::shared_ptr<IResourceManagerClient>& client) {
+ return (int64_t) client.get();
+}
+
+struct TestProcessInfo : public ProcessInfoInterface {
+ TestProcessInfo() {}
+ virtual ~TestProcessInfo() {}
+
+ virtual bool getPriority(int pid, int *priority) {
+ // For testing, use pid as priority.
+ // Lower the value higher the priority.
+ *priority = pid;
+ return true;
+ }
+
+ virtual bool isValidPid(int /* pid */) {
+ return true;
+ }
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
+};
+
+struct TestSystemCallback :
+ public ResourceManagerService::SystemCallbackInterface {
+ TestSystemCallback() :
+ mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
+
+ enum EventType {
+ INVALID = -1,
+ VIDEO_ON = 0,
+ VIDEO_OFF = 1,
+ VIDEO_RESET = 2,
+ CPUSET_ENABLE = 3,
+ CPUSET_DISABLE = 4,
+ };
+
+ struct EventEntry {
+ EventType type;
+ int arg;
+ };
+
+ virtual void noteStartVideo(int uid) override {
+ mLastEvent = {EventType::VIDEO_ON, uid};
+ mEventCount++;
+ }
+
+ virtual void noteStopVideo(int uid) override {
+ mLastEvent = {EventType::VIDEO_OFF, uid};
+ mEventCount++;
+ }
+
+ virtual void noteResetVideo() override {
+ mLastEvent = {EventType::VIDEO_RESET, 0};
+ mEventCount++;
+ }
+
+ virtual bool requestCpusetBoost(bool enable) override {
+ mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
+ mEventCount++;
+ return true;
+ }
+
+ size_t eventCount() { return mEventCount; }
+ EventType lastEventType() { return mLastEvent.type; }
+ EventEntry lastEvent() { return mLastEvent; }
+
+protected:
+ virtual ~TestSystemCallback() {}
+
+private:
+ EventEntry mLastEvent;
+ size_t mEventCount;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
+};
+
+
+struct TestClient : public BnResourceManagerClient {
+ TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
+ : mReclaimed(false), mPid(pid), mService(service) {}
+
+ Status reclaimResource(bool* _aidl_return) override {
+ mService->removeClient(mPid, getId(ref<TestClient>()));
+ mReclaimed = true;
+ *_aidl_return = true;
+ return Status::ok();
+ }
+
+ Status getName(::std::string* _aidl_return) override {
+ *_aidl_return = "test_client";
+ return Status::ok();
+ }
+
+ bool reclaimed() const {
+ return mReclaimed;
+ }
+
+ void reset() {
+ mReclaimed = false;
+ }
+
+ virtual ~TestClient() {}
+
+private:
+ bool mReclaimed;
+ int mPid;
+ std::shared_ptr<ResourceManagerService> mService;
+ DISALLOW_EVIL_CONSTRUCTORS(TestClient);
+};
+
+static const int kTestPid1 = 30;
+static const int kTestUid1 = 1010;
+
+static const int kTestPid2 = 20;
+static const int kTestUid2 = 1011;
+
+static const int kLowPriorityPid = 40;
+static const int kMidPriorityPid = 25;
+static const int kHighPriorityPid = 10;
+
+using EventType = TestSystemCallback::EventType;
+using EventEntry = TestSystemCallback::EventEntry;
+bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
+ return lhs.type == rhs.type && lhs.arg == rhs.arg;
+}
+
+#define CHECK_STATUS_TRUE(condition) \
+ EXPECT_TRUE((condition).isOk() && (result))
+
+#define CHECK_STATUS_FALSE(condition) \
+ EXPECT_TRUE((condition).isOk() && !(result))
+
+class ResourceManagerServiceTestBase : public ::testing::Test {
+public:
+ ResourceManagerServiceTestBase()
+ : mSystemCB(new TestSystemCallback()),
+ mService(::ndk::SharedRefBase::make<ResourceManagerService>(
+ new TestProcessInfo, mSystemCB)),
+ mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, mService)),
+ mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)),
+ mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
+ }
+
+ sp<TestSystemCallback> mSystemCB;
+ std::shared_ptr<ResourceManagerService> mService;
+ std::shared_ptr<IResourceManagerClient> mTestClient1;
+ std::shared_ptr<IResourceManagerClient> mTestClient2;
+ std::shared_ptr<IResourceManagerClient> mTestClient3;
+
+protected:
+ static bool isEqualResources(const std::vector<MediaResourceParcel> &resources1,
+ const ResourceList &resources2) {
+ // convert resource1 to ResourceList
+ ResourceList r1;
+ for (size_t i = 0; i < resources1.size(); ++i) {
+ const auto &res = resources1[i];
+ const auto resType = std::tuple(res.type, res.subType, res.id);
+ r1[resType] = res;
+ }
+ return r1 == resources2;
+ }
+
+ static void expectEqResourceInfo(const ResourceInfo &info,
+ int uid,
+ std::shared_ptr<IResourceManagerClient> client,
+ const std::vector<MediaResourceParcel> &resources) {
+ EXPECT_EQ(uid, info.uid);
+ EXPECT_EQ(client, info.client);
+ EXPECT_TRUE(isEqualResources(resources, info.resources));
+ }
+};
+
+} // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 702935d..15601aa 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -16,197 +16,17 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ResourceManagerService_test"
+
#include <utils/Log.h>
-#include <gtest/gtest.h>
-
+#include "ResourceManagerServiceTestUtils.h"
#include "ResourceManagerService.h"
-#include <aidl/android/media/BnResourceManagerClient.h>
-#include <media/MediaResource.h>
-#include <media/MediaResourcePolicy.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/ProcessInfoInterface.h>
-
-namespace aidl {
-namespace android {
-namespace media {
-bool operator== (const MediaResourceParcel& lhs, const MediaResourceParcel& rhs) {
- return lhs.type == rhs.type && lhs.subType == rhs.subType &&
- lhs.id == rhs.id && lhs.value == rhs.value;
-}}}}
namespace android {
-using Status = ::ndk::ScopedAStatus;
-using ::aidl::android::media::BnResourceManagerClient;
-using ::aidl::android::media::IResourceManagerService;
-using ::aidl::android::media::IResourceManagerClient;
-
-static int64_t getId(const std::shared_ptr<IResourceManagerClient>& client) {
- return (int64_t) client.get();
-}
-
-struct TestProcessInfo : public ProcessInfoInterface {
- TestProcessInfo() {}
- virtual ~TestProcessInfo() {}
-
- virtual bool getPriority(int pid, int *priority) {
- // For testing, use pid as priority.
- // Lower the value higher the priority.
- *priority = pid;
- return true;
- }
-
- virtual bool isValidPid(int /* pid */) {
- return true;
- }
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(TestProcessInfo);
-};
-
-struct TestSystemCallback :
- public ResourceManagerService::SystemCallbackInterface {
- TestSystemCallback() :
- mLastEvent({EventType::INVALID, 0}), mEventCount(0) {}
-
- enum EventType {
- INVALID = -1,
- VIDEO_ON = 0,
- VIDEO_OFF = 1,
- VIDEO_RESET = 2,
- CPUSET_ENABLE = 3,
- CPUSET_DISABLE = 4,
- };
-
- struct EventEntry {
- EventType type;
- int arg;
- };
-
- virtual void noteStartVideo(int uid) override {
- mLastEvent = {EventType::VIDEO_ON, uid};
- mEventCount++;
- }
-
- virtual void noteStopVideo(int uid) override {
- mLastEvent = {EventType::VIDEO_OFF, uid};
- mEventCount++;
- }
-
- virtual void noteResetVideo() override {
- mLastEvent = {EventType::VIDEO_RESET, 0};
- mEventCount++;
- }
-
- virtual bool requestCpusetBoost(bool enable) override {
- mLastEvent = {enable ? EventType::CPUSET_ENABLE : EventType::CPUSET_DISABLE, 0};
- mEventCount++;
- return true;
- }
-
- size_t eventCount() { return mEventCount; }
- EventType lastEventType() { return mLastEvent.type; }
- EventEntry lastEvent() { return mLastEvent; }
-
-protected:
- virtual ~TestSystemCallback() {}
-
-private:
- EventEntry mLastEvent;
- size_t mEventCount;
-
- DISALLOW_EVIL_CONSTRUCTORS(TestSystemCallback);
-};
-
-
-struct TestClient : public BnResourceManagerClient {
- TestClient(int pid, const std::shared_ptr<ResourceManagerService> &service)
- : mReclaimed(false), mPid(pid), mService(service) {}
-
- Status reclaimResource(bool* _aidl_return) override {
- mService->removeClient(mPid, getId(ref<TestClient>()));
- mReclaimed = true;
- *_aidl_return = true;
- return Status::ok();
- }
-
- Status getName(::std::string* _aidl_return) override {
- *_aidl_return = "test_client";
- return Status::ok();
- }
-
- bool reclaimed() const {
- return mReclaimed;
- }
-
- void reset() {
- mReclaimed = false;
- }
-
- virtual ~TestClient() {}
-
-private:
- bool mReclaimed;
- int mPid;
- std::shared_ptr<ResourceManagerService> mService;
- DISALLOW_EVIL_CONSTRUCTORS(TestClient);
-};
-
-static const int kTestPid1 = 30;
-static const int kTestUid1 = 1010;
-
-static const int kTestPid2 = 20;
-static const int kTestUid2 = 1011;
-
-static const int kLowPriorityPid = 40;
-static const int kMidPriorityPid = 25;
-static const int kHighPriorityPid = 10;
-
-using EventType = TestSystemCallback::EventType;
-using EventEntry = TestSystemCallback::EventEntry;
-bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
- return lhs.type == rhs.type && lhs.arg == rhs.arg;
-}
-
-#define CHECK_STATUS_TRUE(condition) \
- EXPECT_TRUE((condition).isOk() && (result))
-
-#define CHECK_STATUS_FALSE(condition) \
- EXPECT_TRUE((condition).isOk() && !(result))
-
-class ResourceManagerServiceTest : public ::testing::Test {
+class ResourceManagerServiceTest : public ResourceManagerServiceTestBase {
public:
- ResourceManagerServiceTest()
- : mSystemCB(new TestSystemCallback()),
- mService(::ndk::SharedRefBase::make<ResourceManagerService>(
- new TestProcessInfo, mSystemCB)),
- mTestClient1(::ndk::SharedRefBase::make<TestClient>(kTestPid1, mService)),
- mTestClient2(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)),
- mTestClient3(::ndk::SharedRefBase::make<TestClient>(kTestPid2, mService)) {
- }
-
-protected:
- static bool isEqualResources(const std::vector<MediaResourceParcel> &resources1,
- const ResourceList &resources2) {
- // convert resource1 to ResourceList
- ResourceList r1;
- for (size_t i = 0; i < resources1.size(); ++i) {
- const auto &res = resources1[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
- r1[resType] = res;
- }
- return r1 == resources2;
- }
-
- static void expectEqResourceInfo(const ResourceInfo &info,
- int uid,
- std::shared_ptr<IResourceManagerClient> client,
- const std::vector<MediaResourceParcel> &resources) {
- EXPECT_EQ(uid, info.uid);
- EXPECT_EQ(client, info.client);
- EXPECT_TRUE(isEqualResources(resources, info.resources));
- }
+ ResourceManagerServiceTest() : ResourceManagerServiceTestBase() {}
void verifyClients(bool c1, bool c2, bool c3) {
TestClient *client1 = static_cast<TestClient*>(mTestClient1.get());
@@ -881,12 +701,6 @@
EXPECT_EQ(4u, mSystemCB->eventCount());
EXPECT_EQ(EventType::CPUSET_DISABLE, mSystemCB->lastEventType());
}
-
- sp<TestSystemCallback> mSystemCB;
- std::shared_ptr<ResourceManagerService> mService;
- std::shared_ptr<IResourceManagerClient> mTestClient1;
- std::shared_ptr<IResourceManagerClient> mTestClient2;
- std::shared_ptr<IResourceManagerClient> mTestClient3;
};
TEST_F(ResourceManagerServiceTest, config) {
diff --git a/services/mediaresourcemanager/test/ResourceObserverService_test.cpp b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
new file mode 100644
index 0000000..4c26246
--- /dev/null
+++ b/services/mediaresourcemanager/test/ResourceObserverService_test.cpp
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2020 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_NDEBUG 0
+#define LOG_TAG "ResourceObserverService_test"
+
+#include <iostream>
+#include <list>
+
+#include <aidl/android/media/BnResourceObserver.h>
+#include <utils/Log.h>
+#include "ResourceObserverService.h"
+#include "ResourceManagerServiceTestUtils.h"
+
+namespace aidl {
+namespace android {
+namespace media {
+bool operator==(const MediaObservableParcel& lhs, const MediaObservableParcel& rhs) {
+ return lhs.type == rhs.type && lhs.value == rhs.value;
+}
+}}} // namespace ::aidl::android::media
+
+namespace android {
+
+using ::aidl::android::media::BnResourceObserver;
+using ::aidl::android::media::MediaObservableParcel;
+using ::aidl::android::media::MediaObservableType;
+
+#define BUSY ::aidl::android::media::MediaObservableEvent::kBusy
+#define IDLE ::aidl::android::media::MediaObservableEvent::kIdle
+#define ALL ::aidl::android::media::MediaObservableEvent::kAll
+
+struct EventTracker {
+ struct Event {
+ enum { NoEvent, Busy, Idle } type = NoEvent;
+ int uid = 0;
+ int pid = 0;
+ std::vector<MediaObservableParcel> observables;
+ };
+
+ static const Event NoEvent;
+
+ static std::string toString(const MediaObservableParcel& observable) {
+ return "{" + ::aidl::android::media::toString(observable.type)
+ + ", " + std::to_string(observable.value) + "}";
+ }
+ static std::string toString(const Event& event) {
+ std::string eventStr;
+ switch (event.type) {
+ case Event::Busy:
+ eventStr = "Busy";
+ break;
+ case Event::Idle:
+ eventStr = "Idle";
+ break;
+ default:
+ return "NoEvent";
+ }
+ std::string observableStr;
+ for (auto &observable : event.observables) {
+ if (!observableStr.empty()) {
+ observableStr += ", ";
+ }
+ observableStr += toString(observable);
+ }
+ return "{" + eventStr + ", " + std::to_string(event.uid) + ", "
+ + std::to_string(event.pid) + ", {" + observableStr + "}}";
+ }
+
+ static Event Busy(int uid, int pid, const std::vector<MediaObservableParcel>& observables) {
+ return { Event::Busy, uid, pid, observables };
+ }
+ static Event Idle(int uid, int pid, const std::vector<MediaObservableParcel>& observables) {
+ return { Event::Idle, uid, pid, observables };
+ }
+
+ // Pop 1 event from front, wait for up to timeoutUs if empty.
+ const Event& pop(int64_t timeoutUs = 0) {
+ std::unique_lock lock(mLock);
+
+ if (mEventQueue.empty() && timeoutUs > 0) {
+ mCondition.wait_for(lock, std::chrono::microseconds(timeoutUs));
+ }
+
+ if (mEventQueue.empty()) {
+ mPoppedEvent = NoEvent;
+ } else {
+ mPoppedEvent = *mEventQueue.begin();
+ mEventQueue.pop_front();
+ }
+
+ return mPoppedEvent;
+ }
+
+ // Push 1 event to back.
+ void append(const Event& event) {
+ ALOGD("%s", toString(event).c_str());
+
+ std::unique_lock lock(mLock);
+
+ mEventQueue.push_back(event);
+ mCondition.notify_one();
+ }
+
+private:
+ std::mutex mLock;
+ std::condition_variable mCondition;
+ Event mPoppedEvent;
+ std::list<Event> mEventQueue;
+};
+
+const EventTracker::Event EventTracker::NoEvent;
+
+// Operators for GTest macros.
+bool operator==(const EventTracker::Event& lhs, const EventTracker::Event& rhs) {
+ return lhs.type == rhs.type && lhs.uid == rhs.uid && lhs.pid == rhs.pid &&
+ lhs.observables == rhs.observables;
+}
+
+std::ostream& operator<<(std::ostream& str, const EventTracker::Event& v) {
+ str << EventTracker::toString(v);
+ return str;
+}
+
+struct TestObserver : public BnResourceObserver, public EventTracker {
+ TestObserver(const char *name) : mName(name) {}
+ ~TestObserver() = default;
+ Status onStatusChanged(MediaObservableEvent event, int32_t uid, int32_t pid,
+ const std::vector<MediaObservableParcel>& observables) override {
+ ALOGD("%s: %s", mName.c_str(), __FUNCTION__);
+ if (event == MediaObservableEvent::kBusy) {
+ append(Busy(uid, pid, observables));
+ } else {
+ append(Idle(uid, pid, observables));
+ }
+
+ return Status::ok();
+ }
+ std::string mName;
+};
+
+class ResourceObserverServiceTest : public ResourceManagerServiceTestBase {
+public:
+ ResourceObserverServiceTest() : ResourceManagerServiceTestBase(),
+ mObserverService(::ndk::SharedRefBase::make<ResourceObserverService>()),
+ mTestObserver1(::ndk::SharedRefBase::make<TestObserver>("observer1")),
+ mTestObserver2(::ndk::SharedRefBase::make<TestObserver>("observer2")),
+ mTestObserver3(::ndk::SharedRefBase::make<TestObserver>("observer3")) {
+ mService->setObserverService(mObserverService);
+ }
+
+ void registerObservers(MediaObservableEvent filter = ALL) {
+ std::vector<MediaObservableFilter> filters1, filters2, filters3;
+ filters1 = {{MediaObservableType::kVideoSecureCodec, filter}};
+ filters2 = {{MediaObservableType::kVideoNonSecureCodec, filter}};
+ filters3 = {{MediaObservableType::kVideoSecureCodec, filter},
+ {MediaObservableType::kVideoNonSecureCodec, filter}};
+
+ // mTestObserver1 monitors secure video codecs.
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+
+ // mTestObserver2 monitors non-secure video codecs.
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver2, filters2).isOk());
+
+ // mTestObserver3 monitors both secure & non-secure video codecs.
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver3, filters3).isOk());
+ }
+
+protected:
+ std::shared_ptr<ResourceObserverService> mObserverService;
+ std::shared_ptr<TestObserver> mTestObserver1;
+ std::shared_ptr<TestObserver> mTestObserver2;
+ std::shared_ptr<TestObserver> mTestObserver3;
+};
+
+TEST_F(ResourceObserverServiceTest, testRegisterObserver) {
+ std::vector<MediaObservableFilter> filters1;
+ Status status;
+
+ // Register with empty observables should fail.
+ status = mObserverService->registerObserver(mTestObserver1, filters1);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.getServiceSpecificError(), BAD_VALUE);
+
+ // mTestObserver1 monitors secure video codecs.
+ filters1 = {{MediaObservableType::kVideoSecureCodec, ALL}};
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+
+ // Register duplicates should fail.
+ status = mObserverService->registerObserver(mTestObserver1, filters1);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.getServiceSpecificError(), ALREADY_EXISTS);
+}
+
+TEST_F(ResourceObserverServiceTest, testUnregisterObserver) {
+ std::vector<MediaObservableFilter> filters1;
+ Status status;
+
+ // Unregister without registering first should fail.
+ status = mObserverService->unregisterObserver(mTestObserver1);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.getServiceSpecificError(), NAME_NOT_FOUND);
+
+ // mTestObserver1 monitors secure video codecs.
+ filters1 = {{MediaObservableType::kVideoSecureCodec, ALL}};
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+ EXPECT_TRUE(mObserverService->unregisterObserver(mTestObserver1).isOk());
+
+ // Unregister again should fail.
+ status = mObserverService->unregisterObserver(mTestObserver1);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(status.getServiceSpecificError(), NAME_NOT_FOUND);
+}
+
+TEST_F(ResourceObserverServiceTest, testAddResourceBasic) {
+ registerObservers();
+
+ std::vector<MediaObservableParcel> observables1, observables2, observables3;
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+ observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+ {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+ std::vector<MediaResourceParcel> resources;
+ // Add secure video codec.
+ resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+
+ // Add non-secure video codec.
+ resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+
+ // Add secure & non-secure video codecs.
+ resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+
+ // Add additional audio codecs, should be ignored.
+ resources.push_back(MediaResource::CodecResource(1 /*secure*/, 0 /*video*/));
+ resources.push_back(MediaResource::CodecResource(0 /*secure*/, 0 /*video*/));
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables3));
+}
+
+TEST_F(ResourceObserverServiceTest, testAddResourceMultiple) {
+ registerObservers();
+
+ std::vector<MediaObservableParcel> observables1, observables2, observables3;
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+ observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+ {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+ std::vector<MediaResourceParcel> resources;
+
+ // Add multiple secure & non-secure video codecs.
+ // Multiple entries of the same type should be merged, count should be propagated correctly.
+ resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 3 /*count*/)};
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 2}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 3}};
+ observables3 = {{MediaObservableType::kVideoSecureCodec, 2},
+ {MediaObservableType::kVideoNonSecureCodec, 3}};
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+}
+
+TEST_F(ResourceObserverServiceTest, testRemoveResourceBasic) {
+ registerObservers();
+
+ std::vector<MediaObservableParcel> observables1, observables2, observables3;
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+ observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+ {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+ std::vector<MediaResourceParcel> resources;
+ // Add secure video codec to client1.
+ resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+ mService->addResource(kTestPid1, kTestUid1, getId(mTestClient1), mTestClient1, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid1, kTestPid1, observables1));
+ // Remove secure video codec. observer 1&3 should receive updates.
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid1, kTestPid1, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid1, kTestPid1, observables1));
+ // Remove secure video codec again, should have no event.
+ mService->removeResource(kTestPid1, getId(mTestClient1), resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+ // Remove client1, should have no event.
+ mService->removeClient(kTestPid1, getId(mTestClient1));
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+
+ // Add non-secure video codec to client2.
+ resources = {MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient2), mTestClient2, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+ // Remove client2, observer 2&3 should receive updates.
+ mService->removeClient(kTestPid2, getId(mTestClient2));
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+ // Remove non-secure codec after client2 removed, should have no event.
+ mService->removeResource(kTestPid2, getId(mTestClient2), resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+ // Remove client2 again, should have no event.
+ mService->removeClient(kTestPid2, getId(mTestClient2));
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+
+ // Add secure & non-secure video codecs, plus audio codecs (that's ignored).
+ resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+ // Remove one audio codec, should have no event.
+ resources = {MediaResource::CodecResource(1 /*secure*/, 0 /*video*/)};
+ mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::NoEvent);
+ // Remove the other audio codec and the secure video codec, only secure video codec
+ // removal should be reported.
+ resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
+ MediaResource::CodecResource(1 /*secure*/, 1 /*video*/)};
+ mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+ // Remove client3 entirely. Non-secure video codec removal should be reported.
+ mService->removeClient(kTestPid2, getId(mTestClient3));
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+}
+
+TEST_F(ResourceObserverServiceTest, testRemoveResourceMultiple) {
+ registerObservers();
+
+ std::vector<MediaObservableParcel> observables1, observables2, observables3;
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+ observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+ {MediaObservableType::kVideoNonSecureCodec, 1}};
+
+ std::vector<MediaResourceParcel> resources;
+
+ // Add multiple secure & non-secure video codecs, plus audio codecs (that's ignored).
+ // (ResourceManager will merge these internally.)
+ resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 4 /*count*/),
+ MediaResource::CodecResource(1 /*secure*/, 0 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 0 /*video*/)};
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 4}};
+ observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+ {MediaObservableType::kVideoNonSecureCodec, 4}};
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables3));
+ // Remove one audio codec, 2 secure video codecs and 2 non-secure video codecs.
+ // 1 secure video codec removal and 2 non-secure video codec removals should be reported.
+ resources = {MediaResource::CodecResource(0 /*secure*/, 0 /*video*/),
+ MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 1 /*video*/, 2 /*count*/)};
+ mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 2}};
+ observables3 = {{MediaObservableType::kVideoSecureCodec, 1},
+ {MediaObservableType::kVideoNonSecureCodec, 2}};
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables3));
+ // Remove client3 entirely. 2 non-secure video codecs removal should be reported.
+ mService->removeClient(kTestPid2, getId(mTestClient3));
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+}
+
+TEST_F(ResourceObserverServiceTest, testEventFilters) {
+ // Register observers with different event filters.
+ std::vector<MediaObservableFilter> filters1, filters2, filters3;
+ filters1 = {{MediaObservableType::kVideoSecureCodec, BUSY}};
+ filters2 = {{MediaObservableType::kVideoNonSecureCodec, IDLE}};
+ filters3 = {{MediaObservableType::kVideoSecureCodec, IDLE},
+ {MediaObservableType::kVideoNonSecureCodec, BUSY}};
+
+ // mTestObserver1 monitors secure video codecs.
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver1, filters1).isOk());
+
+ // mTestObserver2 monitors non-secure video codecs.
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver2, filters2).isOk());
+
+ // mTestObserver3 monitors both secure & non-secure video codecs.
+ EXPECT_TRUE(mObserverService->registerObserver(mTestObserver3, filters3).isOk());
+
+ std::vector<MediaObservableParcel> observables1, observables2;
+ observables1 = {{MediaObservableType::kVideoSecureCodec, 1}};
+ observables2 = {{MediaObservableType::kVideoNonSecureCodec, 1}};
+
+ std::vector<MediaResourceParcel> resources;
+
+ // Add secure & non-secure video codecs.
+ resources = {MediaResource::CodecResource(1 /*secure*/, 1 /*video*/),
+ MediaResource::CodecResource(0 /*secure*/, 1 /*video*/)};
+ mService->addResource(kTestPid2, kTestUid2, getId(mTestClient3), mTestClient3, resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables1));
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Busy(kTestUid2, kTestPid2, observables2));
+
+ // Remove secure & non-secure video codecs.
+ mService->removeResource(kTestPid2, getId(mTestClient3), resources);
+ EXPECT_EQ(mTestObserver1->pop(), EventTracker::NoEvent);
+ EXPECT_EQ(mTestObserver2->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables2));
+ EXPECT_EQ(mTestObserver3->pop(), EventTracker::Idle(kTestUid2, kTestPid2, observables1));
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/test/build_and_run_all_unit_tests.sh b/services/mediaresourcemanager/test/build_and_run_all_unit_tests.sh
new file mode 100755
index 0000000..1c4ae98
--- /dev/null
+++ b/services/mediaresourcemanager/test/build_and_run_all_unit_tests.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Run tests in this directory.
+#
+
+if [ "$SYNC_FINISHED" != true ]; then
+ if [ -z "$ANDROID_BUILD_TOP" ]; then
+ echo "Android build environment not set"
+ exit -1
+ fi
+
+ # ensure we have mm
+ . $ANDROID_BUILD_TOP/build/envsetup.sh
+
+ mm
+
+ echo "waiting for device"
+
+ adb root && adb wait-for-device remount && adb sync
+fi
+
+echo "========================================"
+
+echo "testing ResourceManagerService"
+#adb shell /data/nativetest64/ResourceManagerService_test/ResourceManagerService_test
+adb shell /data/nativetest/ResourceManagerService_test/ResourceManagerService_test
+
+echo "testing ServiceLog"
+#adb shell /data/nativetest64/ServiceLog_test/ServiceLog_test
+adb shell /data/nativetest/ServiceLog_test/ServiceLog_test
+
+echo "testing ResourceObserverService"
+#adb shell /data/nativetest64/ResourceObserverService_test/ResourceObserverService_test
+adb shell /data/nativetest/ResourceObserverService_test/ResourceObserverService_test