MediaCodec: consider usage bits when changing surface.

The new surface cannot add usage bits not already present (as
already existing buffers may become unusable for the surface).

Bug: 22414343
Change-Id: Id8169c79cd0994be134a16782dd04687e46ca1dd
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index a4b24d7..2ca3f1c 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -215,6 +215,7 @@
     sp<MemoryDealer> mDealer[2];
 
     sp<ANativeWindow> mNativeWindow;
+    int mNativeWindowUsageBits;
     sp<AMessage> mInputFormat;
     sp<AMessage> mOutputFormat;
     sp<AMessage> mBaseOutputFormat;
@@ -266,7 +267,8 @@
     status_t freeBuffer(OMX_U32 portIndex, size_t i);
 
     status_t handleSetSurface(const sp<Surface> &surface);
-    status_t setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */);
+    status_t setupNativeWindowSizeFormatAndUsage(
+            ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */);
 
     status_t configureOutputBuffersFromNativeWindow(
             OMX_U32 *nBufferCount, OMX_U32 *nBufferSize,
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 9206b5c..ffd90b3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -493,6 +493,7 @@
 ACodec::ACodec()
     : mQuirks(0),
       mNode(0),
+      mNativeWindowUsageBits(0),
       mSentFormat(false),
       mIsVideo(false),
       mIsEncoder(false),
@@ -642,7 +643,7 @@
         return OK;
     }
 
-    // allow keeping unset surface
+    // cannot switch from bytebuffers to surface
     if (mNativeWindow == NULL) {
         ALOGW("component was not configured with a surface");
         return INVALID_OPERATION;
@@ -661,11 +662,20 @@
         return INVALID_OPERATION;
     }
 
-    status_t err = setupNativeWindowSizeFormatAndUsage(nativeWindow);
+    int usageBits = 0;
+    status_t err = setupNativeWindowSizeFormatAndUsage(nativeWindow, &usageBits);
     if (err != OK) {
         return err;
     }
 
+    int ignoredFlags = (GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER
+            | GRALLOC_USAGE_EXTERNAL_DISP);
+    // New output surface is not allowed to add new usage flag except ignored ones.
+    if ((usageBits & ~(mNativeWindowUsageBits | ignoredFlags)) != 0) {
+        ALOGW("cannot change usage from %#x to %#x", mNativeWindowUsageBits, usageBits);
+        return BAD_VALUE;
+    }
+
     // get min undequeued count. We cannot switch to a surface that has a higher
     // undequeued count than we allocated.
     int minUndequeuedBuffers = 0;
@@ -747,6 +757,7 @@
     }
 
     mNativeWindow = nativeWindow;
+    mNativeWindowUsageBits = usageBits;
     return OK;
 }
 
@@ -868,7 +879,8 @@
     return OK;
 }
 
-status_t ACodec::setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */) {
+status_t ACodec::setupNativeWindowSizeFormatAndUsage(
+        ANativeWindow *nativeWindow /* nonnull */, int *finalUsage /* nonnull */) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
     def.nPortIndex = kPortIndexOutput;
@@ -894,6 +906,7 @@
     }
 
     usage |= GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP;
+    *finalUsage = usage;
 
     ALOGV("gralloc usage: %#x(OMX) => %#x(ACodec)", omxUsage, usage);
     return setNativeWindowSizeFormatAndUsage(
@@ -916,9 +929,10 @@
             mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
 
     if (err == OK) {
-        err = setupNativeWindowSizeFormatAndUsage(mNativeWindow.get());
+        err = setupNativeWindowSizeFormatAndUsage(mNativeWindow.get(), &mNativeWindowUsageBits);
     }
     if (err != OK) {
+        mNativeWindowUsageBits = 0;
         return err;
     }
 
@@ -1937,6 +1951,7 @@
                     // to SW renderer
                     ALOGI("[%s] Falling back to software renderer", mComponentName.c_str());
                     mNativeWindow.clear();
+                    mNativeWindowUsageBits = 0;
                     haveNativeWindow = false;
                     usingSwRenderer = true;
                     if (storingMetadataInDecodedBuffers()) {
@@ -5341,6 +5356,7 @@
     }
 
     mCodec->mNativeWindow.clear();
+    mCodec->mNativeWindowUsageBits = 0;
     mCodec->mNode = 0;
     mCodec->mOMX.clear();
     mCodec->mQuirks = 0;