Merge "ANativeWindow: add queues-to-window-composer check." into honeycomb-mr1
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 361e7dc..dea1b10 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -138,6 +138,10 @@
      * This is an ASYNCHRONOUS call.
      */
     virtual void signal() const = 0;
+
+    /* verify that an ISurface was created by SurfaceFlinger.
+     */
+    virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -161,7 +165,8 @@
         SIGNAL,
         CAPTURE_SCREEN,
         TURN_ELECTRON_BEAM_OFF,
-        TURN_ELECTRON_BEAM_ON
+        TURN_ELECTRON_BEAM_ON,
+        AUTHENTICATE_SURFACE,
     };
 
     virtual status_t    onTransact( uint32_t code,
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index fd83f46..0ac34d0 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -95,6 +95,21 @@
      * 5. Queue, dequeue, queue, dequeue, ad infinitum
      */
     NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+
+    /* Check whether queueBuffer operations on the ANativeWindow send the buffer
+     * to the window compositor.  The query sets the returned 'value' argument
+     * to 1 if the ANativeWindow DOES send queued buffers directly to the window
+     * compositor and 0 if the buffers do not go directly to the window
+     * compositor.
+     *
+     * This can be used to determine whether protected buffer content should be
+     * sent to the ANativeWindow.  Note, however, that a result of 1 does NOT
+     * indicate that queued buffers will be protected from applications or users
+     * capturing their contents.  If that behavior is desired then some other
+     * mechanism (e.g. the GRALLOC_USAGE_PROTECTED flag) should be used in
+     * conjunction with this query.
+     */
+    NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
 };
 
 /* valid operations for the (*perform)() hook */
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 43b330c..a40fac9 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -156,6 +156,10 @@
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
         *value = MIN_UNDEQUEUED_BUFFERS;
         return NO_ERROR;
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+        // SurfaceTextureClient currently never queues frames to SurfaceFlinger.
+        *value = 0;
+        return NO_ERROR;
     }
     return BAD_VALUE;
 }
diff --git a/libs/gui/tests/Android.mk b/libs/gui/tests/Android.mk
new file mode 100644
index 0000000..1dd8885
--- /dev/null
+++ b/libs/gui/tests/Android.mk
@@ -0,0 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+    SurfaceTextureClient_test.cpp \
+
+shared_libraries := \
+	libcutils \
+	libutils \
+	libbinder \
+	libgui \
+	libstlport \
+
+static_libraries := \
+	libgtest \
+	libgtest_main \
+
+c_includes := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+module_tags := tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
+include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
new file mode 100644
index 0000000..0f140ff
--- /dev/null
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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 <gui/SurfaceTextureClient.h>
+#include <gtest/gtest.h>
+
+namespace android {
+
+class SurfaceTextureClientTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mST = new SurfaceTexture(123);
+        mSTC = new SurfaceTextureClient(mST);
+    }
+
+    virtual void TearDown() {
+        mST.clear();
+        mSTC.clear();
+    }
+
+    sp<SurfaceTexture> mST;
+    sp<SurfaceTextureClient> mSTC;
+};
+
+TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
+    sp<ANativeWindow> anw(mSTC);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(0, result);
+}
+
+}
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 01ae23f..8951c3f 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -25,9 +25,11 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
+#include <surfaceflinger/ISurfaceComposer.h>
+
 #include <ui/DisplayInfo.h>
 
-#include <surfaceflinger/ISurfaceComposer.h>
+#include <utils/Log.h>
 
 // ---------------------------------------------------------------------------
 
@@ -178,6 +180,40 @@
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual bool authenticateSurface(const sp<ISurface>& surface) const
+    {
+        Parcel data, reply;
+        int err = NO_ERROR;
+        err = data.writeInterfaceToken(
+                ISurfaceComposer::getInterfaceDescriptor());
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error writing "
+                    "interface descriptor: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        err = data.writeStrongBinder(surface->asBinder());
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error writing strong "
+                    "binder to parcel: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data,
+                &reply);
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error performing "
+                    "transaction: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        int32_t result = 0;
+        err = reply.readInt32(&result);
+        if (err != NO_ERROR) {
+            LOGE("ISurfaceComposer::authenticateSurface: error retrieving "
+                    "result: %s (%d)", strerror(-err), -err);
+            return false;
+        }
+        return result != 0;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -273,6 +309,12 @@
             status_t res = turnElectronBeamOn(mode);
             reply->writeInt32(res);
         } break;
