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:
parent
01de8bf052
commit
134f042286
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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
53
libs/gui/tests/Android.mk
Normal 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
|
47
libs/gui/tests/SurfaceTextureClient_test.cpp
Normal file
47
libs/gui/tests/SurfaceTextureClient_test.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
80
libs/surfaceflinger_client/tests/Surface_test.cpp
Normal file
80
libs/surfaceflinger_client/tests/Surface_test.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user