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:
Mathias Agopian 2010-06-08 19:54:15 -07:00
parent 53503a97a9
commit 579b3f88d0
8 changed files with 113 additions and 51 deletions

View File

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

View File

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

View File

@ -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()
{
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

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

View File

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

View File

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

View File

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

View File

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