/* * Copyright (C) 2007 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. */ #define LOG_TAG "SurfaceComposerClient" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define VERBOSE(...) ((void)0) //#define VERBOSE LOGD #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) namespace android { // --------------------------------------------------------------------------- // Must not be holding SurfaceComposerClient::mLock when acquiring gLock here. static Mutex gLock; static sp gSurfaceManager; static DefaultKeyedVector< sp, wp > gActiveConnections; static SortedVector > gOpenTransactions; static sp gServerCblkMemory; static volatile surface_flinger_cblk_t* gServerCblk; static sp getComposerService() { sp sc; Mutex::Autolock _l(gLock); if (gSurfaceManager != 0) { sc = gSurfaceManager; } else { // release the lock while we're waiting... gLock.unlock(); sp binder; sp sm = defaultServiceManager(); do { binder = sm->getService(String16("SurfaceFlinger")); if (binder == 0) { LOGW("SurfaceFlinger not published, waiting..."); usleep(500000); // 0.5 s } } while(binder == 0); // grab the lock again for updating gSurfaceManager gLock.lock(); if (gSurfaceManager == 0) { sc = interface_cast(binder); gSurfaceManager = sc; } else { sc = gSurfaceManager; } } return sc; } static volatile surface_flinger_cblk_t const * get_cblk() { if (gServerCblk == 0) { sp sm(getComposerService()); Mutex::Autolock _l(gLock); if (gServerCblk == 0) { gServerCblkMemory = sm->getCblk(); LOGE_IF(gServerCblkMemory==0, "Can't get server control block"); gServerCblk = (surface_flinger_cblk_t *)gServerCblkMemory->getBase(); LOGE_IF(gServerCblk==0, "Can't get server control block address"); } } return gServerCblk; } // --------------------------------------------------------------------------- static inline int compare_type( const layer_state_t& lhs, const layer_state_t& rhs) { if (lhs.surface < rhs.surface) return -1; if (lhs.surface > rhs.surface) return 1; return 0; } SurfaceComposerClient::SurfaceComposerClient() { sp sm(getComposerService()); if (sm == 0) { _init(0, 0); return; } _init(sm, sm->createConnection()); if (mClient != 0) { Mutex::Autolock _l(gLock); VERBOSE("Adding client %p to map", this); gActiveConnections.add(mClient->asBinder(), this); } } SurfaceComposerClient::SurfaceComposerClient( const sp& sm, const sp& conn) { _init(sm, interface_cast(conn)); } status_t SurfaceComposerClient::linkToComposerDeath( const sp& recipient, void* cookie, uint32_t flags) { sp sm(getComposerService()); return sm->asBinder()->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::_init( const sp& sm, const sp& conn) { VERBOSE("Creating client %p, conn %p", this, conn.get()); mPrebuiltLayerState = 0; mTransactionOpen = 0; mStatus = NO_ERROR; mControl = 0; mClient = conn; if (mClient == 0) { mStatus = NO_INIT; return; } mControlMemory = mClient->getControlBlock(); mSignalServer = sm; mControl = static_cast(mControlMemory->getBase()); } SurfaceComposerClient::~SurfaceComposerClient() { VERBOSE("Destroying client %p, conn %p", this, mClient.get()); dispose(); } status_t SurfaceComposerClient::initCheck() const { return mStatus; } sp SurfaceComposerClient::connection() const { return (mClient != 0) ? mClient->asBinder() : 0; } sp SurfaceComposerClient::clientForConnection(const sp& conn) { sp client; { // scope for lock Mutex::Autolock _l(gLock); client = gActiveConnections.valueFor(conn).promote(); } if (client == 0) { // Need to make a new client. sp sm(getComposerService()); client = new SurfaceComposerClient(sm, conn); if (client != 0 && client->initCheck() == NO_ERROR) { Mutex::Autolock _l(gLock); gActiveConnections.add(conn, client); //LOGD("we have %d connections", gActiveConnections.size()); } else { client.clear(); } } return client; } void SurfaceComposerClient::dispose() { // this can be called more than once. sp controlMemory; sp client; { Mutex::Autolock _lg(gLock); Mutex::Autolock _lm(mLock); mSignalServer = 0; if (mClient != 0) { client = mClient; mClient.clear(); ssize_t i = gActiveConnections.indexOfKey(client->asBinder()); if (i >= 0 && gActiveConnections.valueAt(i) == this) { VERBOSE("Removing client %p from map at %d", this, int(i)); gActiveConnections.removeItemsAt(i); } } delete mPrebuiltLayerState; mPrebuiltLayerState = 0; controlMemory = mControlMemory; mControlMemory.clear(); mControl = 0; mStatus = NO_INIT; } } status_t SurfaceComposerClient::getDisplayInfo( DisplayID dpy, DisplayInfo* info) { if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; info->w = dcblk->w; info->h = dcblk->h; info->orientation = dcblk->orientation; info->xdpi = dcblk->xdpi; info->ydpi = dcblk->ydpi; info->fps = dcblk->fps; info->density = dcblk->density; return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo)); } ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy) { if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; return dcblk->w; } ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy) { if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; return dcblk->h; } ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy) { if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX) return BAD_VALUE; volatile surface_flinger_cblk_t const * cblk = get_cblk(); volatile display_cblk_t const * dcblk = cblk->displays + dpy; return dcblk->orientation; } ssize_t SurfaceComposerClient::getNumberOfDisplays() { volatile surface_flinger_cblk_t const * cblk = get_cblk(); uint32_t connected = cblk->connected; int n = 0; while (connected) { if (connected&1) n++; connected >>= 1; } return n; } void SurfaceComposerClient::signalServer() { mSignalServer->signal(); } sp SurfaceComposerClient::createSurface( int pid, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { String8 name; const size_t SIZE = 128; char buffer[SIZE]; snprintf(buffer, SIZE, "", getpid()); name.append(buffer); return SurfaceComposerClient::createSurface(pid, name, display, w, h, format, flags); } sp SurfaceComposerClient::createSurface( int pid, const String8& name, DisplayID display, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { sp result; if (mStatus == NO_ERROR) { ISurfaceFlingerClient::surface_data_t data; sp surface = mClient->createSurface(&data, pid, name, display, w, h, format, flags); if (surface != 0) { if (uint32_t(data.token) < SharedBufferStack::NUM_LAYERS_MAX) { result = new SurfaceControl(this, surface, data, w, h, format, flags); } } } return result; } status_t SurfaceComposerClient::destroySurface(SurfaceID sid) { if (mStatus != NO_ERROR) return mStatus; // it's okay to destroy a surface while a transaction is open, // (transactions really are a client-side concept) // however, this indicates probably a misuse of the API or a bug // in the client code. LOGW_IF(mTransactionOpen, "Destroying surface while a transaction is open. " "Client %p: destroying surface %d, mTransactionOpen=%d", this, sid, mTransactionOpen); status_t err = mClient->destroySurface(sid); return err; } void SurfaceComposerClient::openGlobalTransaction() { Mutex::Autolock _l(gLock); if (gOpenTransactions.size()) { LOGE("openGlobalTransaction() called more than once. skipping."); return; } const size_t N = gActiveConnections.size(); VERBOSE("openGlobalTransaction (%ld clients)", N); for (size_t i=0; i client(gActiveConnections.valueAt(i).promote()); if (client != 0 && gOpenTransactions.indexOf(client) < 0) { if (client->openTransaction() == NO_ERROR) { if (gOpenTransactions.add(client) < 0) { // Ooops! LOGE( "Unable to add a SurfaceComposerClient " "to the global transaction set (out of memory?)"); client->closeTransaction(); // let it go, it'll fail later when the user // tries to do something with the transaction } } else { LOGE("openTransaction on client %p failed", client.get()); // let it go, it'll fail later when the user // tries to do something with the transaction } } } } void SurfaceComposerClient::closeGlobalTransaction() { gLock.lock(); SortedVector< sp > clients(gOpenTransactions); gOpenTransactions.clear(); gLock.unlock(); const size_t N = clients.size(); VERBOSE("closeGlobalTransaction (%ld clients)", N); sp sm(getComposerService()); sm->openGlobalTransaction(); for (size_t i=0; icloseTransaction(); } sm->closeGlobalTransaction(); } status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { sp sm(getComposerService()); return sm->freezeDisplay(dpy, flags); } status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) { sp sm(getComposerService()); return sm->unfreezeDisplay(dpy, flags); } int SurfaceComposerClient::setOrientation(DisplayID dpy, int orientation, uint32_t flags) { sp sm(getComposerService()); return sm->setOrientation(dpy, orientation, flags); } status_t SurfaceComposerClient::openTransaction() { if (mStatus != NO_ERROR) return mStatus; Mutex::Autolock _l(mLock); VERBOSE( "openTransaction (client %p, mTransactionOpen=%d)", this, mTransactionOpen); mTransactionOpen++; if (mPrebuiltLayerState == 0) { mPrebuiltLayerState = new layer_state_t; } return NO_ERROR; } status_t SurfaceComposerClient::closeTransaction() { if (mStatus != NO_ERROR) return mStatus; Mutex::Autolock _l(mLock); VERBOSE( "closeTransaction (client %p, mTransactionOpen=%d)", this, mTransactionOpen); if (mTransactionOpen <= 0) { LOGE( "closeTransaction (client %p, mTransactionOpen=%d) " "called more times than openTransaction()", this, mTransactionOpen); return INVALID_OPERATION; } if (mTransactionOpen >= 2) { mTransactionOpen--; return NO_ERROR; } mTransactionOpen = 0; const ssize_t count = mStates.size(); if (count) { mClient->setState(count, mStates.array()); mStates.clear(); } return NO_ERROR; } layer_state_t* SurfaceComposerClient::_get_state_l(SurfaceID index) { // API usage error, do nothing. if (mTransactionOpen<=0) { LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d", this, int(index), mTransactionOpen); return 0; } // use mPrebuiltLayerState just to find out if we already have it layer_state_t& dummy = *mPrebuiltLayerState; dummy.surface = index; ssize_t i = mStates.indexOf(dummy); if (i < 0) { // we don't have it, add an initialized layer_state to our list i = mStates.add(dummy); } return mStates.editArray() + i; } layer_state_t* SurfaceComposerClient::_lockLayerState(SurfaceID id) { layer_state_t* s; mLock.lock(); s = _get_state_l(id); if (!s) mLock.unlock(); return s; } void SurfaceComposerClient::_unlockLayerState() { mLock.unlock(); } status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::ePositionChanged; s->x = x; s->y = y; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eSizeChanged; s->w = w; s->h = h; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eLayerChanged; s->z = z; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::hide(SurfaceID id) { return setFlags(id, ISurfaceComposer::eLayerHidden, ISurfaceComposer::eLayerHidden); } status_t SurfaceComposerClient::show(SurfaceID id, int32_t) { return setFlags(id, 0, ISurfaceComposer::eLayerHidden); } status_t SurfaceComposerClient::freeze(SurfaceID id) { return setFlags(id, ISurfaceComposer::eLayerFrozen, ISurfaceComposer::eLayerFrozen); } status_t SurfaceComposerClient::unfreeze(SurfaceID id) { return setFlags(id, 0, ISurfaceComposer::eLayerFrozen); } status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags, uint32_t mask) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eVisibilityChanged; s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setTransparentRegionHint( SurfaceID id, const Region& transparentRegion) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eTransparentRegionChanged; s->transparentRegion = transparentRegion; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eAlphaChanged; s->alpha = alpha; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setMatrix( SurfaceID id, float dsdx, float dtdx, float dsdy, float dtdy ) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; matrix.dtdx = dtdx; matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; _unlockLayerState(); return NO_ERROR; } status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) { layer_state_t* s = _lockLayerState(id); if (!s) return BAD_INDEX; s->what |= ISurfaceComposer::eFreezeTintChanged; s->tint = tint; _unlockLayerState(); return NO_ERROR; } }; // namespace android