ANativeWindow: add queues-to-window-composer check.

This change adds a new 'method' to the ANativeWindow interface to check
whether buffers queued to the window will be sent directly to the system
window compositor.

Change-Id: I4d4b199e328c110b68b250029aea650f03c8724d
Bug: 3495535
This commit is contained in:
Jamie Gennis 2011-03-08 12:18:54 -08:00
parent 01de8bf052
commit 134f042286
11 changed files with 339 additions and 2 deletions

View File

@ -138,6 +138,10 @@ public:
* 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 @@ public:
SIGNAL,
CAPTURE_SCREEN,
TURN_ELECTRON_BEAM_OFF,
TURN_ELECTRON_BEAM_ON
TURN_ELECTRON_BEAM_ON,
AUTHENTICATE_SURFACE,
};
virtual status_t onTransact( uint32_t code,

View File

@ -95,6 +95,21 @@ enum {
* 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 */

View File

@ -156,6 +156,10 @@ int SurfaceTextureClient::query(int what, int* value) {
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;
}

53
libs/gui/tests/Android.mk Normal file
View File

@ -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

View File

@ -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);
}
}

View File

@ -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 @@ public:
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 BnSurfaceComposer::onTransact(
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);
}

View File

@ -712,6 +712,10 @@ int Surface::query(int what, int* value)
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;
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -327,6 +327,40 @@ void SurfaceFlinger::signal() const {
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)
{

View File

@ -209,6 +209,7 @@ public:
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,