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
* dequeue-able buffer. When these various conditions are not met, the caller
* 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:
SharedBufferServer(SharedClient* sharedClient, int surface, int num,
@ -290,6 +283,9 @@ public:
private:
friend class LightRefBase<SharedBufferServer>;
~SharedBufferServer();
/*
* BufferList is basically a fixed-capacity sorted-vector of
* unsigned 5-bits ints using a 32-bits int as storage.

View File

@ -60,7 +60,6 @@ public:
static bool isSameSurface(
const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs);
SurfaceID ID() const { return mToken; }
uint32_t getFlags() const { return mFlags; }
uint32_t getIdentity() const { return mIdentity; }
@ -145,6 +144,9 @@ public:
uint32_t reserved[2];
};
static status_t writeToParcel(
const sp<Surface>& control, Parcel* parcel);
static sp<Surface> readFromParcel(
const Parcel& data, const sp<Surface>& other);
@ -153,7 +155,6 @@ public:
}
bool isValid();
SurfaceID ID() const { return mToken; }
uint32_t getFlags() const { return mFlags; }
uint32_t getIdentity() const { return mIdentity; }
@ -267,7 +268,6 @@ private:
SharedBufferClient* mSharedBufferClient;
status_t mInitCheck;
sp<ISurface> mSurface;
SurfaceID mToken;
uint32_t mIdentity;
PixelFormat mFormat;
uint32_t mFlags;

View File

@ -76,15 +76,18 @@ Layer::~Layer()
status_t Layer::setToken(const sp<UserClient>& userClient,
SharedClient* sharedClient, int32_t token)
{
SharedBufferServer* lcblk = new SharedBufferServer(
sp<SharedBufferServer> lcblk = new SharedBufferServer(
sharedClient, token, mBufferManager.getDefaultBufferCount(),
getIdentity());
status_t err = mUserClientRef.setToken(userClient, lcblk, token);
if (err != NO_ERROR) {
LOGE("ClientRef::setToken(%p, %p, %u) failed",
userClient.get(), lcblk, token);
delete lcblk;
LOGE_IF(err != NO_ERROR,
"ClientRef::setToken(%p, %p, %u) failed",
userClient.get(), lcblk.get(), token);
if (err == NO_ERROR) {
// we need to free the buffers associated with this surface
}
return err;
@ -95,6 +98,11 @@ int32_t Layer::getToken() const
return mUserClientRef.getToken();
}
sp<UserClient> Layer::getClient() const
{
return mUserClientRef.getClient();
}
// called with SurfaceFlinger::mStateLock as soon as the layer is entered
// in the purgatory list
void Layer::onRemoved()
@ -626,11 +634,10 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const
// ---------------------------------------------------------------------------
Layer::ClientRef::ClientRef()
: mToken(-1) {
: mControlBlock(0), mToken(-1) {
}
Layer::ClientRef::~ClientRef() {
delete lcblk;
}
int32_t Layer::ClientRef::getToken() const {
@ -638,14 +645,25 @@ int32_t Layer::ClientRef::getToken() const {
return mToken;
}
status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
SharedBufferServer* sharedClient, int32_t token) {
sp<UserClient> Layer::ClientRef::getClient() const {
Mutex::Autolock _l(mLock);
if (mToken >= 0)
return INVALID_OPERATION;
return mUserClient.promote();
}
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;
mToken = token;
lcblk = sharedClient;
mControlBlock = sharedClient;
return NO_ERROR;
}
@ -657,12 +675,16 @@ sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const {
// it makes sure the UserClient (and its associated shared memory)
// won't go away while we're accessing it.
Layer::ClientRef::Access::Access(const ClientRef& ref)
: lcblk(0)
: mControlBlock(0)
{
Mutex::Autolock _l(ref.mLock);
mUserClientStrongRef = ref.mUserClient.promote();
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
status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
int32_t getToken() const;
sp<UserClient> getClient() const;
// Set this Layer's buffers size
void setBufferSize(uint32_t w, uint32_t h);
@ -119,24 +120,26 @@ private:
ClientRef& operator = (const ClientRef& rhs);
mutable Mutex mLock;
// binder thread, page-flip thread
SharedBufferServer* lcblk;
sp<SharedBufferServer> mControlBlock;
wp<UserClient> mUserClient;
int32_t mToken;
public:
ClientRef();
~ClientRef();
int32_t getToken() const;
sp<UserClient> getClient() const;
status_t setToken(const sp<UserClient>& uc,
SharedBufferServer* sharedClient, int32_t token);
const sp<SharedBufferServer>& sharedClient, int32_t token);
sp<UserClient> getUserClientUnsafe() const;
class Access {
Access(const Access& rhs);
Access& operator = (const Access& rhs);
sp<UserClient> mUserClientStrongRef;
SharedBufferServer* lcblk;
sp<SharedBufferServer> mControlBlock;
public:
Access(const ClientRef& ref);
inline SharedBufferServer* get() const { return lcblk; }
~Access();
inline SharedBufferServer* get() const { return mControlBlock.get(); }
};
friend class Access;
};

View File

@ -1718,7 +1718,10 @@ void UserClient::detachLayer(const Layer* layer)
{
int32_t name = layer->getToken();
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));
if (layer == 0) return name;
// this layer already has a token, just return it
// FIXME: we should check that this token is for the same client
// if this layer already has a token, just return it
name = layer->getToken();
if (name >= 0) return name;
if ((name >= 0) && (layer->getClient() == this))
return name;
name = 0;
do {
int32_t mask = 1LU<<name;
if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
// 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;
}
if (++name > 31)

View File

@ -494,6 +494,10 @@ SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
}
}
SharedBufferServer::~SharedBufferServer()
{
}
ssize_t SharedBufferServer::retireAndLock()
{
RWLock::AutoRLock _l(mLock);

View File

@ -236,17 +236,15 @@ status_t SurfaceControl::validate() const
status_t SurfaceControl::writeSurfaceToParcel(
const sp<SurfaceControl>& control, Parcel* parcel)
{
uint32_t flags = 0;
uint32_t format = 0;
sp<ISurface> sur;
uint32_t identity = 0;
uint32_t width = 0;
uint32_t height = 0;
sp<SurfaceComposerClient> client;
sp<ISurface> sur;
uint32_t format = 0;
uint32_t flags = 0;
if (SurfaceControl::isValid(control)) {
identity = control->mIdentity;
client = control->mClient;
sur = control->mSurface;
identity = control->mIdentity;
width = control->mWidth;
height = control->mHeight;
format = control->mFormat;
@ -349,6 +347,33 @@ Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
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(
const Parcel& data, const sp<Surface>& other)
{
@ -385,11 +410,11 @@ void Surface::init()
mBuffers.insertAt(0, 2);
if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
mToken = mClient.getTokenForSurface(mSurface);
if (mToken >= 0) {
int32_t token = mClient.getTokenForSurface(mSurface);
if (token >= 0) {
mSharedBufferClient = new SharedBufferClient(
mClient.getSharedClient(), mToken, 2, mIdentity);
mInitCheck = mClient.getSharedClient()->validate(mToken);
mClient.getSharedClient(), token, 2, mIdentity);
mInitCheck = mClient.getSharedClient()->validate(token);
}
}
}
@ -421,7 +446,7 @@ status_t Surface::validate() const
{
// check that we initialized ourself properly
if (mInitCheck != NO_ERROR) {
LOGE("invalid token (%d, identity=%u)", mToken, mIdentity);
LOGE("invalid token (identity=%u)", mIdentity);
return mInitCheck;
}
@ -437,17 +462,17 @@ status_t Surface::validate() const
}
if (mIdentity != identity) {
LOGE("[Surface] using an invalid surface id=%d, "
LOGE("[Surface] using an invalid surface, "
"identity=%u should be %d",
mToken, mIdentity, identity);
mIdentity, identity);
return NO_INIT;
}
// check the surface didn't become invalid
status_t err = mSharedBufferClient->getStatus();
if (err != NO_ERROR) {
LOGE("surface (id=%d, identity=%u) is invalid, err=%d (%s)",
mToken, mIdentity, err, strerror(-err));
LOGE("surface (identity=%u) is invalid, err=%d (%s)",
mIdentity, err, strerror(-err));
return err;
}

View File

@ -111,6 +111,9 @@ status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
if (mOwner != ownData)
return INVALID_OPERATION;
if (handle && w==width && h==height && f==format && reqUsage==usage)
return NO_ERROR;
if (handle) {
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);