|  | /* | 
|  | * 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 "SurfaceFlinger" | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <stdint.h> | 
|  | #include <unistd.h> | 
|  | #include <fcntl.h> | 
|  | #include <errno.h> | 
|  | #include <math.h> | 
|  | #include <limits.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <sys/ioctl.h> | 
|  |  | 
|  | #include <cutils/log.h> | 
|  | #include <cutils/properties.h> | 
|  |  | 
|  | #include <utils/IPCThreadState.h> | 
|  | #include <utils/IServiceManager.h> | 
|  | #include <utils/MemoryDealer.h> | 
|  | #include <utils/MemoryBase.h> | 
|  | #include <utils/String8.h> | 
|  | #include <utils/String16.h> | 
|  | #include <utils/StopWatch.h> | 
|  |  | 
|  | #include <ui/PixelFormat.h> | 
|  | #include <ui/DisplayInfo.h> | 
|  | #include <ui/EGLDisplaySurface.h> | 
|  |  | 
|  | #include <pixelflinger/pixelflinger.h> | 
|  | #include <GLES/gl.h> | 
|  |  | 
|  | #include "clz.h" | 
|  | #include "CPUGauge.h" | 
|  | #include "Layer.h" | 
|  | #include "LayerBlur.h" | 
|  | #include "LayerBuffer.h" | 
|  | #include "LayerDim.h" | 
|  | #include "LayerBitmap.h" | 
|  | #include "LayerOrientationAnim.h" | 
|  | #include "OrientationAnimation.h" | 
|  | #include "SurfaceFlinger.h" | 
|  | #include "VRamHeap.h" | 
|  |  | 
|  | #include "DisplayHardware/DisplayHardware.h" | 
|  | #include "GPUHardware/GPUHardware.h" | 
|  |  | 
|  |  | 
|  | #define DISPLAY_COUNT       1 | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | void SurfaceFlinger::instantiate() { | 
|  | defaultServiceManager()->addService( | 
|  | String16("SurfaceFlinger"), new SurfaceFlinger()); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::shutdown() { | 
|  | // we should unregister here, but not really because | 
|  | // when (if) the service manager goes away, all the services | 
|  | // it has a reference to will leave too. | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | SurfaceFlinger::LayerVector::LayerVector(const SurfaceFlinger::LayerVector& rhs) | 
|  | : lookup(rhs.lookup), layers(rhs.layers) | 
|  | { | 
|  | } | 
|  |  | 
|  | ssize_t SurfaceFlinger::LayerVector::indexOf( | 
|  | LayerBase* key, size_t guess) const | 
|  | { | 
|  | if (guess<size() && lookup.keyAt(guess) == key) | 
|  | return guess; | 
|  | const ssize_t i = lookup.indexOfKey(key); | 
|  | if (i>=0) { | 
|  | const size_t idx = lookup.valueAt(i); | 
|  | LOG_ASSERT(layers[idx]==key, | 
|  | "LayerVector[%p]: layers[%d]=%p, key=%p", | 
|  | this, int(idx), layers[idx], key); | 
|  | return idx; | 
|  | } | 
|  | return i; | 
|  | } | 
|  |  | 
|  | ssize_t SurfaceFlinger::LayerVector::add( | 
|  | LayerBase* layer, | 
|  | Vector<LayerBase*>::compar_t cmp) | 
|  | { | 
|  | size_t count = layers.size(); | 
|  | ssize_t l = 0; | 
|  | ssize_t h = count-1; | 
|  | ssize_t mid; | 
|  | LayerBase* const* a = layers.array(); | 
|  | while (l <= h) { | 
|  | mid = l + (h - l)/2; | 
|  | const int c = cmp(a+mid, &layer); | 
|  | if (c == 0)     { l = mid; break; } | 
|  | else if (c<0)   { l = mid+1; } | 
|  | else            { h = mid-1; } | 
|  | } | 
|  | size_t order = l; | 
|  | while (order<count && !cmp(&layer, a+order)) { | 
|  | order++; | 
|  | } | 
|  | count = lookup.size(); | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | if (lookup.valueAt(i) >= order) { | 
|  | lookup.editValueAt(i)++; | 
|  | } | 
|  | } | 
|  | layers.insertAt(layer, order); | 
|  | lookup.add(layer, order); | 
|  | return order; | 
|  | } | 
|  |  | 
|  | ssize_t SurfaceFlinger::LayerVector::remove(LayerBase* layer) | 
|  | { | 
|  | const ssize_t keyIndex = lookup.indexOfKey(layer); | 
|  | if (keyIndex >= 0) { | 
|  | const size_t index = lookup.valueAt(keyIndex); | 
|  | LOG_ASSERT(layers[index]==layer, | 
|  | "LayerVector[%p]: layers[%u]=%p, layer=%p", | 
|  | this, int(index), layers[index], layer); | 
|  | layers.removeItemsAt(index); | 
|  | lookup.removeItemsAt(keyIndex); | 
|  | const size_t count = lookup.size(); | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | if (lookup.valueAt(i) >= size_t(index)) { | 
|  | lookup.editValueAt(i)--; | 
|  | } | 
|  | } | 
|  | return index; | 
|  | } | 
|  | return NAME_NOT_FOUND; | 
|  | } | 
|  |  | 
|  | ssize_t SurfaceFlinger::LayerVector::reorder( | 
|  | LayerBase* layer, | 
|  | Vector<LayerBase*>::compar_t cmp) | 
|  | { | 
|  | // XXX: it's a little lame. but oh well... | 
|  | ssize_t err = remove(layer); | 
|  | if (err >=0) | 
|  | err = add(layer, cmp); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  | #if 0 | 
|  | #pragma mark - | 
|  | #endif | 
|  |  | 
|  | SurfaceFlinger::SurfaceFlinger() | 
|  | :   BnSurfaceComposer(), Thread(false), | 
|  | mTransactionFlags(0), | 
|  | mTransactionCount(0), | 
|  | mBootTime(systemTime()), | 
|  | mLastScheduledBroadcast(NULL), | 
|  | mVisibleRegionsDirty(false), | 
|  | mDeferReleaseConsole(false), | 
|  | mFreezeDisplay(false), | 
|  | mFreezeCount(0), | 
|  | mFreezeDisplayTime(0), | 
|  | mDebugRegion(0), | 
|  | mDebugCpu(0), | 
|  | mDebugFps(0), | 
|  | mDebugBackground(0), | 
|  | mDebugNoBootAnimation(0), | 
|  | mSyncObject(), | 
|  | mDeplayedTransactionPending(0), | 
|  | mConsoleSignals(0), | 
|  | mSecureFrameBuffer(0) | 
|  | { | 
|  | init(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::init() | 
|  | { | 
|  | LOGI("SurfaceFlinger is starting"); | 
|  |  | 
|  | // debugging stuff... | 
|  | char value[PROPERTY_VALUE_MAX]; | 
|  | property_get("debug.sf.showupdates", value, "0"); | 
|  | mDebugRegion = atoi(value); | 
|  | property_get("debug.sf.showcpu", value, "0"); | 
|  | mDebugCpu = atoi(value); | 
|  | property_get("debug.sf.showbackground", value, "0"); | 
|  | mDebugBackground = atoi(value); | 
|  | property_get("debug.sf.showfps", value, "0"); | 
|  | mDebugFps = atoi(value); | 
|  | property_get("debug.sf.nobootanimation", value, "0"); | 
|  | mDebugNoBootAnimation = atoi(value); | 
|  |  | 
|  | LOGI_IF(mDebugRegion,           "showupdates enabled"); | 
|  | LOGI_IF(mDebugCpu,              "showcpu enabled"); | 
|  | LOGI_IF(mDebugBackground,       "showbackground enabled"); | 
|  | LOGI_IF(mDebugFps,              "showfps enabled"); | 
|  | LOGI_IF(mDebugNoBootAnimation,  "boot animation disabled"); | 
|  | } | 
|  |  | 
|  | SurfaceFlinger::~SurfaceFlinger() | 
|  | { | 
|  | glDeleteTextures(1, &mWormholeTexName); | 
|  | delete mOrientationAnimation; | 
|  | } | 
|  |  | 
|  | copybit_device_t* SurfaceFlinger::getBlitEngine() const | 
|  | { | 
|  | return graphicPlane(0).displayHardware().getBlitEngine(); | 
|  | } | 
|  |  | 
|  | overlay_control_device_t* SurfaceFlinger::getOverlayEngine() const | 
|  | { | 
|  | return graphicPlane(0).displayHardware().getOverlayEngine(); | 
|  | } | 
|  |  | 
|  | sp<IMemory> SurfaceFlinger::getCblk() const | 
|  | { | 
|  | return mServerCblkMemory; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::requestGPU(const sp<IGPUCallback>& callback, | 
|  | gpu_info_t* gpu) | 
|  | { | 
|  | IPCThreadState* ipc = IPCThreadState::self(); | 
|  | const int pid = ipc->getCallingPid(); | 
|  | status_t err = mGPU->request(pid, callback, gpu); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::revokeGPU() | 
|  | { | 
|  | return mGPU->friendlyRevoke(); | 
|  | } | 
|  |  | 
|  | sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection() | 
|  | { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | uint32_t token = mTokens.acquire(); | 
|  |  | 
|  | Client* client = new Client(token, this); | 
|  | if ((client == 0) || (client->ctrlblk == 0)) { | 
|  | mTokens.release(token); | 
|  | return 0; | 
|  | } | 
|  | status_t err = mClientsMap.add(token, client); | 
|  | if (err < 0) { | 
|  | delete client; | 
|  | mTokens.release(token); | 
|  | return 0; | 
|  | } | 
|  | sp<BClient> bclient = | 
|  | new BClient(this, token, client->controlBlockMemory()); | 
|  | return bclient; | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::destroyConnection(ClientID cid) | 
|  | { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | Client* const client = mClientsMap.valueFor(cid); | 
|  | if (client) { | 
|  | // free all the layers this client owns | 
|  | const Vector<LayerBaseClient*>& layers = client->getLayers(); | 
|  | const size_t count = layers.size(); | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | LayerBaseClient* const layer = layers[i]; | 
|  | removeLayer_l(layer); | 
|  | } | 
|  |  | 
|  | // the resources associated with this client will be freed | 
|  | // during the next transaction, after these surfaces have been | 
|  | // properly removed from the screen | 
|  |  | 
|  | // remove this client from our ClientID->Client mapping. | 
|  | mClientsMap.removeItem(cid); | 
|  |  | 
|  | // and add it to the list of disconnected clients | 
|  | mDisconnectedClients.add(client); | 
|  |  | 
|  | // request a transaction | 
|  | setTransactionFlags(eTransactionNeeded); | 
|  | } | 
|  | } | 
|  |  | 
|  | const GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) const | 
|  | { | 
|  | LOGE_IF(uint32_t(dpy) >= DISPLAY_COUNT, "Invalid DisplayID %d", dpy); | 
|  | const GraphicPlane& plane(mGraphicPlanes[dpy]); | 
|  | return plane; | 
|  | } | 
|  |  | 
|  | GraphicPlane& SurfaceFlinger::graphicPlane(int dpy) | 
|  | { | 
|  | return const_cast<GraphicPlane&>( | 
|  | const_cast<SurfaceFlinger const *>(this)->graphicPlane(dpy)); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::bootFinished() | 
|  | { | 
|  | const nsecs_t now = systemTime(); | 
|  | const nsecs_t duration = now - mBootTime; | 
|  | LOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) ); | 
|  | if (mBootAnimation != 0) { | 
|  | mBootAnimation->requestExit(); | 
|  | mBootAnimation.clear(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::onFirstRef() | 
|  | { | 
|  | run("SurfaceFlinger", PRIORITY_URGENT_DISPLAY); | 
|  |  | 
|  | // Wait for the main thread to be done with its initialization | 
|  | mReadyToRunBarrier.wait(); | 
|  | } | 
|  |  | 
|  |  | 
|  | static inline uint16_t pack565(int r, int g, int b) { | 
|  | return (r<<11)|(g<<5)|b; | 
|  | } | 
|  |  | 
|  | // this is defined in libGLES_CM.so | 
|  | extern ISurfaceComposer* GLES_localSurfaceManager; | 
|  |  | 
|  | status_t SurfaceFlinger::readyToRun() | 
|  | { | 
|  | LOGI(   "SurfaceFlinger's main thread ready to run. " | 
|  | "Initializing graphics H/W..."); | 
|  |  | 
|  | // create the shared control-block | 
|  | mServerHeap = new MemoryDealer(4096, MemoryDealer::READ_ONLY); | 
|  | LOGE_IF(mServerHeap==0, "can't create shared memory dealer"); | 
|  |  | 
|  | mServerCblkMemory = mServerHeap->allocate(4096); | 
|  | LOGE_IF(mServerCblkMemory==0, "can't create shared control block"); | 
|  |  | 
|  | mServerCblk = static_cast<surface_flinger_cblk_t *>(mServerCblkMemory->pointer()); | 
|  | LOGE_IF(mServerCblk==0, "can't get to shared control block's address"); | 
|  | new(mServerCblk) surface_flinger_cblk_t; | 
|  |  | 
|  | // get a reference to the GPU if we have one | 
|  | mGPU = GPUFactory::getGPU(); | 
|  |  | 
|  | // create the surface Heap manager, which manages the heaps | 
|  | // (be it in RAM or VRAM) where surfaces are allocated | 
|  | // We give 8 MB per client. | 
|  | mSurfaceHeapManager = new SurfaceHeapManager(this, 8 << 20); | 
|  |  | 
|  |  | 
|  | GLES_localSurfaceManager = static_cast<ISurfaceComposer*>(this); | 
|  |  | 
|  | // we only support one display currently | 
|  | int dpy = 0; | 
|  |  | 
|  | { | 
|  | // initialize the main display | 
|  | GraphicPlane& plane(graphicPlane(dpy)); | 
|  | DisplayHardware* const hw = new DisplayHardware(this, dpy); | 
|  | plane.setDisplayHardware(hw); | 
|  | } | 
|  |  | 
|  | // initialize primary screen | 
|  | // (other display should be initialized in the same manner, but | 
|  | // asynchronously, as they could come and go. None of this is supported | 
|  | // yet). | 
|  | const GraphicPlane& plane(graphicPlane(dpy)); | 
|  | const DisplayHardware& hw = plane.displayHardware(); | 
|  | const uint32_t w = hw.getWidth(); | 
|  | const uint32_t h = hw.getHeight(); | 
|  | const uint32_t f = hw.getFormat(); | 
|  | hw.makeCurrent(); | 
|  |  | 
|  | // initialize the shared control block | 
|  | mServerCblk->connected |= 1<<dpy; | 
|  | display_cblk_t* dcblk = mServerCblk->displays + dpy; | 
|  | memset(dcblk, 0, sizeof(display_cblk_t)); | 
|  | dcblk->w            = w; | 
|  | dcblk->h            = h; | 
|  | dcblk->format       = f; | 
|  | dcblk->orientation  = ISurfaceComposer::eOrientationDefault; | 
|  | dcblk->xdpi         = hw.getDpiX(); | 
|  | dcblk->ydpi         = hw.getDpiY(); | 
|  | dcblk->fps          = hw.getRefreshRate(); | 
|  | dcblk->density      = hw.getDensity(); | 
|  | asm volatile ("":::"memory"); | 
|  |  | 
|  | // Initialize OpenGL|ES | 
|  | glActiveTexture(GL_TEXTURE0); | 
|  | glBindTexture(GL_TEXTURE_2D, 0); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 
|  | glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | 
|  | glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | 
|  | glPixelStorei(GL_PACK_ALIGNMENT, 4); | 
|  | glEnableClientState(GL_VERTEX_ARRAY); | 
|  | glEnable(GL_SCISSOR_TEST); | 
|  | glShadeModel(GL_FLAT); | 
|  | glDisable(GL_DITHER); | 
|  | glDisable(GL_CULL_FACE); | 
|  |  | 
|  | const uint16_t g0 = pack565(0x0F,0x1F,0x0F); | 
|  | const uint16_t g1 = pack565(0x17,0x2f,0x17); | 
|  | const uint16_t textureData[4] = { g0, g1, g1, g0 }; | 
|  | glGenTextures(1, &mWormholeTexName); | 
|  | glBindTexture(GL_TEXTURE_2D, mWormholeTexName); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); | 
|  | glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); | 
|  | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2, 2, 0, | 
|  | GL_RGB, GL_UNSIGNED_SHORT_5_6_5, textureData); | 
|  |  | 
|  | glViewport(0, 0, w, h); | 
|  | glMatrixMode(GL_PROJECTION); | 
|  | glLoadIdentity(); | 
|  | glOrthof(0, w, h, 0, 0, 1); | 
|  |  | 
|  | LayerDim::initDimmer(this, w, h); | 
|  |  | 
|  | mReadyToRunBarrier.open(); | 
|  |  | 
|  | /* | 
|  | *  We're now ready to accept clients... | 
|  | */ | 
|  |  | 
|  | mOrientationAnimation = new OrientationAnimation(this); | 
|  |  | 
|  | // start CPU gauge display | 
|  | if (mDebugCpu) | 
|  | mCpuGauge = new CPUGauge(this, ms2ns(500)); | 
|  |  | 
|  | // the boot animation! | 
|  | if (mDebugNoBootAnimation == false) | 
|  | mBootAnimation = new BootAnimation(this); | 
|  |  | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | // ---------------------------------------------------------------------------- | 
|  | #if 0 | 
|  | #pragma mark - | 
|  | #pragma mark Events Handler | 
|  | #endif | 
|  |  | 
|  | void SurfaceFlinger::waitForEvent() | 
|  | { | 
|  | // wait for something to do | 
|  | if (UNLIKELY(isFrozen())) { | 
|  | // wait 5 seconds | 
|  | const nsecs_t freezeDisplayTimeout = ms2ns(5000); | 
|  | const nsecs_t now = systemTime(); | 
|  | if (mFreezeDisplayTime == 0) { | 
|  | mFreezeDisplayTime = now; | 
|  | } | 
|  | nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime); | 
|  | int err = (waitTime > 0) ? mSyncObject.wait(waitTime) : TIMED_OUT; | 
|  | if (err != NO_ERROR) { | 
|  | if (isFrozen()) { | 
|  | // we timed out and are still frozen | 
|  | LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d", | 
|  | mFreezeDisplay, mFreezeCount); | 
|  | mFreezeCount = 0; | 
|  | mFreezeDisplay = false; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | mFreezeDisplayTime = 0; | 
|  | mSyncObject.wait(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::signalEvent() { | 
|  | mSyncObject.open(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::signal() const { | 
|  | mSyncObject.open(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::signalDelayedEvent(nsecs_t delay) | 
|  | { | 
|  | if (android_atomic_or(1, &mDeplayedTransactionPending) == 0) { | 
|  | sp<DelayedTransaction> delayedEvent(new DelayedTransaction(this, delay)); | 
|  | delayedEvent->run("DelayedeEvent", PRIORITY_URGENT_DISPLAY); | 
|  | } | 
|  | } | 
|  |  | 
|  | // ---------------------------------------------------------------------------- | 
|  | #if 0 | 
|  | #pragma mark - | 
|  | #pragma mark Main loop | 
|  | #endif | 
|  |  | 
|  | bool SurfaceFlinger::threadLoop() | 
|  | { | 
|  | waitForEvent(); | 
|  |  | 
|  | // check for transactions | 
|  | if (UNLIKELY(mConsoleSignals)) { | 
|  | handleConsoleEvents(); | 
|  | } | 
|  |  | 
|  | if (LIKELY(mTransactionCount == 0)) { | 
|  | // if we're in a global transaction, don't do anything. | 
|  | const uint32_t mask = eTransactionNeeded | eTraversalNeeded; | 
|  | uint32_t transactionFlags = getTransactionFlags(mask); | 
|  | if (LIKELY(transactionFlags)) { | 
|  | handleTransaction(transactionFlags); | 
|  | } | 
|  | } | 
|  |  | 
|  | // post surfaces (if needed) | 
|  | handlePageFlip(); | 
|  |  | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  | if (LIKELY(hw.canDraw())) { | 
|  | // repaint the framebuffer (if needed) | 
|  | handleRepaint(); | 
|  |  | 
|  | // release the clients before we flip ('cause flip might block) | 
|  | unlockClients(); | 
|  | executeScheduledBroadcasts(); | 
|  |  | 
|  | // sample the cpu gauge | 
|  | if (UNLIKELY(mDebugCpu)) { | 
|  | handleDebugCpu(); | 
|  | } | 
|  |  | 
|  | postFramebuffer(); | 
|  | } else { | 
|  | // pretend we did the post | 
|  | unlockClients(); | 
|  | executeScheduledBroadcasts(); | 
|  | usleep(16667); // 60 fps period | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::postFramebuffer() | 
|  | { | 
|  | const bool skip = mOrientationAnimation->run(); | 
|  | if (UNLIKELY(skip)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!mInvalidRegion.isEmpty()) { | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  |  | 
|  | if (UNLIKELY(mDebugFps)) { | 
|  | debugShowFPS(); | 
|  | } | 
|  |  | 
|  | hw.flip(mInvalidRegion); | 
|  |  | 
|  | mInvalidRegion.clear(); | 
|  |  | 
|  | if (Layer::deletedTextures.size()) { | 
|  | glDeleteTextures( | 
|  | Layer::deletedTextures.size(), | 
|  | Layer::deletedTextures.array()); | 
|  | Layer::deletedTextures.clear(); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::handleConsoleEvents() | 
|  | { | 
|  | // something to do with the console | 
|  | const DisplayHardware& hw = graphicPlane(0).displayHardware(); | 
|  |  | 
|  | int what = android_atomic_and(0, &mConsoleSignals); | 
|  | if (what & eConsoleAcquired) { | 
|  | hw.acquireScreen(); | 
|  | } | 
|  |  | 
|  | if (mDeferReleaseConsole && hw.canDraw()) { | 
|  | // We got the release signal before the aquire signal | 
|  | mDeferReleaseConsole = false; | 
|  | revokeGPU(); | 
|  | hw.releaseScreen(); | 
|  | } | 
|  |  | 
|  | if (what & eConsoleReleased) { | 
|  | if (hw.canDraw()) { | 
|  | revokeGPU(); | 
|  | hw.releaseScreen(); | 
|  | } else { | 
|  | mDeferReleaseConsole = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | mDirtyRegion.set(hw.bounds()); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) | 
|  | { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  |  | 
|  | const LayerVector& currentLayers = mCurrentState.layersSortedByZ; | 
|  | const size_t count = currentLayers.size(); | 
|  |  | 
|  | /* | 
|  | * Traversal of the children | 
|  | * (perform the transaction for each of them if needed) | 
|  | */ | 
|  |  | 
|  | const bool layersNeedTransaction = transactionFlags & eTraversalNeeded; | 
|  | if (layersNeedTransaction) { | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | LayerBase* const layer = currentLayers[i]; | 
|  | uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded); | 
|  | if (!trFlags) continue; | 
|  |  | 
|  | const uint32_t flags = layer->doTransaction(0); | 
|  | if (flags & Layer::eVisibleRegion) | 
|  | mVisibleRegionsDirty = true; | 
|  |  | 
|  | if (flags & Layer::eRestartTransaction) { | 
|  | // restart the transaction, but back-off a little | 
|  | layer->setTransactionFlags(eTransactionNeeded); | 
|  | setTransactionFlags(eTraversalNeeded, ms2ns(8)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Perform our own transaction if needed | 
|  | */ | 
|  |  | 
|  | if (transactionFlags & eTransactionNeeded) { | 
|  | if (mCurrentState.orientation != mDrawingState.orientation) { | 
|  | // the orientation has changed, recompute all visible regions | 
|  | // and invalidate everything. | 
|  |  | 
|  | const int dpy = 0; | 
|  | const int orientation = mCurrentState.orientation; | 
|  | const uint32_t type = mCurrentState.orientationType; | 
|  | GraphicPlane& plane(graphicPlane(dpy)); | 
|  | plane.setOrientation(orientation); | 
|  |  | 
|  | // update the shared control block | 
|  | const DisplayHardware& hw(plane.displayHardware()); | 
|  | volatile display_cblk_t* dcblk = mServerCblk->displays + dpy; | 
|  | dcblk->orientation = orientation; | 
|  | if (orientation & eOrientationSwapMask) { | 
|  | // 90 or 270 degrees orientation | 
|  | dcblk->w = hw.getHeight(); | 
|  | dcblk->h = hw.getWidth(); | 
|  | } else { | 
|  | dcblk->w = hw.getWidth(); | 
|  | dcblk->h = hw.getHeight(); | 
|  | } | 
|  |  | 
|  | mVisibleRegionsDirty = true; | 
|  | mDirtyRegion.set(hw.bounds()); | 
|  | mFreezeDisplayTime = 0; | 
|  | mOrientationAnimation->onOrientationChanged(type); | 
|  | } | 
|  |  | 
|  | if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) { | 
|  | // freezing or unfreezing the display -> trigger animation if needed | 
|  | mFreezeDisplay = mCurrentState.freezeDisplay; | 
|  | } | 
|  |  | 
|  | // some layers might have been removed, so | 
|  | // we need to update the regions they're exposing. | 
|  | size_t c = mRemovedLayers.size(); | 
|  | if (c) { | 
|  | mVisibleRegionsDirty = true; | 
|  | } | 
|  |  | 
|  | const LayerVector& currentLayers = mCurrentState.layersSortedByZ; | 
|  | if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) { | 
|  | // layers have been added | 
|  | mVisibleRegionsDirty = true; | 
|  | } | 
|  |  | 
|  | // get rid of all resources we don't need anymore | 
|  | // (layers and clients) | 
|  | free_resources_l(); | 
|  | } | 
|  |  | 
|  | commitTransaction(); | 
|  | } | 
|  |  | 
|  | sp<FreezeLock> SurfaceFlinger::getFreezeLock() const | 
|  | { | 
|  | return new FreezeLock(const_cast<SurfaceFlinger *>(this)); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::computeVisibleRegions( | 
|  | LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion) | 
|  | { | 
|  | const GraphicPlane& plane(graphicPlane(0)); | 
|  | const Transform& planeTransform(plane.transform()); | 
|  |  | 
|  | Region aboveOpaqueLayers; | 
|  | Region aboveCoveredLayers; | 
|  | Region dirty; | 
|  |  | 
|  | bool secureFrameBuffer = false; | 
|  |  | 
|  | size_t i = currentLayers.size(); | 
|  | while (i--) { | 
|  | LayerBase* const layer = currentLayers[i]; | 
|  | layer->validateVisibility(planeTransform); | 
|  |  | 
|  | // start with the whole surface at its current location | 
|  | const Layer::State& s = layer->drawingState(); | 
|  | const Rect bounds(layer->visibleBounds()); | 
|  |  | 
|  | // handle hidden surfaces by setting the visible region to empty | 
|  | Region opaqueRegion; | 
|  | Region visibleRegion; | 
|  | Region coveredRegion; | 
|  | if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) { | 
|  | visibleRegion.clear(); | 
|  | } else { | 
|  | const bool translucent = layer->needsBlending(); | 
|  | visibleRegion.set(bounds); | 
|  | coveredRegion = visibleRegion; | 
|  |  | 
|  | // Remove the transparent area from the visible region | 
|  | if (translucent) { | 
|  | visibleRegion.subtractSelf(layer->transparentRegionScreen); | 
|  | } | 
|  |  | 
|  | // compute the opaque region | 
|  | if (s.alpha==255 && !translucent && layer->getOrientation()>=0) { | 
|  | // the opaque region is the visible region | 
|  | opaqueRegion = visibleRegion; | 
|  | } | 
|  | } | 
|  |  | 
|  | // subtract the opaque region covered by the layers above us | 
|  | visibleRegion.subtractSelf(aboveOpaqueLayers); | 
|  | coveredRegion.andSelf(aboveCoveredLayers); | 
|  |  | 
|  | // compute this layer's dirty region | 
|  | if (layer->contentDirty) { | 
|  | // we need to invalidate the whole region | 
|  | dirty = visibleRegion; | 
|  | // as well, as the old visible region | 
|  | dirty.orSelf(layer->visibleRegionScreen); | 
|  | layer->contentDirty = false; | 
|  | } else { | 
|  | // compute the exposed region | 
|  | // dirty = what's visible now - what's wasn't covered before | 
|  | //       = what's visible now & what's was covered before | 
|  | dirty = visibleRegion.intersect(layer->coveredRegionScreen); | 
|  | } | 
|  | dirty.subtractSelf(aboveOpaqueLayers); | 
|  |  | 
|  | // accumulate to the screen dirty region | 
|  | dirtyRegion.orSelf(dirty); | 
|  |  | 
|  | // updade aboveOpaqueLayers/aboveCoveredLayers for next (lower) layer | 
|  | aboveOpaqueLayers.orSelf(opaqueRegion); | 
|  | aboveCoveredLayers.orSelf(bounds); | 
|  |  | 
|  | // Store the visible region is screen space | 
|  | layer->setVisibleRegion(visibleRegion); | 
|  | layer->setCoveredRegion(coveredRegion); | 
|  |  | 
|  | // If a secure layer is partially visible, lockdown the screen! | 
|  | if (layer->isSecure() && !visibleRegion.isEmpty()) { | 
|  | secureFrameBuffer = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | mSecureFrameBuffer = secureFrameBuffer; | 
|  | opaqueRegion = aboveOpaqueLayers; | 
|  | } | 
|  |  | 
|  |  | 
|  | void SurfaceFlinger::commitTransaction() | 
|  | { | 
|  | mDrawingState = mCurrentState; | 
|  | mTransactionCV.signal(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::handlePageFlip() | 
|  | { | 
|  | bool visibleRegions = mVisibleRegionsDirty; | 
|  | LayerVector& currentLayers = const_cast<LayerVector&>(mDrawingState.layersSortedByZ); | 
|  | visibleRegions |= lockPageFlip(currentLayers); | 
|  |  | 
|  | const DisplayHardware& hw = graphicPlane(0).displayHardware(); | 
|  | const Region screenRegion(hw.bounds()); | 
|  | if (visibleRegions) { | 
|  | Region opaqueRegion; | 
|  | computeVisibleRegions(currentLayers, mDirtyRegion, opaqueRegion); | 
|  | mWormholeRegion = screenRegion.subtract(opaqueRegion); | 
|  | mVisibleRegionsDirty = false; | 
|  | } | 
|  |  | 
|  | unlockPageFlip(currentLayers); | 
|  | mDirtyRegion.andSelf(screenRegion); | 
|  | } | 
|  |  | 
|  | bool SurfaceFlinger::lockPageFlip(const LayerVector& currentLayers) | 
|  | { | 
|  | bool recomputeVisibleRegions = false; | 
|  | size_t count = currentLayers.size(); | 
|  | LayerBase* const* layers = currentLayers.array(); | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | LayerBase* const layer = layers[i]; | 
|  | layer->lockPageFlip(recomputeVisibleRegions); | 
|  | } | 
|  | return recomputeVisibleRegions; | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::unlockPageFlip(const LayerVector& currentLayers) | 
|  | { | 
|  | const GraphicPlane& plane(graphicPlane(0)); | 
|  | const Transform& planeTransform(plane.transform()); | 
|  | size_t count = currentLayers.size(); | 
|  | LayerBase* const* layers = currentLayers.array(); | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | LayerBase* const layer = layers[i]; | 
|  | layer->unlockPageFlip(planeTransform, mDirtyRegion); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::handleRepaint() | 
|  | { | 
|  | // set the frame buffer | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  | glMatrixMode(GL_MODELVIEW); | 
|  | glLoadIdentity(); | 
|  |  | 
|  | if (UNLIKELY(mDebugRegion)) { | 
|  | debugFlashRegions(); | 
|  | } | 
|  |  | 
|  | // compute the invalid region | 
|  | mInvalidRegion.orSelf(mDirtyRegion); | 
|  |  | 
|  | uint32_t flags = hw.getFlags(); | 
|  | if (flags & DisplayHardware::BUFFER_PRESERVED) { | 
|  | // here we assume DisplayHardware::flip()'s  implementation | 
|  | // performs the copy-back optimization. | 
|  | } else { | 
|  | if (flags & DisplayHardware::UPDATE_ON_DEMAND) { | 
|  | // we need to fully redraw the part that will be updated | 
|  | mDirtyRegion.set(mInvalidRegion.bounds()); | 
|  | } else { | 
|  | // we need to redraw everything | 
|  | mDirtyRegion.set(hw.bounds()); | 
|  | mInvalidRegion = mDirtyRegion; | 
|  | } | 
|  | } | 
|  |  | 
|  | // compose all surfaces | 
|  | composeSurfaces(mDirtyRegion); | 
|  |  | 
|  | // clear the dirty regions | 
|  | mDirtyRegion.clear(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::composeSurfaces(const Region& dirty) | 
|  | { | 
|  | if (UNLIKELY(!mWormholeRegion.isEmpty())) { | 
|  | // should never happen unless the window manager has a bug | 
|  | // draw something... | 
|  | drawWormhole(); | 
|  | } | 
|  | const SurfaceFlinger& flinger(*this); | 
|  | const LayerVector& drawingLayers(mDrawingState.layersSortedByZ); | 
|  | const size_t count = drawingLayers.size(); | 
|  | LayerBase const* const* const layers = drawingLayers.array(); | 
|  | for (size_t i=0 ; i<count ; ++i) { | 
|  | LayerBase const * const layer = layers[i]; | 
|  | const Region& visibleRegion(layer->visibleRegionScreen); | 
|  | if (!visibleRegion.isEmpty())  { | 
|  | const Region clip(dirty.intersect(visibleRegion)); | 
|  | if (!clip.isEmpty()) { | 
|  | layer->draw(clip); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::unlockClients() | 
|  | { | 
|  | const LayerVector& drawingLayers(mDrawingState.layersSortedByZ); | 
|  | const size_t count = drawingLayers.size(); | 
|  | LayerBase* const* const layers = drawingLayers.array(); | 
|  | for (size_t i=0 ; i<count ; ++i) { | 
|  | LayerBase* const layer = layers[i]; | 
|  | layer->finishPageFlip(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::scheduleBroadcast(Client* client) | 
|  | { | 
|  | if (mLastScheduledBroadcast != client) { | 
|  | mLastScheduledBroadcast = client; | 
|  | mScheduledBroadcasts.add(client); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::executeScheduledBroadcasts() | 
|  | { | 
|  | SortedVector<Client*>& list = mScheduledBroadcasts; | 
|  | size_t count = list.size(); | 
|  | while (count--) { | 
|  | per_client_cblk_t* const cblk = list[count]->ctrlblk; | 
|  | if (cblk->lock.tryLock() == NO_ERROR) { | 
|  | cblk->cv.broadcast(); | 
|  | list.removeAt(count); | 
|  | cblk->lock.unlock(); | 
|  | } else { | 
|  | // schedule another round | 
|  | LOGW("executeScheduledBroadcasts() skipped, " | 
|  | "contention on the client. We'll try again later..."); | 
|  | signalDelayedEvent(ms2ns(4)); | 
|  | } | 
|  | } | 
|  | mLastScheduledBroadcast = 0; | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::handleDebugCpu() | 
|  | { | 
|  | Mutex::Autolock _l(mDebugLock); | 
|  | if (mCpuGauge != 0) | 
|  | mCpuGauge->sample(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::debugFlashRegions() | 
|  | { | 
|  | if (UNLIKELY(!mDirtyRegion.isRect())) { | 
|  | // TODO: do this only if we don't have preserving | 
|  | // swapBuffer. If we don't have update-on-demand, | 
|  | // redraw everything. | 
|  | composeSurfaces(Region(mDirtyRegion.bounds())); | 
|  | } | 
|  |  | 
|  | glDisable(GL_TEXTURE_2D); | 
|  | glDisable(GL_BLEND); | 
|  | glDisable(GL_DITHER); | 
|  | glDisable(GL_SCISSOR_TEST); | 
|  |  | 
|  | glColor4x(0x10000, 0, 0x10000, 0x10000); | 
|  |  | 
|  | Rect r; | 
|  | Region::iterator iterator(mDirtyRegion); | 
|  | while (iterator.iterate(&r)) { | 
|  | GLfloat vertices[][2] = { | 
|  | { r.left,  r.top }, | 
|  | { r.left,  r.bottom }, | 
|  | { r.right, r.bottom }, | 
|  | { r.right, r.top } | 
|  | }; | 
|  | glVertexPointer(2, GL_FLOAT, 0, vertices); | 
|  | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | 
|  | } | 
|  |  | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  | hw.flip(mDirtyRegion.merge(mInvalidRegion)); | 
|  | mInvalidRegion.clear(); | 
|  |  | 
|  | if (mDebugRegion > 1) | 
|  | usleep(mDebugRegion * 1000); | 
|  |  | 
|  | glEnable(GL_SCISSOR_TEST); | 
|  | //mDirtyRegion.dump("mDirtyRegion"); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::drawWormhole() const | 
|  | { | 
|  | const Region region(mWormholeRegion.intersect(mDirtyRegion)); | 
|  | if (region.isEmpty()) | 
|  | return; | 
|  |  | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  | const int32_t width = hw.getWidth(); | 
|  | const int32_t height = hw.getHeight(); | 
|  |  | 
|  | glDisable(GL_BLEND); | 
|  | glDisable(GL_DITHER); | 
|  |  | 
|  | if (LIKELY(!mDebugBackground)) { | 
|  | glClearColorx(0,0,0,0); | 
|  | Rect r; | 
|  | Region::iterator iterator(region); | 
|  | while (iterator.iterate(&r)) { | 
|  | const GLint sy = height - (r.top + r.height()); | 
|  | glScissor(r.left, sy, r.width(), r.height()); | 
|  | glClear(GL_COLOR_BUFFER_BIT); | 
|  | } | 
|  | } else { | 
|  | const GLshort vertices[][2] = { { 0, 0 }, { width, 0 }, | 
|  | { width, height }, { 0, height }  }; | 
|  | const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 },  { 1, 1 }, { 0, 1 } }; | 
|  | glVertexPointer(2, GL_SHORT, 0, vertices); | 
|  | glTexCoordPointer(2, GL_SHORT, 0, tcoords); | 
|  | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | 
|  | glEnable(GL_TEXTURE_2D); | 
|  | glBindTexture(GL_TEXTURE_2D, mWormholeTexName); | 
|  | glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); | 
|  | glMatrixMode(GL_TEXTURE); | 
|  | glLoadIdentity(); | 
|  | glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1); | 
|  | Rect r; | 
|  | Region::iterator iterator(region); | 
|  | while (iterator.iterate(&r)) { | 
|  | const GLint sy = height - (r.top + r.height()); | 
|  | glScissor(r.left, sy, r.width(), r.height()); | 
|  | glDrawArrays(GL_TRIANGLE_FAN, 0, 4); | 
|  | } | 
|  | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | 
|  | } | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::debugShowFPS() const | 
|  | { | 
|  | static int mFrameCount; | 
|  | static int mLastFrameCount = 0; | 
|  | static nsecs_t mLastFpsTime = 0; | 
|  | static float mFps = 0; | 
|  | mFrameCount++; | 
|  | nsecs_t now = systemTime(); | 
|  | nsecs_t diff = now - mLastFpsTime; | 
|  | if (diff > ms2ns(250)) { | 
|  | mFps =  ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; | 
|  | mLastFpsTime = now; | 
|  | mLastFrameCount = mFrameCount; | 
|  | } | 
|  | // XXX: mFPS has the value we want | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::addLayer(LayerBase* layer) | 
|  | { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | addLayer_l(layer); | 
|  | setTransactionFlags(eTransactionNeeded|eTraversalNeeded); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::removeLayer(LayerBase* layer) | 
|  | { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | removeLayer_l(layer); | 
|  | setTransactionFlags(eTransactionNeeded); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::invalidateLayerVisibility(LayerBase* layer) | 
|  | { | 
|  | layer->forceVisibilityTransaction(); | 
|  | setTransactionFlags(eTraversalNeeded); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::addLayer_l(LayerBase* layer) | 
|  | { | 
|  | ssize_t i = mCurrentState.layersSortedByZ.add( | 
|  | layer, &LayerBase::compareCurrentStateZ); | 
|  | LayerBaseClient* lbc = LayerBase::dynamicCast<LayerBaseClient*>(layer); | 
|  | if (lbc) { | 
|  | mLayerMap.add(lbc->serverIndex(), lbc); | 
|  | } | 
|  | mRemovedLayers.remove(layer); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::removeLayer_l(LayerBase* layerBase) | 
|  | { | 
|  | ssize_t index = mCurrentState.layersSortedByZ.remove(layerBase); | 
|  | if (index >= 0) { | 
|  | mRemovedLayers.add(layerBase); | 
|  | LayerBaseClient* layer = LayerBase::dynamicCast<LayerBaseClient*>(layerBase); | 
|  | if (layer) { | 
|  | mLayerMap.removeItem(layer->serverIndex()); | 
|  | } | 
|  | return NO_ERROR; | 
|  | } | 
|  | // it's possible that we don't find a layer, because it might | 
|  | // have been destroyed already -- this is not technically an error | 
|  | // from the user because there is a race between destroySurface, | 
|  | // destroyclient and destroySurface-from-a-transaction. | 
|  | return (index == NAME_NOT_FOUND) ? status_t(NO_ERROR) : index; | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::free_resources_l() | 
|  | { | 
|  | // Destroy layers that were removed | 
|  | destroy_all_removed_layers_l(); | 
|  |  | 
|  | // free resources associated with disconnected clients | 
|  | SortedVector<Client*>& scheduledBroadcasts(mScheduledBroadcasts); | 
|  | Vector<Client*>& disconnectedClients(mDisconnectedClients); | 
|  | const size_t count = disconnectedClients.size(); | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | Client* client = disconnectedClients[i]; | 
|  | // if this client is the scheduled broadcast list, | 
|  | // remove it from there (and we don't need to signal it | 
|  | // since it is dead). | 
|  | int32_t index = scheduledBroadcasts.indexOf(client); | 
|  | if (index >= 0) { | 
|  | scheduledBroadcasts.removeItemsAt(index); | 
|  | } | 
|  | mTokens.release(client->cid); | 
|  | delete client; | 
|  | } | 
|  | disconnectedClients.clear(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::destroy_all_removed_layers_l() | 
|  | { | 
|  | size_t c = mRemovedLayers.size(); | 
|  | while (c--) { | 
|  | LayerBase* const removed_layer = mRemovedLayers[c]; | 
|  |  | 
|  | LOGE_IF(mCurrentState.layersSortedByZ.indexOf(removed_layer) >= 0, | 
|  | "layer %p removed but still in the current state list", | 
|  | removed_layer); | 
|  |  | 
|  | delete removed_layer; | 
|  | } | 
|  | mRemovedLayers.clear(); | 
|  | } | 
|  |  | 
|  |  | 
|  | uint32_t SurfaceFlinger::getTransactionFlags(uint32_t flags) | 
|  | { | 
|  | return android_atomic_and(~flags, &mTransactionFlags) & flags; | 
|  | } | 
|  |  | 
|  | uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, nsecs_t delay) | 
|  | { | 
|  | uint32_t old = android_atomic_or(flags, &mTransactionFlags); | 
|  | if ((old & flags)==0) { // wake the server up | 
|  | if (delay > 0) { | 
|  | signalDelayedEvent(delay); | 
|  | } else { | 
|  | signalEvent(); | 
|  | } | 
|  | } | 
|  | return old; | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::openGlobalTransaction() | 
|  | { | 
|  | android_atomic_inc(&mTransactionCount); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::closeGlobalTransaction() | 
|  | { | 
|  | if (android_atomic_dec(&mTransactionCount) == 1) { | 
|  | signalEvent(); | 
|  | } | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags) | 
|  | { | 
|  | if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) | 
|  | return BAD_VALUE; | 
|  |  | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | mCurrentState.freezeDisplay = 1; | 
|  | setTransactionFlags(eTransactionNeeded); | 
|  |  | 
|  | // flags is intended to communicate some sort of animation behavior | 
|  | // (for instance fadding) | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags) | 
|  | { | 
|  | if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) | 
|  | return BAD_VALUE; | 
|  |  | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | mCurrentState.freezeDisplay = 0; | 
|  | setTransactionFlags(eTransactionNeeded); | 
|  |  | 
|  | // flags is intended to communicate some sort of animation behavior | 
|  | // (for instance fadding) | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | int SurfaceFlinger::setOrientation(DisplayID dpy, | 
|  | int orientation, uint32_t flags) | 
|  | { | 
|  | if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT)) | 
|  | return BAD_VALUE; | 
|  |  | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | if (mCurrentState.orientation != orientation) { | 
|  | if (uint32_t(orientation)<=eOrientation270 || orientation==42) { | 
|  | mCurrentState.orientationType = flags; | 
|  | mCurrentState.orientation = orientation; | 
|  | setTransactionFlags(eTransactionNeeded); | 
|  | mTransactionCV.wait(mStateLock); | 
|  | } else { | 
|  | orientation = BAD_VALUE; | 
|  | } | 
|  | } | 
|  | return orientation; | 
|  | } | 
|  |  | 
|  | sp<ISurface> SurfaceFlinger::createSurface(ClientID clientId, int pid, | 
|  | ISurfaceFlingerClient::surface_data_t* params, | 
|  | DisplayID d, uint32_t w, uint32_t h, PixelFormat format, | 
|  | uint32_t flags) | 
|  | { | 
|  | LayerBaseClient* layer = 0; | 
|  | sp<LayerBaseClient::Surface> surfaceHandle; | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | Client* const c = mClientsMap.valueFor(clientId); | 
|  | if (UNLIKELY(!c)) { | 
|  | LOGE("createSurface() failed, client not found (id=%d)", clientId); | 
|  | return surfaceHandle; | 
|  | } | 
|  |  | 
|  | //LOGD("createSurface for pid %d (%d x %d)", pid, w, h); | 
|  | int32_t id = c->generateId(pid); | 
|  | if (uint32_t(id) >= NUM_LAYERS_MAX) { | 
|  | LOGE("createSurface() failed, generateId = %d", id); | 
|  | return surfaceHandle; | 
|  | } | 
|  |  | 
|  | switch (flags & eFXSurfaceMask) { | 
|  | case eFXSurfaceNormal: | 
|  | if (UNLIKELY(flags & ePushBuffers)) { | 
|  | layer = createPushBuffersSurfaceLocked(c, d, id, w, h, flags); | 
|  | } else { | 
|  | layer = createNormalSurfaceLocked(c, d, id, w, h, format, flags); | 
|  | } | 
|  | break; | 
|  | case eFXSurfaceBlur: | 
|  | layer = createBlurSurfaceLocked(c, d, id, w, h, flags); | 
|  | break; | 
|  | case eFXSurfaceDim: | 
|  | layer = createDimSurfaceLocked(c, d, id, w, h, flags); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (layer) { | 
|  | setTransactionFlags(eTransactionNeeded); | 
|  | surfaceHandle = layer->getSurface(); | 
|  | if (surfaceHandle != 0) | 
|  | surfaceHandle->getSurfaceData(params); | 
|  | } | 
|  |  | 
|  | return surfaceHandle; | 
|  | } | 
|  |  | 
|  | LayerBaseClient* SurfaceFlinger::createNormalSurfaceLocked( | 
|  | Client* client, DisplayID display, | 
|  | int32_t id, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) | 
|  | { | 
|  | // initialize the surfaces | 
|  | switch (format) { // TODO: take h/w into account | 
|  | case PIXEL_FORMAT_TRANSPARENT: | 
|  | case PIXEL_FORMAT_TRANSLUCENT: | 
|  | format = PIXEL_FORMAT_RGBA_8888; | 
|  | break; | 
|  | case PIXEL_FORMAT_OPAQUE: | 
|  | format = PIXEL_FORMAT_RGB_565; | 
|  | break; | 
|  | } | 
|  |  | 
|  | Layer* layer = new Layer(this, display, client, id); | 
|  | status_t err = layer->setBuffers(client, w, h, format, flags); | 
|  | if (LIKELY(err == NO_ERROR)) { | 
|  | layer->initStates(w, h, flags); | 
|  | addLayer_l(layer); | 
|  | } else { | 
|  | LOGE("createNormalSurfaceLocked() failed (%s)", strerror(-err)); | 
|  | delete layer; | 
|  | return 0; | 
|  | } | 
|  | return layer; | 
|  | } | 
|  |  | 
|  | LayerBaseClient* SurfaceFlinger::createBlurSurfaceLocked( | 
|  | Client* client, DisplayID display, | 
|  | int32_t id, uint32_t w, uint32_t h, uint32_t flags) | 
|  | { | 
|  | LayerBlur* layer = new LayerBlur(this, display, client, id); | 
|  | layer->initStates(w, h, flags); | 
|  | addLayer_l(layer); | 
|  | return layer; | 
|  | } | 
|  |  | 
|  | LayerBaseClient* SurfaceFlinger::createDimSurfaceLocked( | 
|  | Client* client, DisplayID display, | 
|  | int32_t id, uint32_t w, uint32_t h, uint32_t flags) | 
|  | { | 
|  | LayerDim* layer = new LayerDim(this, display, client, id); | 
|  | layer->initStates(w, h, flags); | 
|  | addLayer_l(layer); | 
|  | return layer; | 
|  | } | 
|  |  | 
|  | LayerBaseClient* SurfaceFlinger::createPushBuffersSurfaceLocked( | 
|  | Client* client, DisplayID display, | 
|  | int32_t id, uint32_t w, uint32_t h, uint32_t flags) | 
|  | { | 
|  | LayerBuffer* layer = new LayerBuffer(this, display, client, id); | 
|  | layer->initStates(w, h, flags); | 
|  | addLayer_l(layer); | 
|  | return layer; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::destroySurface(SurfaceID index) | 
|  | { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | LayerBaseClient* const layer = getLayerUser_l(index); | 
|  | status_t err = removeLayer_l(layer); | 
|  | if (err < 0) | 
|  | return err; | 
|  | setTransactionFlags(eTransactionNeeded); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::setClientState( | 
|  | ClientID cid, | 
|  | int32_t count, | 
|  | const layer_state_t* states) | 
|  | { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | uint32_t flags = 0; | 
|  | cid <<= 16; | 
|  | for (int i=0 ; i<count ; i++) { | 
|  | const layer_state_t& s = states[i]; | 
|  | LayerBaseClient* layer = getLayerUser_l(s.surface | cid); | 
|  | if (layer) { | 
|  | const uint32_t what = s.what; | 
|  | // check if it has been destroyed first | 
|  | if (what & eDestroyed) { | 
|  | if (removeLayer_l(layer) == NO_ERROR) { | 
|  | flags |= eTransactionNeeded; | 
|  | // we skip everything else... well, no, not really | 
|  | // we skip ONLY that transaction. | 
|  | continue; | 
|  | } | 
|  | } | 
|  | if (what & ePositionChanged) { | 
|  | if (layer->setPosition(s.x, s.y)) | 
|  | flags |= eTraversalNeeded; | 
|  | } | 
|  | if (what & eLayerChanged) { | 
|  | if (layer->setLayer(s.z)) { | 
|  | mCurrentState.layersSortedByZ.reorder( | 
|  | layer, &Layer::compareCurrentStateZ); | 
|  | // we need traversal (state changed) | 
|  | // AND transaction (list changed) | 
|  | flags |= eTransactionNeeded|eTraversalNeeded; | 
|  | } | 
|  | } | 
|  | if (what & eSizeChanged) { | 
|  | if (layer->setSize(s.w, s.h)) | 
|  | flags |= eTraversalNeeded; | 
|  | } | 
|  | if (what & eAlphaChanged) { | 
|  | if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f))) | 
|  | flags |= eTraversalNeeded; | 
|  | } | 
|  | if (what & eMatrixChanged) { | 
|  | if (layer->setMatrix(s.matrix)) | 
|  | flags |= eTraversalNeeded; | 
|  | } | 
|  | if (what & eTransparentRegionChanged) { | 
|  | if (layer->setTransparentRegionHint(s.transparentRegion)) | 
|  | flags |= eTraversalNeeded; | 
|  | } | 
|  | if (what & eVisibilityChanged) { | 
|  | if (layer->setFlags(s.flags, s.mask)) | 
|  | flags |= eTraversalNeeded; | 
|  | } | 
|  | } | 
|  | } | 
|  | if (flags) { | 
|  | setTransactionFlags(flags); | 
|  | } | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | LayerBaseClient* SurfaceFlinger::getLayerUser_l(SurfaceID s) const | 
|  | { | 
|  | return mLayerMap.valueFor(s); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::screenReleased(int dpy) | 
|  | { | 
|  | // this may be called by a signal handler, we can't do too much in here | 
|  | android_atomic_or(eConsoleReleased, &mConsoleSignals); | 
|  | signalEvent(); | 
|  | } | 
|  |  | 
|  | void SurfaceFlinger::screenAcquired(int dpy) | 
|  | { | 
|  | // this may be called by a signal handler, we can't do too much in here | 
|  | android_atomic_or(eConsoleAcquired, &mConsoleSignals); | 
|  | signalEvent(); | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) | 
|  | { | 
|  | const size_t SIZE = 1024; | 
|  | char buffer[SIZE]; | 
|  | String8 result; | 
|  | if (checkCallingPermission( | 
|  | String16("android.permission.DUMP")) == false) | 
|  | { // not allowed | 
|  | snprintf(buffer, SIZE, "Permission Denial: " | 
|  | "can't dump SurfaceFlinger from pid=%d, uid=%d\n", | 
|  | IPCThreadState::self()->getCallingPid(), | 
|  | IPCThreadState::self()->getCallingUid()); | 
|  | result.append(buffer); | 
|  | } else { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | size_t s = mClientsMap.size(); | 
|  | char name[64]; | 
|  | for (size_t i=0 ; i<s ; i++) { | 
|  | Client* client = mClientsMap.valueAt(i); | 
|  | sprintf(name, "  Client (id=0x%08x)", client->cid); | 
|  | client->dump(name); | 
|  | } | 
|  | const LayerVector& currentLayers = mCurrentState.layersSortedByZ; | 
|  | const size_t count = currentLayers.size(); | 
|  | for (size_t i=0 ; i<count ; i++) { | 
|  | /*** LayerBase ***/ | 
|  | LayerBase const * const layer = currentLayers[i]; | 
|  | const Layer::State& s = layer->drawingState(); | 
|  | snprintf(buffer, SIZE, | 
|  | "+ %s %p\n" | 
|  | "      " | 
|  | "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), " | 
|  | "needsBlending=%1d, invalidate=%1d, " | 
|  | "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", | 
|  | layer->getTypeID(), layer, | 
|  | s.z, layer->tx(), layer->ty(), s.w, s.h, | 
|  | layer->needsBlending(), layer->contentDirty, | 
|  | s.alpha, s.flags, | 
|  | s.transform[0], s.transform[1], | 
|  | s.transform[2], s.transform[3]); | 
|  | result.append(buffer); | 
|  | buffer[0] = 0; | 
|  | /*** LayerBaseClient ***/ | 
|  | LayerBaseClient* const lbc = | 
|  | LayerBase::dynamicCast<LayerBaseClient*>((LayerBase*)layer); | 
|  | if (lbc) { | 
|  | snprintf(buffer, SIZE, | 
|  | "      " | 
|  | "id=0x%08x, client=0x%08x, identity=%u\n", | 
|  | lbc->clientIndex(), lbc->client ? lbc->client->cid : 0, | 
|  | lbc->getIdentity()); | 
|  | } | 
|  | result.append(buffer); | 
|  | buffer[0] = 0; | 
|  | /*** Layer ***/ | 
|  | Layer* const l = LayerBase::dynamicCast<Layer*>((LayerBase*)layer); | 
|  | if (l) { | 
|  | const LayerBitmap& buf0(l->getBuffer(0)); | 
|  | const LayerBitmap& buf1(l->getBuffer(1)); | 
|  | snprintf(buffer, SIZE, | 
|  | "      " | 
|  | "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u], mTextureName=%d," | 
|  | " freezeLock=%p, swapState=0x%08x\n", | 
|  | l->pixelFormat(), | 
|  | buf0.width(), buf0.height(), buf0.stride(), | 
|  | buf1.width(), buf1.height(), buf1.stride(), | 
|  | l->getTextureName(), l->getFreezeLock().get(), | 
|  | l->lcblk->swapState); | 
|  | } | 
|  | result.append(buffer); | 
|  | buffer[0] = 0; | 
|  | s.transparentRegion.dump(result, "transparentRegion"); | 
|  | layer->transparentRegionScreen.dump(result, "transparentRegionScreen"); | 
|  | layer->visibleRegionScreen.dump(result, "visibleRegionScreen"); | 
|  | } | 
|  | mWormholeRegion.dump(result, "WormholeRegion"); | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  | snprintf(buffer, SIZE, | 
|  | "  display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n", | 
|  | mFreezeDisplay?"yes":"no", mFreezeCount, | 
|  | mCurrentState.orientation, hw.canDraw()); | 
|  | result.append(buffer); | 
|  |  | 
|  | sp<AllocatorInterface> allocator; | 
|  | if (mGPU != 0) { | 
|  | snprintf(buffer, SIZE, "  GPU owner: %d\n", mGPU->getOwner()); | 
|  | result.append(buffer); | 
|  | allocator = mGPU->getAllocator(); | 
|  | if (allocator != 0) { | 
|  | allocator->dump(result, "GPU Allocator"); | 
|  | } | 
|  | } | 
|  | allocator = mSurfaceHeapManager->getAllocator(NATIVE_MEMORY_TYPE_PMEM); | 
|  | if (allocator != 0) { | 
|  | allocator->dump(result, "PMEM Allocator"); | 
|  | } | 
|  | } | 
|  | write(fd, result.string(), result.size()); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t SurfaceFlinger::onTransact( | 
|  | uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) | 
|  | { | 
|  | switch (code) { | 
|  | case CREATE_CONNECTION: | 
|  | case OPEN_GLOBAL_TRANSACTION: | 
|  | case CLOSE_GLOBAL_TRANSACTION: | 
|  | case SET_ORIENTATION: | 
|  | case FREEZE_DISPLAY: | 
|  | case UNFREEZE_DISPLAY: | 
|  | case BOOT_FINISHED: | 
|  | case REVOKE_GPU: | 
|  | { | 
|  | // codes that require permission check | 
|  | IPCThreadState* ipc = IPCThreadState::self(); | 
|  | const int pid = ipc->getCallingPid(); | 
|  | const int self_pid = getpid(); | 
|  | if (UNLIKELY(pid != self_pid)) { | 
|  | // we're called from a different process, do the real check | 
|  | if (!checkCallingPermission( | 
|  | String16("android.permission.ACCESS_SURFACE_FLINGER"))) | 
|  | { | 
|  | const int uid = ipc->getCallingUid(); | 
|  | LOGE("Permission Denial: " | 
|  | "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); | 
|  | return PERMISSION_DENIED; | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags); | 
|  | if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) { | 
|  | // HARDWARE_TEST stuff... | 
|  | if (UNLIKELY(checkCallingPermission( | 
|  | String16("android.permission.HARDWARE_TEST")) == false)) | 
|  | { // not allowed | 
|  | LOGE("Permission Denial: pid=%d, uid=%d\n", | 
|  | IPCThreadState::self()->getCallingPid(), | 
|  | IPCThreadState::self()->getCallingUid()); | 
|  | return PERMISSION_DENIED; | 
|  | } | 
|  | int n; | 
|  | switch (code) { | 
|  | case 1000: // SHOW_CPU | 
|  | n = data.readInt32(); | 
|  | mDebugCpu = n ? 1 : 0; | 
|  | if (mDebugCpu) { | 
|  | if (mCpuGauge == 0) { | 
|  | mCpuGauge = new CPUGauge(this, ms2ns(500)); | 
|  | } | 
|  | } else { | 
|  | if (mCpuGauge != 0) { | 
|  | mCpuGauge->requestExitAndWait(); | 
|  | Mutex::Autolock _l(mDebugLock); | 
|  | mCpuGauge.clear(); | 
|  | } | 
|  | } | 
|  | return NO_ERROR; | 
|  | case 1001:  // SHOW_FPS | 
|  | n = data.readInt32(); | 
|  | mDebugFps = n ? 1 : 0; | 
|  | return NO_ERROR; | 
|  | case 1002:  // SHOW_UPDATES | 
|  | n = data.readInt32(); | 
|  | mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); | 
|  | return NO_ERROR; | 
|  | case 1003:  // SHOW_BACKGROUND | 
|  | n = data.readInt32(); | 
|  | mDebugBackground = n ? 1 : 0; | 
|  | return NO_ERROR; | 
|  | case 1004:{ // repaint everything | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  | mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe | 
|  | signalEvent(); | 
|  | } | 
|  | return NO_ERROR; | 
|  | case 1005: // ask GPU revoke | 
|  | mGPU->friendlyRevoke(); | 
|  | return NO_ERROR; | 
|  | case 1006: // revoke GPU | 
|  | mGPU->unconditionalRevoke(); | 
|  | return NO_ERROR; | 
|  | case 1007: // set mFreezeCount | 
|  | mFreezeCount = data.readInt32(); | 
|  | return NO_ERROR; | 
|  | case 1010:  // interrogate. | 
|  | reply->writeInt32(mDebugCpu); | 
|  | reply->writeInt32(0); | 
|  | reply->writeInt32(mDebugRegion); | 
|  | reply->writeInt32(mDebugBackground); | 
|  | return NO_ERROR; | 
|  | case 1013: { | 
|  | Mutex::Autolock _l(mStateLock); | 
|  | const DisplayHardware& hw(graphicPlane(0).displayHardware()); | 
|  | reply->writeInt32(hw.getPageFlipCount()); | 
|  | } | 
|  | return NO_ERROR; | 
|  | } | 
|  | } | 
|  | return err; | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  | #if 0 | 
|  | #pragma mark - | 
|  | #endif | 
|  |  | 
|  | Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger) | 
|  | : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger) | 
|  | { | 
|  | mSharedHeapAllocator = getSurfaceHeapManager()->createHeap(); | 
|  | const int pgsize = getpagesize(); | 
|  | const int cblksize=((sizeof(per_client_cblk_t)+(pgsize-1))&~(pgsize-1)); | 
|  | mCblkHeap = new MemoryDealer(cblksize); | 
|  | mCblkMemory = mCblkHeap->allocate(cblksize); | 
|  | if (mCblkMemory != 0) { | 
|  | ctrlblk = static_cast<per_client_cblk_t *>(mCblkMemory->pointer()); | 
|  | if (ctrlblk) { // construct the shared structure in-place. | 
|  | new(ctrlblk) per_client_cblk_t; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | Client::~Client() { | 
|  | if (ctrlblk) { | 
|  | const int pgsize = getpagesize(); | 
|  | ctrlblk->~per_client_cblk_t();  // destroy our shared-structure. | 
|  | } | 
|  | } | 
|  |  | 
|  | const sp<SurfaceHeapManager>& Client::getSurfaceHeapManager() const { | 
|  | return mFlinger->getSurfaceHeapManager(); | 
|  | } | 
|  |  | 
|  | int32_t Client::generateId(int pid) | 
|  | { | 
|  | const uint32_t i = clz( ~mBitmap ); | 
|  | if (i >= NUM_LAYERS_MAX) { | 
|  | return NO_MEMORY; | 
|  | } | 
|  | mPid = pid; | 
|  | mInUse.add(uint8_t(i)); | 
|  | mBitmap |= 1<<(31-i); | 
|  | return i; | 
|  | } | 
|  | status_t Client::bindLayer(LayerBaseClient* layer, int32_t id) | 
|  | { | 
|  | ssize_t idx = mInUse.indexOf(id); | 
|  | if (idx < 0) | 
|  | return NAME_NOT_FOUND; | 
|  | return mLayers.insertAt(layer, idx); | 
|  | } | 
|  | void Client::free(int32_t id) | 
|  | { | 
|  | ssize_t idx = mInUse.remove(uint8_t(id)); | 
|  | if (idx >= 0) { | 
|  | mBitmap &= ~(1<<(31-id)); | 
|  | mLayers.removeItemsAt(idx); | 
|  | } | 
|  | } | 
|  |  | 
|  | sp<MemoryDealer> Client::createAllocator(uint32_t flags) | 
|  | { | 
|  | sp<MemoryDealer> allocator; | 
|  | allocator = getSurfaceHeapManager()->createHeap( | 
|  | flags, getClientPid(), mSharedHeapAllocator); | 
|  | return allocator; | 
|  | } | 
|  |  | 
|  | bool Client::isValid(int32_t i) const { | 
|  | return (uint32_t(i)<NUM_LAYERS_MAX) && (mBitmap & (1<<(31-i))); | 
|  | } | 
|  | const uint8_t* Client::inUseArray() const { | 
|  | return mInUse.array(); | 
|  | } | 
|  | size_t Client::numActiveLayers() const { | 
|  | return mInUse.size(); | 
|  | } | 
|  | LayerBaseClient* Client::getLayerUser(int32_t i) const { | 
|  | ssize_t idx = mInUse.indexOf(uint8_t(i)); | 
|  | if (idx<0) return 0; | 
|  | return mLayers[idx]; | 
|  | } | 
|  |  | 
|  | void Client::dump(const char* what) | 
|  | { | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  | #if 0 | 
|  | #pragma mark - | 
|  | #endif | 
|  |  | 
|  | BClient::BClient(SurfaceFlinger *flinger, ClientID cid, const sp<IMemory>& cblk) | 
|  | : mId(cid), mFlinger(flinger), mCblk(cblk) | 
|  | { | 
|  | } | 
|  |  | 
|  | BClient::~BClient() { | 
|  | // destroy all resources attached to this client | 
|  | mFlinger->destroyConnection(mId); | 
|  | } | 
|  |  | 
|  | void BClient::getControlBlocks(sp<IMemory>* ctrl) const { | 
|  | *ctrl = mCblk; | 
|  | } | 
|  |  | 
|  | sp<ISurface> BClient::createSurface( | 
|  | ISurfaceFlingerClient::surface_data_t* params, int pid, | 
|  | DisplayID display, uint32_t w, uint32_t h, PixelFormat format, | 
|  | uint32_t flags) | 
|  | { | 
|  | return mFlinger->createSurface(mId, pid, params, display, w, h, format, flags); | 
|  | } | 
|  |  | 
|  | status_t BClient::destroySurface(SurfaceID sid) | 
|  | { | 
|  | sid |= (mId << 16); // add the client-part to id | 
|  | return mFlinger->destroySurface(sid); | 
|  | } | 
|  |  | 
|  | status_t BClient::setState(int32_t count, const layer_state_t* states) | 
|  | { | 
|  | return mFlinger->setClientState(mId, count, states); | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | GraphicPlane::GraphicPlane() | 
|  | : mHw(0) | 
|  | { | 
|  | } | 
|  |  | 
|  | GraphicPlane::~GraphicPlane() { | 
|  | delete mHw; | 
|  | } | 
|  |  | 
|  | bool GraphicPlane::initialized() const { | 
|  | return mHw ? true : false; | 
|  | } | 
|  |  | 
|  | void GraphicPlane::setDisplayHardware(DisplayHardware *hw) { | 
|  | mHw = hw; | 
|  | } | 
|  |  | 
|  | void GraphicPlane::setTransform(const Transform& tr) { | 
|  | mTransform = tr; | 
|  | mGlobalTransform = mOrientationTransform * mTransform; | 
|  | } | 
|  |  | 
|  | status_t GraphicPlane::orientationToTransfrom( | 
|  | int orientation, int w, int h, Transform* tr) | 
|  | { | 
|  | float a, b, c, d, x, y; | 
|  | switch (orientation) { | 
|  | case ISurfaceComposer::eOrientationDefault: | 
|  | a=1; b=0; c=0; d=1; x=0; y=0; | 
|  | break; | 
|  | case ISurfaceComposer::eOrientation90: | 
|  | a=0; b=-1; c=1; d=0; x=w; y=0; | 
|  | break; | 
|  | case ISurfaceComposer::eOrientation180: | 
|  | a=-1; b=0; c=0; d=-1; x=w; y=h; | 
|  | break; | 
|  | case ISurfaceComposer::eOrientation270: | 
|  | a=0; b=1; c=-1; d=0; x=0; y=h; | 
|  | break; | 
|  | default: | 
|  | return BAD_VALUE; | 
|  | } | 
|  | tr->set(a, b, c, d); | 
|  | tr->set(x, y); | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | status_t GraphicPlane::setOrientation(int orientation) | 
|  | { | 
|  | const DisplayHardware& hw(displayHardware()); | 
|  | const float w = hw.getWidth(); | 
|  | const float h = hw.getHeight(); | 
|  |  | 
|  | if (orientation == ISurfaceComposer::eOrientationDefault) { | 
|  | // make sure the default orientation is optimal | 
|  | mOrientationTransform.reset(); | 
|  | mOrientation = orientation; | 
|  | mGlobalTransform = mTransform; | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | // If the rotation can be handled in hardware, this is where | 
|  | // the magic should happen. | 
|  | if (UNLIKELY(orientation == 42)) { | 
|  | float a, b, c, d, x, y; | 
|  | const float r = (3.14159265f / 180.0f) * 42.0f; | 
|  | const float si = sinf(r); | 
|  | const float co = cosf(r); | 
|  | a=co; b=-si; c=si; d=co; | 
|  | x = si*(h*0.5f) + (1-co)*(w*0.5f); | 
|  | y =-si*(w*0.5f) + (1-co)*(h*0.5f); | 
|  | mOrientationTransform.set(a, b, c, d); | 
|  | mOrientationTransform.set(x, y); | 
|  | } else { | 
|  | GraphicPlane::orientationToTransfrom(orientation, w, h, | 
|  | &mOrientationTransform); | 
|  | } | 
|  | mOrientation = orientation; | 
|  | mGlobalTransform = mOrientationTransform * mTransform; | 
|  | return NO_ERROR; | 
|  | } | 
|  |  | 
|  | const DisplayHardware& GraphicPlane::displayHardware() const { | 
|  | return *mHw; | 
|  | } | 
|  |  | 
|  | const Transform& GraphicPlane::transform() const { | 
|  | return mGlobalTransform; | 
|  | } | 
|  |  | 
|  | // --------------------------------------------------------------------------- | 
|  |  | 
|  | }; // namespace android |