allow re-targetting of surfaces
Surfaces can now be parcelized and sent to remote processes. When a surface crosses a process boundary, it looses its connection with the current process and gets attached to the new one. Change-Id: I39c7b055bcd3ea1162ef2718d3d4b866bf7c81c0
This commit is contained in:
parent
53503a97a9
commit
579b3f88d0
|
@ -43,15 +43,6 @@ namespace android {
|
||||||
* unless they are in use by the server, which is only the case for the last
|
* unless they are in use by the server, which is only the case for the last
|
||||||
* dequeue-able buffer. When these various conditions are not met, the caller
|
* dequeue-able buffer. When these various conditions are not met, the caller
|
||||||
* waits until the condition is met.
|
* waits until the condition is met.
|
||||||
*
|
|
||||||
*
|
|
||||||
* CAVEATS:
|
|
||||||
*
|
|
||||||
* In the current implementation there are several limitations:
|
|
||||||
* - buffers must be locked in the same order they've been dequeued
|
|
||||||
* - buffers must be enqueued in the same order they've been locked
|
|
||||||
* - dequeue() is not reentrant
|
|
||||||
* - no error checks are done on the condition above
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -269,7 +260,9 @@ private:
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class SharedBufferServer : public SharedBufferBase
|
class SharedBufferServer
|
||||||
|
: public SharedBufferBase,
|
||||||
|
public LightRefBase<SharedBufferServer>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SharedBufferServer(SharedClient* sharedClient, int surface, int num,
|
SharedBufferServer(SharedClient* sharedClient, int surface, int num,
|
||||||
|
@ -290,6 +283,9 @@ public:
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class LightRefBase<SharedBufferServer>;
|
||||||
|
~SharedBufferServer();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BufferList is basically a fixed-capacity sorted-vector of
|
* BufferList is basically a fixed-capacity sorted-vector of
|
||||||
* unsigned 5-bits ints using a 32-bits int as storage.
|
* unsigned 5-bits ints using a 32-bits int as storage.
|
||||||
|
|
|
@ -60,7 +60,6 @@ public:
|
||||||
static bool isSameSurface(
|
static bool isSameSurface(
|
||||||
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
|
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
|
||||||
|
|
||||||
SurfaceID ID() const { return mToken; }
|
|
||||||
uint32_t getFlags() const { return mFlags; }
|
uint32_t getFlags() const { return mFlags; }
|
||||||
uint32_t getIdentity() const { return mIdentity; }
|
uint32_t getIdentity() const { return mIdentity; }
|
||||||
|
|
||||||
|
@ -145,6 +144,9 @@ public:
|
||||||
uint32_t reserved[2];
|
uint32_t reserved[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static status_t writeToParcel(
|
||||||
|
const sp<Surface>& control, Parcel* parcel);
|
||||||
|
|
||||||
static sp<Surface> readFromParcel(
|
static sp<Surface> readFromParcel(
|
||||||
const Parcel& data, const sp<Surface>& other);
|
const Parcel& data, const sp<Surface>& other);
|
||||||
|
|
||||||
|
@ -153,7 +155,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isValid();
|
bool isValid();
|
||||||
SurfaceID ID() const { return mToken; }
|
|
||||||
uint32_t getFlags() const { return mFlags; }
|
uint32_t getFlags() const { return mFlags; }
|
||||||
uint32_t getIdentity() const { return mIdentity; }
|
uint32_t getIdentity() const { return mIdentity; }
|
||||||
|
|
||||||
|
@ -267,7 +268,6 @@ private:
|
||||||
SharedBufferClient* mSharedBufferClient;
|
SharedBufferClient* mSharedBufferClient;
|
||||||
status_t mInitCheck;
|
status_t mInitCheck;
|
||||||
sp<ISurface> mSurface;
|
sp<ISurface> mSurface;
|
||||||
SurfaceID mToken;
|
|
||||||
uint32_t mIdentity;
|
uint32_t mIdentity;
|
||||||
PixelFormat mFormat;
|
PixelFormat mFormat;
|
||||||
uint32_t mFlags;
|
uint32_t mFlags;
|
||||||
|
|
|
@ -76,15 +76,18 @@ Layer::~Layer()
|
||||||
status_t Layer::setToken(const sp<UserClient>& userClient,
|
status_t Layer::setToken(const sp<UserClient>& userClient,
|
||||||
SharedClient* sharedClient, int32_t token)
|
SharedClient* sharedClient, int32_t token)
|
||||||
{
|
{
|
||||||
SharedBufferServer* lcblk = new SharedBufferServer(
|
sp<SharedBufferServer> lcblk = new SharedBufferServer(
|
||||||
sharedClient, token, mBufferManager.getDefaultBufferCount(),
|
sharedClient, token, mBufferManager.getDefaultBufferCount(),
|
||||||
getIdentity());
|
getIdentity());
|
||||||
|
|
||||||
status_t err = mUserClientRef.setToken(userClient, lcblk, token);
|
status_t err = mUserClientRef.setToken(userClient, lcblk, token);
|
||||||
if (err != NO_ERROR) {
|
|
||||||
LOGE("ClientRef::setToken(%p, %p, %u) failed",
|
LOGE_IF(err != NO_ERROR,
|
||||||
userClient.get(), lcblk, token);
|
"ClientRef::setToken(%p, %p, %u) failed",
|
||||||
delete lcblk;
|
userClient.get(), lcblk.get(), token);
|
||||||
|
|
||||||
|
if (err == NO_ERROR) {
|
||||||
|
// we need to free the buffers associated with this surface
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -95,6 +98,11 @@ int32_t Layer::getToken() const
|
||||||
return mUserClientRef.getToken();
|
return mUserClientRef.getToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sp<UserClient> Layer::getClient() const
|
||||||
|
{
|
||||||
|
return mUserClientRef.getClient();
|
||||||
|
}
|
||||||
|
|
||||||
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
|
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
|
||||||
// in the purgatory list
|
// in the purgatory list
|
||||||
void Layer::onRemoved()
|
void Layer::onRemoved()
|
||||||
|
@ -626,11 +634,10 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
Layer::ClientRef::ClientRef()
|
Layer::ClientRef::ClientRef()
|
||||||
: mToken(-1) {
|
: mControlBlock(0), mToken(-1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Layer::ClientRef::~ClientRef() {
|
Layer::ClientRef::~ClientRef() {
|
||||||
delete lcblk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t Layer::ClientRef::getToken() const {
|
int32_t Layer::ClientRef::getToken() const {
|
||||||
|
@ -638,14 +645,25 @@ int32_t Layer::ClientRef::getToken() const {
|
||||||
return mToken;
|
return mToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
|
sp<UserClient> Layer::ClientRef::getClient() const {
|
||||||
SharedBufferServer* sharedClient, int32_t token) {
|
|
||||||
Mutex::Autolock _l(mLock);
|
Mutex::Autolock _l(mLock);
|
||||||
if (mToken >= 0)
|
return mUserClient.promote();
|
||||||
return INVALID_OPERATION;
|
}
|
||||||
|
|
||||||
|
status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
|
||||||
|
const sp<SharedBufferServer>& sharedClient, int32_t token) {
|
||||||
|
Mutex::Autolock _l(mLock);
|
||||||
|
|
||||||
|
{ // scope for strong mUserClient reference
|
||||||
|
sp<UserClient> userClient(mUserClient.promote());
|
||||||
|
if (mUserClient != 0 && mControlBlock != 0) {
|
||||||
|
mControlBlock->setStatus(NO_INIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mUserClient = uc;
|
mUserClient = uc;
|
||||||
mToken = token;
|
mToken = token;
|
||||||
lcblk = sharedClient;
|
mControlBlock = sharedClient;
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -657,12 +675,16 @@ sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const {
|
||||||
// it makes sure the UserClient (and its associated shared memory)
|
// it makes sure the UserClient (and its associated shared memory)
|
||||||
// won't go away while we're accessing it.
|
// won't go away while we're accessing it.
|
||||||
Layer::ClientRef::Access::Access(const ClientRef& ref)
|
Layer::ClientRef::Access::Access(const ClientRef& ref)
|
||||||
: lcblk(0)
|
: mControlBlock(0)
|
||||||
{
|
{
|
||||||
Mutex::Autolock _l(ref.mLock);
|
Mutex::Autolock _l(ref.mLock);
|
||||||
mUserClientStrongRef = ref.mUserClient.promote();
|
mUserClientStrongRef = ref.mUserClient.promote();
|
||||||
if (mUserClientStrongRef != 0)
|
if (mUserClientStrongRef != 0)
|
||||||
lcblk = ref.lcblk;
|
mControlBlock = ref.mControlBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layer::ClientRef::Access::~Access()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -60,6 +60,7 @@ public:
|
||||||
// associate a UserClient to this Layer
|
// associate a UserClient to this Layer
|
||||||
status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
|
status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
|
||||||
int32_t getToken() const;
|
int32_t getToken() const;
|
||||||
|
sp<UserClient> getClient() const;
|
||||||
|
|
||||||
// Set this Layer's buffers size
|
// Set this Layer's buffers size
|
||||||
void setBufferSize(uint32_t w, uint32_t h);
|
void setBufferSize(uint32_t w, uint32_t h);
|
||||||
|
@ -119,24 +120,26 @@ private:
|
||||||
ClientRef& operator = (const ClientRef& rhs);
|
ClientRef& operator = (const ClientRef& rhs);
|
||||||
mutable Mutex mLock;
|
mutable Mutex mLock;
|
||||||
// binder thread, page-flip thread
|
// binder thread, page-flip thread
|
||||||
SharedBufferServer* lcblk;
|
sp<SharedBufferServer> mControlBlock;
|
||||||
wp<UserClient> mUserClient;
|
wp<UserClient> mUserClient;
|
||||||
int32_t mToken;
|
int32_t mToken;
|
||||||
public:
|
public:
|
||||||
ClientRef();
|
ClientRef();
|
||||||
~ClientRef();
|
~ClientRef();
|
||||||
int32_t getToken() const;
|
int32_t getToken() const;
|
||||||
|
sp<UserClient> getClient() const;
|
||||||
status_t setToken(const sp<UserClient>& uc,
|
status_t setToken(const sp<UserClient>& uc,
|
||||||
SharedBufferServer* sharedClient, int32_t token);
|
const sp<SharedBufferServer>& sharedClient, int32_t token);
|
||||||
sp<UserClient> getUserClientUnsafe() const;
|
sp<UserClient> getUserClientUnsafe() const;
|
||||||
class Access {
|
class Access {
|
||||||
Access(const Access& rhs);
|
Access(const Access& rhs);
|
||||||
Access& operator = (const Access& rhs);
|
Access& operator = (const Access& rhs);
|
||||||
sp<UserClient> mUserClientStrongRef;
|
sp<UserClient> mUserClientStrongRef;
|
||||||
SharedBufferServer* lcblk;
|
sp<SharedBufferServer> mControlBlock;
|
||||||
public:
|
public:
|
||||||
Access(const ClientRef& ref);
|
Access(const ClientRef& ref);
|
||||||
inline SharedBufferServer* get() const { return lcblk; }
|
~Access();
|
||||||
|
inline SharedBufferServer* get() const { return mControlBlock.get(); }
|
||||||
};
|
};
|
||||||
friend class Access;
|
friend class Access;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1718,7 +1718,10 @@ void UserClient::detachLayer(const Layer* layer)
|
||||||
{
|
{
|
||||||
int32_t name = layer->getToken();
|
int32_t name = layer->getToken();
|
||||||
if (name >= 0) {
|
if (name >= 0) {
|
||||||
android_atomic_and(~(1LU<<name), &mBitmap);
|
int32_t mask = 1LU<<name;
|
||||||
|
if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) {
|
||||||
|
LOGW("token %d wasn't marked as used %08x", name, int(mBitmap));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1732,17 +1735,23 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
|
||||||
sp<Layer> layer(mFlinger->getLayer(sur));
|
sp<Layer> layer(mFlinger->getLayer(sur));
|
||||||
if (layer == 0) return name;
|
if (layer == 0) return name;
|
||||||
|
|
||||||
// this layer already has a token, just return it
|
// if this layer already has a token, just return it
|
||||||
// FIXME: we should check that this token is for the same client
|
|
||||||
name = layer->getToken();
|
name = layer->getToken();
|
||||||
if (name >= 0) return name;
|
if ((name >= 0) && (layer->getClient() == this))
|
||||||
|
return name;
|
||||||
|
|
||||||
name = 0;
|
name = 0;
|
||||||
do {
|
do {
|
||||||
int32_t mask = 1LU<<name;
|
int32_t mask = 1LU<<name;
|
||||||
if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
|
if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
|
||||||
// we found and locked that name
|
// we found and locked that name
|
||||||
layer->setToken(const_cast<UserClient*>(this), ctrlblk, name);
|
status_t err = layer->setToken(
|
||||||
|
const_cast<UserClient*>(this), ctrlblk, name);
|
||||||
|
if (err != NO_ERROR) {
|
||||||
|
// free the name
|
||||||
|
android_atomic_and(~mask, &mBitmap);
|
||||||
|
name = err;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (++name > 31)
|
if (++name > 31)
|
||||||
|
|
|
@ -494,6 +494,10 @@ SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedBufferServer::~SharedBufferServer()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t SharedBufferServer::retireAndLock()
|
ssize_t SharedBufferServer::retireAndLock()
|
||||||
{
|
{
|
||||||
RWLock::AutoRLock _l(mLock);
|
RWLock::AutoRLock _l(mLock);
|
||||||
|
|
|
@ -236,17 +236,15 @@ status_t SurfaceControl::validate() const
|
||||||
status_t SurfaceControl::writeSurfaceToParcel(
|
status_t SurfaceControl::writeSurfaceToParcel(
|
||||||
const sp<SurfaceControl>& control, Parcel* parcel)
|
const sp<SurfaceControl>& control, Parcel* parcel)
|
||||||
{
|
{
|
||||||
uint32_t flags = 0;
|
sp<ISurface> sur;
|
||||||
uint32_t format = 0;
|
|
||||||
uint32_t identity = 0;
|
uint32_t identity = 0;
|
||||||
uint32_t width = 0;
|
uint32_t width = 0;
|
||||||
uint32_t height = 0;
|
uint32_t height = 0;
|
||||||
sp<SurfaceComposerClient> client;
|
uint32_t format = 0;
|
||||||
sp<ISurface> sur;
|
uint32_t flags = 0;
|
||||||
if (SurfaceControl::isValid(control)) {
|
if (SurfaceControl::isValid(control)) {
|
||||||
identity = control->mIdentity;
|
|
||||||
client = control->mClient;
|
|
||||||
sur = control->mSurface;
|
sur = control->mSurface;
|
||||||
|
identity = control->mIdentity;
|
||||||
width = control->mWidth;
|
width = control->mWidth;
|
||||||
height = control->mHeight;
|
height = control->mHeight;
|
||||||
format = control->mFormat;
|
format = control->mFormat;
|
||||||
|
@ -349,6 +347,33 @@ Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t Surface::writeToParcel(
|
||||||
|
const sp<Surface>& surface, Parcel* parcel)
|
||||||
|
{
|
||||||
|
sp<ISurface> sur;
|
||||||
|
uint32_t identity = 0;
|
||||||
|
uint32_t width = 0;
|
||||||
|
uint32_t height = 0;
|
||||||
|
uint32_t format = 0;
|
||||||
|
uint32_t flags = 0;
|
||||||
|
if (Surface::isValid(surface)) {
|
||||||
|
sur = surface->mSurface;
|
||||||
|
identity = surface->mIdentity;
|
||||||
|
width = surface->mWidth;
|
||||||
|
height = surface->mHeight;
|
||||||
|
format = surface->mFormat;
|
||||||
|
flags = surface->mFlags;
|
||||||
|
}
|
||||||
|
parcel->writeStrongBinder(sur!=0 ? sur->asBinder() : NULL);
|
||||||
|
parcel->writeInt32(identity);
|
||||||
|
parcel->writeInt32(width);
|
||||||
|
parcel->writeInt32(height);
|
||||||
|
parcel->writeInt32(format);
|
||||||
|
parcel->writeInt32(flags);
|
||||||
|
return NO_ERROR;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
sp<Surface> Surface::readFromParcel(
|
sp<Surface> Surface::readFromParcel(
|
||||||
const Parcel& data, const sp<Surface>& other)
|
const Parcel& data, const sp<Surface>& other)
|
||||||
{
|
{
|
||||||
|
@ -385,11 +410,11 @@ void Surface::init()
|
||||||
mBuffers.insertAt(0, 2);
|
mBuffers.insertAt(0, 2);
|
||||||
|
|
||||||
if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
|
if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
|
||||||
mToken = mClient.getTokenForSurface(mSurface);
|
int32_t token = mClient.getTokenForSurface(mSurface);
|
||||||
if (mToken >= 0) {
|
if (token >= 0) {
|
||||||
mSharedBufferClient = new SharedBufferClient(
|
mSharedBufferClient = new SharedBufferClient(
|
||||||
mClient.getSharedClient(), mToken, 2, mIdentity);
|
mClient.getSharedClient(), token, 2, mIdentity);
|
||||||
mInitCheck = mClient.getSharedClient()->validate(mToken);
|
mInitCheck = mClient.getSharedClient()->validate(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,7 +446,7 @@ status_t Surface::validate() const
|
||||||
{
|
{
|
||||||
// check that we initialized ourself properly
|
// check that we initialized ourself properly
|
||||||
if (mInitCheck != NO_ERROR) {
|
if (mInitCheck != NO_ERROR) {
|
||||||
LOGE("invalid token (%d, identity=%u)", mToken, mIdentity);
|
LOGE("invalid token (identity=%u)", mIdentity);
|
||||||
return mInitCheck;
|
return mInitCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -437,17 +462,17 @@ status_t Surface::validate() const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIdentity != identity) {
|
if (mIdentity != identity) {
|
||||||
LOGE("[Surface] using an invalid surface id=%d, "
|
LOGE("[Surface] using an invalid surface, "
|
||||||
"identity=%u should be %d",
|
"identity=%u should be %d",
|
||||||
mToken, mIdentity, identity);
|
mIdentity, identity);
|
||||||
return NO_INIT;
|
return NO_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the surface didn't become invalid
|
// check the surface didn't become invalid
|
||||||
status_t err = mSharedBufferClient->getStatus();
|
status_t err = mSharedBufferClient->getStatus();
|
||||||
if (err != NO_ERROR) {
|
if (err != NO_ERROR) {
|
||||||
LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
|
LOGE("surface (identity=%u) is invalid, err=%d (%s)",
|
||||||
mToken, mIdentity, err, strerror(-err));
|
mIdentity, err, strerror(-err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,6 +111,9 @@ status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
|
||||||
if (mOwner != ownData)
|
if (mOwner != ownData)
|
||||||
return INVALID_OPERATION;
|
return INVALID_OPERATION;
|
||||||
|
|
||||||
|
if (handle && w==width && h==height && f==format && reqUsage==usage)
|
||||||
|
return NO_ERROR;
|
||||||
|
|
||||||
if (handle) {
|
if (handle) {
|
||||||
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
|
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
|
||||||
allocator.free(handle);
|
allocator.free(handle);
|
||||||
|
|
Loading…
Reference in New Issue