+        case AUTHENTICATE_SURFACE: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder());
+            int32_t result = authenticateSurface(surface) ? 1 : 0;
+            reply->writeInt32(result);
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/surfaceflinger_client/Surface.cpp b/libs/surfaceflinger_client/Surface.cpp
index 818114a..afabbf4 100644
--- a/libs/surfaceflinger_client/Surface.cpp
+++ b/libs/surfaceflinger_client/Surface.cpp
@@ -712,6 +712,10 @@
     case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
         *value = MIN_UNDEQUEUED_BUFFERS;
         return NO_ERROR;
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        *value = sf->authenticateSurface(mSurface) ? 1 : 0;
+        return NO_ERROR;
     }
     return BAD_VALUE;
 }
diff --git a/libs/surfaceflinger_client/tests/Android.mk b/libs/surfaceflinger_client/tests/Android.mk
index 5053e7d..212b8e7 100644
--- a/libs/surfaceflinger_client/tests/Android.mk
+++ b/libs/surfaceflinger_client/tests/Android.mk
@@ -1 +1,53 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+ifneq ($(TARGET_SIMULATOR),true)
+
+# Build the unit tests.
+test_src_files := \
+    Surface_test.cpp \
+
+shared_libraries := \
+	libcutils \
+	libutils \
+	libbinder \
+	libsurfaceflinger_client \
+	libstlport \
+
+static_libraries := \
+	libgtest \
+	libgtest_main \
+
+c_includes := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+module_tags := tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
 include $(call all-subdir-makefiles)
+
+endif
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/surfaceflinger_client/tests/Surface_test.cpp b/libs/surfaceflinger_client/tests/Surface_test.cpp
new file mode 100644
index 0000000..b39631c
--- /dev/null
+++ b/libs/surfaceflinger_client/tests/Surface_test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 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 <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+
+#include <utils/String8.h>
+
+namespace android {
+
+class SurfaceTest : public ::testing::Test {
+protected:
+    virtual sp<SurfaceComposerClient> getSurfaceComposerClient() {
+        return sp<SurfaceComposerClient>(new SurfaceComposerClient);
+    }
+
+    virtual void SetUp() {
+        mComposerClient = getSurfaceComposerClient();
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        mSurfaceControl = mComposerClient->createSurface(getpid(),
+                String8("Test Surface"), 0, 32, 32, PIXEL_FORMAT_RGB_888, 0);
+
+        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl->isValid());
+
+        ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
+        ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
+        ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+
+        mSurface = mSurfaceControl->getSurface();
+        ASSERT_TRUE(mSurface != NULL);
+    }
+
+    virtual void TearDown() {
+        mComposerClient->dispose();
+    }
+
+    sp<Surface> mSurface;
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mSurfaceControl;
+};
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenVisible) {
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(1, result);
+}
+
+TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) {
+    mSurfaceControl.clear();
+
+    sp<ANativeWindow> anw(mSurface);
+    int result = -123;
+    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+            &result);
+    EXPECT_EQ(NO_ERROR, err);
+    EXPECT_EQ(1, result);
+}
+
+}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 554fa43..7b19a4c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -327,6 +327,40 @@
     const_cast<SurfaceFlinger*>(this)->signalEvent();
 }
 
+bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
+    Mutex::Autolock _l(mStateLock);
+    sp<IBinder> surfBinder(surface->asBinder());
+
+    // Check the visible layer list for the ISurface
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+        if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+            return true;
+        }
+    }
+
+    // Check the layers in the purgatory.  This check is here so that if a
+    // Surface gets destroyed before all the clients are done using it, the
+    // error will not be reported as "surface XYZ is not authenticated", but
+    // will instead fail later on when the client tries to use the surface,
+    // which should be reported as "surface XYZ returned an -ENODEV".  The
+    // purgatorized layers are no less authentic than the visible ones, so this
+    // should not cause any harm.
+    size_t purgatorySize =  mLayerPurgatory.size();
+    for (size_t i=0 ; i<purgatorySize ; i++) {
+        const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+        sp<LayerBaseClient> lbc(layer->getLayerBaseClient());
+        if (lbc != NULL && lbc->getSurfaceBinder() == surfBinder) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 status_t SurfaceFlinger::postMessageAsync(const sp<MessageBase>& msg,
         nsecs_t reltime, uint32_t flags)
 {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6dd91ac..9566819 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -209,6 +209,7 @@
     virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
     virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
     virtual void                        signal() const;
+    virtual bool                        authenticateSurface(const sp<ISurface>& surface) const;
 
     virtual status_t captureScreen(DisplayID dpy,
             sp<IMemoryHeap>* heap,