Merge "RELAND: "stagefright: MediaCodec::releaseAsync()"" into rvc-dev am: 929c364533 am: 5242549c4e
Change-Id: I1d55d56c8287a4cd9428fb35d15b8ae3914039d8
diff --git a/media/libmedia/aidl/android/media/IResourceManagerService.aidl b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
index 3dd0859..1b2d522 100644
--- a/media/libmedia/aidl/android/media/IResourceManagerService.aidl
+++ b/media/libmedia/aidl/android/media/IResourceManagerService.aidl
@@ -94,4 +94,12 @@
* remove existing override on originalPid if newPid is -1.
*/
void overridePid(int originalPid, int newPid);
+
+ /**
+ * Mark a client for pending removal
+ *
+ * @param pid pid from which the client's resources will be removed.
+ * @param clientId clientId within the pid that will be removed.
+ */
+ void markClientForPendingRemoval(int pid, long clientId);
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b597583..11f2f38 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -199,6 +199,7 @@
void addResource(const MediaResourceParcel &resource);
void removeResource(const MediaResourceParcel &resource);
void removeClient();
+ void markClientForPendingRemoval();
bool reclaimResource(const std::vector<MediaResourceParcel> &resources);
private:
@@ -280,6 +281,14 @@
mService->removeClient(mPid, getId(mClient));
}
+void MediaCodec::ResourceManagerServiceProxy::markClientForPendingRemoval() {
+ Mutex::Autolock _l(mLock);
+ if (mService == nullptr) {
+ return;
+ }
+ mService->markClientForPendingRemoval(mPid, getId(mClient));
+}
+
bool MediaCodec::ResourceManagerServiceProxy::reclaimResource(
const std::vector<MediaResourceParcel> &resources) {
Mutex::Autolock _l(mLock);
@@ -297,6 +306,33 @@
////////////////////////////////////////////////////////////////////////////////
+class MediaCodec::ReleaseSurface {
+public:
+ ReleaseSurface() {
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mSurface = new Surface(mProducer, false /* controlledByApp */);
+ struct ConsumerListener : public BnConsumerListener {
+ void onFrameAvailable(const BufferItem&) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+ };
+ sp<ConsumerListener> listener{new ConsumerListener};
+ mConsumer->consumerConnect(listener, false);
+ mConsumer->setConsumerName(String8{"MediaCodec.release"});
+ }
+
+ const sp<Surface> &getSurface() {
+ return mSurface;
+ }
+
+private:
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<Surface> mSurface;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
namespace {
enum {
@@ -1432,7 +1468,13 @@
status_t MediaCodec::release() {
sp<AMessage> msg = new AMessage(kWhatRelease, this);
+ sp<AMessage> response;
+ return PostAndAwaitResponse(msg, &response);
+}
+status_t MediaCodec::releaseAsync() {
+ sp<AMessage> msg = new AMessage(kWhatRelease, this);
+ msg->setInt32("async", 1);
sp<AMessage> response;
return PostAndAwaitResponse(msg, &response);
}
@@ -2600,7 +2642,9 @@
mResourceManagerProxy->removeClient();
- (new AMessage)->postReply(mReplyID);
+ if (mReplyID != nullptr) {
+ (new AMessage)->postReply(mReplyID);
+ }
break;
}
@@ -2987,6 +3031,26 @@
break;
}
+ int32_t async = 0;
+ if (msg->findInt32("async", &async) && async) {
+ if ((mState == CONFIGURED || mState == STARTED || mState == FLUSHED)
+ && mSurface != NULL) {
+ if (!mReleaseSurface) {
+ mReleaseSurface.reset(new ReleaseSurface);
+ }
+ status_t err = connectToSurface(mReleaseSurface->getSurface());
+ ALOGW_IF(err != OK, "error connecting to release surface: err = %d", err);
+ if (err == OK && !(mFlags & kFlagUsesSoftwareRenderer)) {
+ err = mCodec->setSurface(mReleaseSurface->getSurface());
+ ALOGW_IF(err != OK, "error setting release surface: err = %d", err);
+ }
+ if (err == OK) {
+ (void)disconnectFromSurface();
+ mSurface = mReleaseSurface->getSurface();
+ }
+ }
+ }
+
mReplyID = replyID;
setState(msg->what() == kWhatStop ? STOPPING : RELEASING);
@@ -2999,6 +3063,12 @@
pushBlankBuffersToNativeWindow(mSurface.get());
}
+ if (async) {
+ mResourceManagerProxy->markClientForPendingRemoval();
+ (new AMessage)->postReply(mReplyID);
+ mReplyID = 0;
+ }
+
break;
}
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 022c48e..63a9dad 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -139,6 +139,8 @@
// object.
status_t release();
+ status_t releaseAsync();
+
status_t flush();
status_t queueInputBuffer(
@@ -509,6 +511,9 @@
// when low latency is on
int64_t mInputBufferCounter; // number of input buffers queued since last reset/flush
+ class ReleaseSurface;
+ std::unique_ptr<ReleaseSurface> mReleaseSurface;
+
sp<BatteryChecker> mBatteryChecker;
void statsBufferSent(int64_t presentationUs);
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index be5af00..ff45c87 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -114,6 +114,7 @@
info.uid = uid;
info.clientId = clientId;
info.client = client;
+ info.pendingRemoval = false;
index = infos.add(clientId, info);
}
@@ -648,6 +649,36 @@
return Status::ok();
}
+Status ResourceManagerService::markClientForPendingRemoval(int32_t pid, int64_t clientId) {
+ String8 log = String8::format(
+ "markClientForPendingRemoval(pid %d, clientId %lld)",
+ pid, (long long) clientId);
+ mServiceLog->add(log);
+
+ Mutex::Autolock lock(mLock);
+ if (!mProcessInfo->isValidPid(pid)) {
+ ALOGE("Rejected markClientForPendingRemoval call with invalid pid.");
+ return Status::fromServiceSpecificError(BAD_VALUE);
+ }
+ ssize_t index = mMap.indexOfKey(pid);
+ if (index < 0) {
+ ALOGV("markClientForPendingRemoval: didn't find pid %d for clientId %lld",
+ pid, (long long)clientId);
+ return Status::ok();
+ }
+ ResourceInfos &infos = mMap.editValueAt(index);
+
+ index = infos.indexOfKey(clientId);
+ if (index < 0) {
+ ALOGV("markClientForPendingRemoval: didn't find clientId %lld", (long long) clientId);
+ return Status::ok();
+ }
+
+ ResourceInfo &info = infos.editValueAt(index);
+ info.pendingRemoval = true;
+ return Status::ok();
+}
+
bool ResourceManagerService::getPriority_l(int pid, int* priority) {
int newPid = pid;
@@ -693,6 +724,12 @@
int lowestPriorityPid;
int lowestPriority;
int callingPriority;
+
+ // Before looking into other processes, check if we have clients marked for
+ // pending removal in the same process.
+ if (getBiggestClient_l(callingPid, type, client, true /* pendingRemovalOnly */)) {
+ return true;
+ }
if (!getPriority_l(callingPid, &callingPriority)) {
ALOGE("getLowestPriorityBiggestClient_l: can't get process priority for pid %d",
callingPid);
@@ -761,7 +798,8 @@
}
bool ResourceManagerService::getBiggestClient_l(
- int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client) {
+ int pid, MediaResource::Type type, std::shared_ptr<IResourceManagerClient> *client,
+ bool pendingRemovalOnly) {
ssize_t index = mMap.indexOfKey(pid);
if (index < 0) {
ALOGE("getBiggestClient_l: can't find resource info for pid %d", pid);
@@ -773,6 +811,9 @@
const ResourceInfos &infos = mMap.valueAt(index);
for (size_t i = 0; i < infos.size(); ++i) {
const ResourceList &resources = infos[i].resources;
+ if (pendingRemovalOnly && !infos[i].pendingRemoval) {
+ continue;
+ }
for (auto it = resources.begin(); it != resources.end(); it++) {
const MediaResourceParcel &resource = it->second;
if (resource.type == type) {
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index 92048c3..49c247e 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -18,6 +18,8 @@
#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICE_H
+#include <map>
+
#include <aidl/android/media/BnResourceManagerService.h>
#include <arpa/inet.h>
#include <media/MediaResource.h>
@@ -50,6 +52,7 @@
std::shared_ptr<IResourceManagerClient> client;
sp<DeathNotifier> deathNotifier;
ResourceList resources;
+ bool pendingRemoval{false};
};
// TODO: convert these to std::map
@@ -122,6 +125,8 @@
int originalPid,
int newPid) override;
+ Status markClientForPendingRemoval(int32_t pid, int64_t clientId) override;
+
Status removeResource(int pid, int64_t clientId, bool checkValid);
private:
@@ -146,7 +151,8 @@
// Gets the client who owns biggest piece of specified resource type from pid.
// Returns false if failed. The client will remain unchanged if failed.
bool getBiggestClient_l(int pid, MediaResource::Type type,
- std::shared_ptr<IResourceManagerClient> *client);
+ std::shared_ptr<IResourceManagerClient> *client,
+ bool pendingRemovalOnly = false);
bool isCallingPriorityHigher_l(int callingPid, int pid);
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 5d839fa..702935d 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -472,6 +472,56 @@
}
}
+ void testMarkClientForPendingRemoval() {
+ bool result;
+
+ {
+ addResource();
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+ // Remove low priority clients
+ mService->removeClient(kTestPid1, getId(mTestClient1));
+
+ // no lower priority client
+ CHECK_STATUS_FALSE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(false /* c1 */, false /* c2 */, false /* c3 */);
+
+ mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+ // client marked for pending removal from the same process got reclaimed
+ CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+ // clean up client 3 which still left
+ mService->removeClient(kTestPid2, getId(mTestClient3));
+ }
+
+ {
+ addResource();
+ mService->mSupportsSecureWithNonSecureCodec = true;
+
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
+
+ mService->markClientForPendingRemoval(kTestPid2, getId(mTestClient2));
+
+ // client marked for pending removal from the same process got reclaimed
+ // first, even though there are lower priority process
+ CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(false /* c1 */, true /* c2 */, false /* c3 */);
+
+ // lower priority client got reclaimed
+ CHECK_STATUS_TRUE(mService->reclaimResource(kTestPid2, resources, &result));
+ verifyClients(true /* c1 */, false /* c2 */, false /* c3 */);
+
+ // clean up client 3 which still left
+ mService->removeClient(kTestPid2, getId(mTestClient3));
+ }
+ }
+
void testRemoveClient() {
addResource();
@@ -900,4 +950,8 @@
testOverridePid();
}
+TEST_F(ResourceManagerServiceTest, markClientForPendingRemoval) {
+ testMarkClientForPendingRemoval();
+}
+
} // namespace android