Merge "Release virtual display buffer immediately after HWC set" into jb-mr2-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 29838e4..d85a1d7 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -176,13 +176,18 @@
// Truncate a file.
static bool truncateFile(const char* path)
{
- int err = truncate(path, 0);
- if (err != 0) {
+ // This uses creat rather than truncate because some of the debug kernel
+ // device nodes (e.g. k_ftraceFilterPath) currently aren't changed by
+ // calls to truncate, but they are cleared by calls to creat.
+ int traceFD = creat(path, 0);
+ if (traceFD == -1) {
fprintf(stderr, "error truncating %s: %s (%d)\n", path,
- strerror(errno), errno);
+ strerror(errno), errno);
return false;
}
+ close(traceFD);
+
return true;
}
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index b3a4cc6..a18c00d 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -101,6 +101,12 @@
run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
+ if (screenshot_path[0]) {
+ ALOGI("taking screenshot\n");
+ run_command(NULL, 10, "/system/bin/screencap", "-p", screenshot_path, NULL);
+ ALOGI("wrote screenshot: %s\n", screenshot_path);
+ }
+
for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
@@ -159,12 +165,6 @@
dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console");
dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads");
- if (screenshot_path[0]) {
- ALOGI("taking screenshot\n");
- run_command(NULL, 10, "/system/bin/screencap", "-p", screenshot_path, NULL);
- ALOGI("wrote screenshot: %s\n", screenshot_path);
- }
-
run_command("SYSTEM SETTINGS", 20, SU_PATH, "root", "sqlite3",
"/data/data/com.android.providers.settings/databases/settings.db",
"pragma user_version; select * from system; select * from secure; select * from global;", NULL);
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 93dff32..4b956c7 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -37,7 +37,7 @@
* This queue is synchronous by default.
*/
-class CpuConsumer: public ConsumerBase
+class CpuConsumer : public ConsumerBase
{
public:
typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
@@ -88,14 +88,25 @@
// Maximum number of buffers that can be locked at a time
uint32_t mMaxLockedBuffers;
+ status_t releaseAcquiredBufferLocked(int lockedIdx);
+
virtual void freeBufferLocked(int slotIndex);
- // Array for tracking pointers passed to the consumer, matching the
- // mSlots indexing
- struct LockedSlot {
+ // Tracking for buffers acquired by the user
+ struct AcquiredBuffer {
+ // Need to track the original mSlot index and the buffer itself because
+ // the mSlot entry may be freed/reused before the acquired buffer is
+ // released.
+ int mSlot;
sp<GraphicBuffer> mGraphicBuffer;
void *mBufferPointer;
- } mLockedSlots[BufferQueue::NUM_BUFFER_SLOTS];
+
+ AcquiredBuffer() :
+ mSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mBufferPointer(NULL) {
+ }
+ };
+ Vector<AcquiredBuffer> mAcquiredBuffers;
// Count of currently locked buffers
uint32_t mCurrentLockedBuffers;
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 47f9552..9018b87 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -95,14 +95,6 @@
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& surface) const = 0;
- /* Capture the specified screen. requires READ_FRAME_BUFFER permission
- * This function will fail if there is a secure window on screen.
- */
- virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
-
/* triggers screen off and waits for it to complete
* requires ACCESS_SURFACE_FLINGER permission.
*/
@@ -123,7 +115,8 @@
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer) = 0;
};
// ----------------------------------------------------------------------------
@@ -141,7 +134,6 @@
GET_BUILT_IN_DISPLAY,
SET_TRANSACTION_STATE,
AUTHENTICATE_SURFACE,
- CAPTURE_SCREEN_DEPRECATED,
BLANK,
UNBLANK,
GET_DISPLAY_INFO,
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 38c931d..23655c7 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -30,6 +30,7 @@
#include <ui/PixelFormat.h>
+#include <gui/CpuConsumer.h>
#include <gui/SurfaceControl.h>
namespace android {
@@ -38,7 +39,6 @@
class DisplayInfo;
class Composer;
-class IMemoryHeap;
class ISurfaceComposerClient;
class IGraphicBufferProducer;
class Region;
@@ -164,10 +164,9 @@
uint32_t minLayerZ, uint32_t maxLayerZ);
private:
- sp<IMemoryHeap> mHeap;
- uint32_t mWidth;
- uint32_t mHeight;
- PixelFormat mFormat;
+ mutable sp<CpuConsumer> mCpuConsumer;
+ CpuConsumer::LockedBuffer mBuffer;
+ bool mHaveBuffer;
public:
ScreenshotClient();
@@ -180,6 +179,8 @@
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ);
+ sp<CpuConsumer> getCpuConsumer() const;
+
// release memory occupied by the screenshot
void release();
diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h
index fe8eb6f..f27754c 100644
--- a/include/gui/SurfaceControl.h
+++ b/include/gui/SurfaceControl.h
@@ -58,7 +58,7 @@
status_t setLayerStack(int32_t layerStack);
status_t setLayer(int32_t layer);
- status_t setPosition(int32_t x, int32_t y);
+ status_t setPosition(float x, float y);
status_t setSize(uint32_t w, uint32_t h);
status_t hide();
status_t show();
diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h
new file mode 100644
index 0000000..77da0bf
--- /dev/null
+++ b/include/media/drm/DrmAPI.h
@@ -0,0 +1,205 @@
+ /*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef DRM_API_H_
+#define DRM_API_H_
+
+#include <utils/List.h>
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+#include <media/stagefright/foundation/ABase.h>
+
+// Loadable DrmEngine shared libraries should define the entry points
+// createDrmFactory and createCryptoFactory as shown below:
+//
+// extern "C" {
+// extern android::DrmFactory *createDrmFactory();
+// extern android::CryptoFactory *createCryptoFactory();
+// }
+
+namespace android {
+
+ struct DrmPlugin;
+
+ // DRMs are implemented in DrmEngine plugins, which are dynamically
+ // loadable shared libraries that implement the entry points
+ // createDrmFactory and createCryptoFactory. createDrmFactory
+ // constructs and returns an instance of a DrmFactory object. Similarly,
+ // createCryptoFactory creates an instance of a CryptoFactory object.
+ // When a MediaCrypto or MediaDrm object needs to be constructed, all
+ // available DrmEngines present in the plugins directory on the device
+ // are scanned for a matching DrmEngine that can support the crypto
+ // scheme. When a match is found, the DrmEngine's createCryptoPlugin and
+ // createDrmPlugin methods are used to create CryptoPlugin or
+ // DrmPlugin instances to support that DRM scheme.
+
+ class DrmFactory {
+ public:
+ DrmFactory() {}
+ virtual ~DrmFactory() {}
+
+ // DrmFactory::isCryptoSchemeSupported can be called to determine
+ // if the plugin factory is able to construct plugins that support a
+ // given crypto scheme, which is specified by a UUID.
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
+
+ // Construct a DrmPlugin for the crypto scheme specified by UUID.
+ virtual status_t createDrmPlugin(
+ const uint8_t uuid[16], DrmPlugin **plugin) = 0;
+
+ private:
+ DrmFactory(const DrmFactory &);
+ DrmFactory &operator=(const DrmFactory &);
+ };
+
+ class DrmPlugin {
+ public:
+ enum EventType {
+ kDrmPluginEventProvisionRequired,
+ kDrmPluginEventLicenseNeeded,
+ kDrmPluginEventLicenseExpired,
+ kDrmPluginEventVendorDefined
+ };
+
+ // A license can be for offline content or for online streaming.
+ // Offline licenses are persisted on the device and may be used when the device
+ // is disconnected from the network.
+ enum LicenseType {
+ kLicenseType_Offline,
+ kLicenseType_Streaming
+ };
+
+ DrmPlugin() {}
+ virtual ~DrmPlugin() {}
+
+ // Open a new session with the DrmPlugin object. A session ID is returned
+ // in the sessionId parameter.
+ virtual status_t openSession(Vector<uint8_t> &sessionId) = 0;
+
+ // Close a session on the DrmPlugin object.
+ virtual status_t closeSession(Vector<uint8_t> const &sessionId) = 0;
+
+ // A license request/response exchange occurs between the app and a License
+ // Server to obtain the keys required to decrypt the content. getLicenseRequest()
+ // is used to obtain an opaque license request blob that is delivered to the
+ // license server.
+ //
+ // The init data passed to getLicenseRequest is container-specific and its
+ // meaning is interpreted based on the mime type provided in the mimeType
+ // parameter to getLicenseRequest. It could contain, for example, the content
+ // ID, key ID or other data obtained from the content metadata that is required
+ // in generating the license request.
+ //
+ // licenseType specifes if the license is for streaming or offline content
+ //
+ // optionalParameters are included in the license server request message to
+ // allow a client application to provide additional message parameters to the
+ // server.
+ //
+ // If successful, the opaque license request blob is returned to the caller.
+ virtual status_t
+ getLicenseRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, LicenseType licenseType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl) = 0;
+
+ // After a license response is received by the app, it is provided to the
+ // Drm plugin using provideLicenseResponse.
+ virtual status_t provideLicenseResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response) = 0;
+
+ // Remove the keys associated with a license.
+ virtual status_t removeLicense(Vector<uint8_t> const &sessionId) = 0;
+
+ // Request an informative description of the license for the session. The status
+ // is in the form of {name, value} pairs. Since DRM license policies vary by
+ // vendor, the specific status field names are determined by each DRM vendor.
+ // Refer to your DRM provider documentation for definitions of the field names
+ // for a particular DrmEngine.
+ virtual status_t
+ queryLicenseStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const = 0;
+
+ // A provision request/response exchange occurs between the app and a
+ // provisioning server to retrieve a device certificate. getProvisionRequest
+ // is used to obtain an opaque license request blob that is delivered to the
+ // provisioning server.
+ //
+ // If successful, the opaque provision request blob is returned to the caller.
+ virtual status_t getProvisionRequest(Vector<uint8_t> &request,
+ String8 &defaultUrl) = 0;
+
+ // After a provision response is received by the app, it is provided to the
+ // Drm plugin using provideProvisionResponse.
+ virtual status_t provideProvisionResponse(Vector<uint8_t> const &response) = 0;
+
+ // A means of enforcing the contractual requirement for a concurrent stream
+ // limit per subscriber across devices is provided via SecureStop. SecureStop
+ // is a means of securely monitoring the lifetime of sessions. Since playback
+ // on a device can be interrupted due to reboot, power failure, etc. a means
+ // of persisting the lifetime information on the device is needed.
+ //
+ // A signed version of the sessionID is written to persistent storage on the
+ // device when each MediaCrypto object is created. The sessionID is signed by
+ // the device private key to prevent tampering.
+ //
+ // In the normal case, playback will be completed, the session destroyed and
+ // the Secure Stops will be queried. The App queries secure stops and forwards
+ // the secure stop message to the server which verifies the signature and
+ // notifies the server side database that the session destruction has been
+ // confirmed. The persisted record on the client is only removed after positive
+ // confirmation that the server received the message using releaseSecureStops().
+ virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
+ virtual status_t releaseSecureStops(Vector<uint8_t> const &ssRelease) = 0;
+
+ // Read a property value given the device property string. There are a few forms
+ // of property access methods, depending on the data type returned.
+ // Since DRM plugin properties may vary, additional field names may be defined
+ // by each DRM vendor. Refer to your DRM provider documentation for definitions
+ // of its additional field names.
+ //
+ // Standard values are:
+ // "vendor" [string] identifies the maker of the plugin
+ // "version" [string] identifies the version of the plugin
+ // "description" [string] describes the plugin
+ // 'deviceUniqueId' [byte array] The device unique identifier is established
+ // during device provisioning and provides a means of uniquely identifying
+ // each device.
+ virtual status_t getPropertyString(String8 const &name, String8 &value ) const = 0;
+ virtual status_t getPropertyByteArray(String8 const &name,
+ Vector<uint8_t> &value ) const = 0;
+
+ // Write a property value given the device property string. There are a few forms
+ // of property setting methods, depending on the data type.
+ // Since DRM plugin properties may vary, additional field names may be defined
+ // by each DRM vendor. Refer to your DRM provider documentation for definitions
+ // of its field names.
+ virtual status_t setPropertyString(String8 const &name,
+ String8 const &value ) = 0;
+ virtual status_t setPropertyByteArray(String8 const &name,
+ Vector<uint8_t> const &value ) = 0;
+
+ // TODO: provide way to send an event
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(DrmPlugin);
+ };
+
+} // namespace android
+
+#endif // DRM_API_H_
diff --git a/include/media/drm/DrmClientAPI.h b/include/media/drm/DrmClientAPI.h
deleted file mode 100644
index 6a08933..0000000
--- a/include/media/drm/DrmClientAPI.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef DRM_CLIENT_API_H_
-#define DRM_CLIENT_API_H_
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/List.h>
-#include <media/stagefright/foundation/ABase.h>
-
-namespace android {
-
- // A DrmMessageStatus object aggregates a sessionId, which uniquely
- // identifies a playback context with a status code and opaque message
- // data.
- struct DrmMessageStatus {
- Vector<uint8_t> mSessionId;
- status_t mStatus;
- Vector<uint8_t> mData;
- };
-
- class DrmClientPlugin {
- public:
-
- // A license can be for downloaded, offline content or for online streaming
- // Offline licenses are persisted on the device and may be used when the device
- // is disconnected from the network.
- enum LicenseType {
- kLicenseType_Offline,
- kLicenseType_Streaming
- };
-
- DrmClientPlugin() {}
- virtual ~DrmClientPlugin() {}
-
- // A license request/response exchange occurs between the app and a License
- // Server to obtain the keys required to decrypt the content. getLicenseRequest()
- // is used to obtain an opaque license request blob that is delivered to the
- // license server.
- //
- // The init data passed to getLicenseRequest is container-specific and its
- // meaning is interpreted based on the mime type provided in the mimeType
- // parameter to getLicenseRequest. It could contain, for example, the content
- // ID, key ID or other data obtained from the content metadata that is required
- // in generating the license request.
- //
- // The DrmMessageStatus returned from getLicenseRequest contains a sessionId for
- // the new session, a status code indicating whether the operation was successful
- // and if so, the request blob is placed into the mData field.
- virtual DrmMessageStatus getLicenseRequest(Vector<uint8_t> const &initData,
- String8 const &mimeType, LicenseType licenseType) = 0;
-
- // After a license response is received by the app, it is provided to the
- // DrmClient plugin using provideLicenseResponse. The response data is provided
- // in the mData field of the response parameter.
- virtual status_t provideLicenseResponse(DrmMessageStatus const &response) = 0;
-
- // Remove the keys associated with a license and release the session
- virtual status_t clearLicense(Vector<uint8_t> const &sessionId) = 0;
-
- // A provision request/response exchange occurs between the app and a
- // provisioning server to retrieve a device certificate. getProvisionRequest
- // is used to obtain an opaque license request blob that is delivered to the
- // provisioning server.
- //
- // The DrmMessageStatus returned from getLicenseRequest contains a status code
- // indicating whether the operation was successful and if so, the request blob
- // is placed into the mData field.
- virtual DrmMessageStatus getProvisionRequest() = 0;
-
- // After a provision response is received by the app, it is provided to the
- // DrmClient plugin using provideProvisionResponse. The response data is
- // provided in the mData field of the response parameter.
- virtual status_t provideProvisionResponse(DrmMessageStatus const &response) = 0;
-
- // A means of enforcing the contractual requirement for a concurrent stream
- // limit per subscriber across devices is provided via SecureStop. SecureStop
- // is a means of securely monitoring the lifetime of sessions. Since playback
- // on a device can be interrupted due to reboot, power failure, etc. a means
- // of persisting the lifetime information on the device is needed.
- //
- // A signed version of the sessionID is written to persistent storage on the
- // device when each MediaCrypto object is created. The sessionID is signed by
- // the device private key to prevent tampering.
- //
- // In the normal case, playback will be completed, the session destroyed and
- // the Secure Stops will be queried. The App queries secure stops and forwards
- // the secure stop message to the server which verifies the signature and
- // notifies the server side database that the session destruction has been
- // confirmed. The persisted record on the client is only removed after positive
- // confirmation that the server received the message using releaseSecureStops().
- virtual List<DrmMessageStatus> getSecureStops() = 0;
- virtual status_t releaseSecureStops(DrmMessageStatus const &ssRelease) = 0;
-
- // Retrieve the device unique identifier for this device. The device unique
- // identifier is established during device provisioning.
- virtual Vector<uint8_t> getDeviceUniqueId() const = 0;
-
- private:
- DISALLOW_EVIL_CONSTRUCTORS(DrmClientPlugin);
- };
-
-} // namespace android
-
-#endif // DRM_CLIENT_API_H_
diff --git a/include/media/drm/DrmEngineAPI.h b/include/media/drm/DrmEngineAPI.h
deleted file mode 100644
index 25bd34a..0000000
--- a/include/media/drm/DrmEngineAPI.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2012 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.
- */
-
-#ifndef DRM_ENGINE_API_H_
-#define DRM_ENGINE_API_H_
-
-#include <utils/Errors.h>
-#include <media/stagefright/foundation/ABase.h>
-
-
-namespace android {
-
- class CryptoPlugin;
- class DrmClientPlugin;
-
- // DRMs are implemented in DrmEngine plugins, which are dynamically
- // loadable shared libraries that implement the entry point
- // createDrmPluginFactory. createDrmPluginFactory constructs and returns
- // an instance of a DrmPluginFactory object. When a MediaCrypto or
- // DrmClient object needs to be constructed, all available
- // DrmEngines present in the plugins directory on the device are scanned
- // for a matching DrmEngine that can support the crypto scheme. When a
- // match is found, the DrmEngine’s createCryptoPlugin or
- // createDrmClientPlugin methods are used to create CryptoPlugin or
- // DrmClientPlugin instances to support that DRM scheme.
-
- class DrmPluginFactory {
- public:
- DrmPluginFactory() {}
- virtual ~DrmPluginFactory() {}
-
- // DrmPluginFactory::isCryptoSchemeSupported can be called to determine
- // if the plugin factory is able to construct plugins that support a
- // given crypto scheme, which is specified by a UUID.
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
-
- // Construct a CryptoPlugin for the crypto scheme specified by UUID.
- // {data, size} provide scheme-specific initialization data.
- virtual status_t createCryptoPlugin(
- const uint8_t uuid[16], const void *data, size_t size,
- CryptoPlugin **plugin) = 0;
-
- // Construct a DrmClientPlugin for the crypto scheme specified by UUID.
- // {data, size} provide scheme-specific initialization data.
- virtual status_t createDrmClientPlugin(
- const uint8_t uuid[16], const void *data, size_t size,
- DrmClientPlugin **plugin) = 0;
-
- private:
- DISALLOW_EVIL_CONSTRUCTORS(DrmPluginFactory);
- };
-
-} // namespace android
-
- // Loadable DrmEngine shared libraries should define the entry point
- // createDrmPluginFactory as shown below:
- //
- // extern "C" {
- // extern android::DrmPluginFactory *createDrmPluginFactory();
- // }
-
-#endif // DRM_ENGINE_API_H_
diff --git a/include/utils/CallStack.h b/include/utils/CallStack.h
index 079e20c..61dc832 100644
--- a/include/utils/CallStack.h
+++ b/include/utils/CallStack.h
@@ -35,6 +35,8 @@
};
CallStack();
+ CallStack(const char* logtag, int32_t ignoreDepth=1,
+ int32_t maxDepth=MAX_DEPTH);
CallStack(const CallStack& rhs);
~CallStack();
@@ -53,8 +55,8 @@
void update(int32_t ignoreDepth=1, int32_t maxDepth=MAX_DEPTH);
- // Dump a stack trace to the log
- void dump(const char* prefix = 0) const;
+ // Dump a stack trace to the log using the supplied logtag
+ void dump(const char* logtag, const char* prefix = 0) const;
// Return a string (possibly very long) containing the complete stack trace
String8 toString(const char* prefix = 0) const;
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 0a8e10a..033fe67 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -52,12 +52,16 @@
}
// ---------------------------------------------------------------------------
-class ReferenceMover;
-class ReferenceConverterBase {
+
+class ReferenceRenamer {
+protected:
+ // destructor is purposedly not virtual so we avoid code overhead from
+ // subclasses; we have to make it protected to guarantee that it
+ // cannot be called from this base class (and to make strict compilers
+ // happy).
+ ~ReferenceRenamer() { }
public:
- virtual size_t getReferenceTypeSize() const = 0;
- virtual void* getReferenceBase(void const*) const = 0;
- inline virtual ~ReferenceConverterBase() { }
+ virtual void operator()(size_t i) const = 0;
};
// ---------------------------------------------------------------------------
@@ -144,17 +148,23 @@
virtual void onLastWeakRef(const void* id);
private:
- friend class ReferenceMover;
- static void moveReferences(void* d, void const* s, size_t n,
- const ReferenceConverterBase& caster);
-
-private:
friend class weakref_type;
class weakref_impl;
RefBase(const RefBase& o);
RefBase& operator=(const RefBase& o);
+private:
+ friend class ReferenceMover;
+
+ static void renameRefs(size_t n, const ReferenceRenamer& renamer);
+
+ static void renameRefId(weakref_type* ref,
+ const void* old_id, const void* new_id);
+
+ static void renameRefId(RefBase* ref,
+ const void* old_id, const void* new_id);
+
weakref_impl* const mRefs;
};
@@ -185,8 +195,9 @@
private:
friend class ReferenceMover;
- inline static void moveReferences(void* d, void const* s, size_t n,
- const ReferenceConverterBase& caster) { }
+ inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
+ inline static void renameRefId(T* ref,
+ const void* old_id, const void* new_id) { }
private:
mutable volatile int32_t mCount;
@@ -455,42 +466,48 @@
// this class just serves as a namespace so TYPE::moveReferences can stay
// private.
-
class ReferenceMover {
- // StrongReferenceCast and WeakReferenceCast do the impedance matching
- // between the generic (void*) implementation in Refbase and the strongly typed
- // template specializations below.
-
- template <typename TYPE>
- struct StrongReferenceCast : public ReferenceConverterBase {
- virtual size_t getReferenceTypeSize() const { return sizeof( sp<TYPE> ); }
- virtual void* getReferenceBase(void const* p) const {
- sp<TYPE> const* sptr(reinterpret_cast<sp<TYPE> const*>(p));
- return static_cast<typename TYPE::basetype *>(sptr->get());
- }
- };
-
- template <typename TYPE>
- struct WeakReferenceCast : public ReferenceConverterBase {
- virtual size_t getReferenceTypeSize() const { return sizeof( wp<TYPE> ); }
- virtual void* getReferenceBase(void const* p) const {
- wp<TYPE> const* sptr(reinterpret_cast<wp<TYPE> const*>(p));
- return static_cast<typename TYPE::basetype *>(sptr->unsafe_get());
- }
- };
-
public:
+ // it would be nice if we could make sure no extra code is generated
+ // for sp<TYPE> or wp<TYPE> when TYPE is a descendant of RefBase:
+ // Using a sp<RefBase> override doesn't work; it's a bit like we wanted
+ // a template<typename TYPE inherits RefBase> template...
+
template<typename TYPE> static inline
void move_references(sp<TYPE>* d, sp<TYPE> const* s, size_t n) {
+
+ class Renamer : public ReferenceRenamer {
+ sp<TYPE>* d;
+ sp<TYPE> const* s;
+ virtual void operator()(size_t i) const {
+ // The id are known to be the sp<>'s this pointer
+ TYPE::renameRefId(d[i].get(), &s[i], &d[i]);
+ }
+ public:
+ Renamer(sp<TYPE>* d, sp<TYPE> const* s) : s(s), d(d) { }
+ };
+
memmove(d, s, n*sizeof(sp<TYPE>));
- StrongReferenceCast<TYPE> caster;
- TYPE::moveReferences(d, s, n, caster);
+ TYPE::renameRefs(n, Renamer(d, s));
}
+
+
template<typename TYPE> static inline
void move_references(wp<TYPE>* d, wp<TYPE> const* s, size_t n) {
+
+ class Renamer : public ReferenceRenamer {
+ wp<TYPE>* d;
+ wp<TYPE> const* s;
+ virtual void operator()(size_t i) const {
+ // The id are known to be the wp<>'s this pointer
+ TYPE::renameRefId(d[i].get_refs(), &s[i], &d[i]);
+ }
+ public:
+ Renamer(wp<TYPE>* d, wp<TYPE> const* s) : s(s), d(d) { }
+ };
+
memmove(d, s, n*sizeof(wp<TYPE>));
- WeakReferenceCast<TYPE> caster;
- TYPE::moveReferences(d, s, n, caster);
+ TYPE::renameRefs(n, Renamer(d, s));
}
};
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index cd2451a..07cb41a 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -246,9 +246,7 @@
if (VERBOSE) {
ALOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
binder.get(), this, mSize, mHeapId);
- CallStack stack;
- stack.update();
- stack.dump("callstack");
+ CallStack stack(LOG_TAG);
}
munmap(mBase, mSize);
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 1ee6673..a638cfa 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -17,8 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "CpuConsumer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <utils/Log.h>
+#include <cutils/compiler.h>
+#include <utils/Log.h>
#include <gui/CpuConsumer.h>
#define CC_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
@@ -34,9 +35,8 @@
mMaxLockedBuffers(maxLockedBuffers),
mCurrentLockedBuffers(0)
{
- for (size_t i=0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- mLockedSlots[i].mBufferPointer = NULL;
- }
+ // Create tracking entries for locked buffers
+ mAcquiredBuffers.insertAt(0, maxLockedBuffers);
mBufferQueue->setSynchronousMode(synchronousMode);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
@@ -44,21 +44,11 @@
}
CpuConsumer::~CpuConsumer() {
- status_t err;
- for (size_t i=0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
- if (mLockedSlots[i].mBufferPointer != NULL) {
- mLockedSlots[i].mBufferPointer = NULL;
- err = mLockedSlots[i].mGraphicBuffer->unlock();
- mLockedSlots[i].mGraphicBuffer.clear();
- if (err != OK) {
- CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__,
- i);
- }
-
- }
- }
+ // ConsumerBase destructor does all the work.
}
+
+
void CpuConsumer::setName(const String8& name) {
Mutex::Autolock _l(mMutex);
mName = name;
@@ -109,8 +99,19 @@
err);
return err;
}
- mLockedSlots[buf].mBufferPointer = bufferPointer;
- mLockedSlots[buf].mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+ size_t lockedIdx = 0;
+ for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) {
+ if (mAcquiredBuffers[lockedIdx].mSlot ==
+ BufferQueue::INVALID_BUFFER_SLOT) {
+ break;
+ }
+ }
+ assert(lockedIdx < mMaxLockedBuffers);
+
+ AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
+ ab.mSlot = buf;
+ ab.mBufferPointer = bufferPointer;
+ ab.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
nativeBuffer->data =
reinterpret_cast<uint8_t*>(bufferPointer);
@@ -132,29 +133,46 @@
status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
Mutex::Autolock _l(mMutex);
- int slotIndex = 0;
+ size_t lockedIdx = 0;
status_t err;
void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
- for (; slotIndex < BufferQueue::NUM_BUFFER_SLOTS; slotIndex++) {
- if (bufPtr == mLockedSlots[slotIndex].mBufferPointer) break;
+ for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) {
+ if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break;
}
- if (slotIndex == BufferQueue::NUM_BUFFER_SLOTS) {
+ if (lockedIdx == mMaxLockedBuffers) {
CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
return BAD_VALUE;
}
- mLockedSlots[slotIndex].mBufferPointer = NULL;
- err = mLockedSlots[slotIndex].mGraphicBuffer->unlock();
- mLockedSlots[slotIndex].mGraphicBuffer.clear();
+ return releaseAcquiredBufferLocked(lockedIdx);
+}
+
+status_t CpuConsumer::releaseAcquiredBufferLocked(int lockedIdx) {
+ status_t err;
+
+ err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlock();
if (err != OK) {
- CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex);
+ CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__,
+ lockedIdx);
return err;
}
- releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ int buf = mAcquiredBuffers[lockedIdx].mSlot;
+
+ // release the buffer if it hasn't already been freed by the BufferQueue.
+ // This can happen, for example, when the producer of this buffer
+ // disconnected after this buffer was acquired.
+ if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer ==
+ mSlots[buf].mGraphicBuffer)) {
+ releaseBufferLocked(buf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ }
+
+ AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
+ ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ ab.mBufferPointer = NULL;
+ ab.mGraphicBuffer.clear();
mCurrentLockedBuffers--;
-
return OK;
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 0a79ff7..6442a86 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -102,31 +102,11 @@
remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply);
}
- virtual status_t captureScreen(
- const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- data.writeStrongBinder(display);
- data.writeInt32(reqWidth);
- data.writeInt32(reqHeight);
- data.writeInt32(minLayerZ);
- data.writeInt32(maxLayerZ);
- remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN_DEPRECATED, data, &reply);
- *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
- *width = reply.readInt32();
- *height = reply.readInt32();
- *format = reply.readInt32();
- return reply.readInt32();
- }
-
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -136,6 +116,7 @@
data.writeInt32(reqHeight);
data.writeInt32(minLayerZ);
data.writeInt32(maxLayerZ);
+ data.writeInt32(isCpuConsumer);
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
return reply.readInt32();
}
@@ -285,24 +266,6 @@
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
} break;
- case CAPTURE_SCREEN_DEPRECATED: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IBinder> display = data.readStrongBinder();
- uint32_t reqWidth = data.readInt32();
- uint32_t reqHeight = data.readInt32();
- uint32_t minLayerZ = data.readInt32();
- uint32_t maxLayerZ = data.readInt32();
- sp<IMemoryHeap> heap;
- uint32_t w, h;
- PixelFormat f;
- status_t res = captureScreen(display, &heap, &w, &h, &f,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
- reply->writeStrongBinder(heap->asBinder());
- reply->writeInt32(w);
- reply->writeInt32(h);
- reply->writeInt32(f);
- reply->writeInt32(res);
- } break;
case CAPTURE_SCREEN: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
sp<IBinder> display = data.readStrongBinder();
@@ -312,8 +275,10 @@
uint32_t reqHeight = data.readInt32();
uint32_t minLayerZ = data.readInt32();
uint32_t maxLayerZ = data.readInt32();
+ bool isCpuConsumer = data.readInt32();
status_t res = captureScreen(display, producer,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ isCpuConsumer);
reply->writeInt32(res);
} break;
case AUTHENTICATE_SURFACE: {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 4a4c0c8..ec46fce 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -31,6 +31,7 @@
#include <ui/DisplayInfo.h>
+#include <gui/CpuConsumer.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
@@ -617,30 +618,21 @@
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
return s->captureScreen(display, producer,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ false);
}
ScreenshotClient::ScreenshotClient()
- : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
+ : mHaveBuffer(false) {
+ memset(&mBuffer, 0, sizeof(mBuffer));
}
-status_t ScreenshotClient::update(const sp<IBinder>& display) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, 0, 0,
- 0, -1UL);
-}
-
-status_t ScreenshotClient::update(const sp<IBinder>& display,
- uint32_t reqWidth, uint32_t reqHeight) {
- sp<ISurfaceComposer> s(ComposerService::getComposerService());
- if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
- 0, -1UL);
+sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
+ if (mCpuConsumer == NULL) {
+ mCpuConsumer = new CpuConsumer(1);
+ mCpuConsumer->setName(String8("ScreenshotClient"));
+ }
+ return mCpuConsumer;
}
status_t ScreenshotClient::update(const sp<IBinder>& display,
@@ -648,38 +640,66 @@
uint32_t minLayerZ, uint32_t maxLayerZ) {
sp<ISurfaceComposer> s(ComposerService::getComposerService());
if (s == NULL) return NO_INIT;
- mHeap = 0;
- return s->captureScreen(display, &mHeap,
- &mWidth, &mHeight, &mFormat, reqWidth, reqHeight,
- minLayerZ, maxLayerZ);
+ sp<CpuConsumer> cpuConsumer = getCpuConsumer();
+
+ if (mHaveBuffer) {
+ mCpuConsumer->unlockBuffer(mBuffer);
+ memset(&mBuffer, 0, sizeof(mBuffer));
+ mHaveBuffer = false;
+ }
+
+ status_t err = s->captureScreen(display,cpuConsumer->getBufferQueue(),
+ reqWidth, reqHeight, minLayerZ, maxLayerZ, true);
+
+ if (err == NO_ERROR) {
+ err = mCpuConsumer->lockNextBuffer(&mBuffer);
+ if (err == NO_ERROR) {
+ mHaveBuffer = true;
+ }
+ }
+ return err;
+}
+
+status_t ScreenshotClient::update(const sp<IBinder>& display) {
+ return ScreenshotClient::update(display, 0, 0, 0, -1UL);
+}
+
+status_t ScreenshotClient::update(const sp<IBinder>& display,
+ uint32_t reqWidth, uint32_t reqHeight) {
+ return ScreenshotClient::update(display, reqWidth, reqHeight, 0, -1UL);
}
void ScreenshotClient::release() {
- mHeap = 0;
+ if (mHaveBuffer) {
+ mCpuConsumer->unlockBuffer(mBuffer);
+ memset(&mBuffer, 0, sizeof(mBuffer));
+ mHaveBuffer = false;
+ }
+ mCpuConsumer.clear();
}
void const* ScreenshotClient::getPixels() const {
- return mHeap->getBase();
+ return mBuffer.data;
}
uint32_t ScreenshotClient::getWidth() const {
- return mWidth;
+ return mBuffer.width;
}
uint32_t ScreenshotClient::getHeight() const {
- return mHeight;
+ return mBuffer.height;
}
PixelFormat ScreenshotClient::getFormat() const {
- return mFormat;
+ return mBuffer.format;
}
uint32_t ScreenshotClient::getStride() const {
- return mWidth;
+ return mBuffer.stride;
}
size_t ScreenshotClient::getSize() const {
- return mHeap->getSize();
+ return mBuffer.stride * mBuffer.height * bytesPerPixel(mBuffer.format);
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index bb57948..f4e88f5 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -102,7 +102,7 @@
const sp<SurfaceComposerClient>& client(mClient);
return client->setLayer(mHandle, layer);
}
-status_t SurfaceControl::setPosition(int32_t x, int32_t y) {
+status_t SurfaceControl::setPosition(float x, float y) {
status_t err = validate();
if (err < 0) return err;
const sp<SurfaceComposerClient>& client(mClient);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 545b547..429becf 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -23,11 +23,17 @@
#include <utils/String8.h>
#include <private/gui/ComposerService.h>
+#include <binder/ProcessState.h>
namespace android {
class SurfaceTest : public ::testing::Test {
protected:
+
+ SurfaceTest() {
+ ProcessState::self()->startThreadPool();
+ }
+
virtual void SetUp() {
mComposerClient = new SurfaceComposerClient;
ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
@@ -81,14 +87,11 @@
sp<ANativeWindow> anw(mSurface);
// Verify the screenshot works with no protected buffers.
- sp<IMemoryHeap> heap;
- uint32_t w=0, h=0;
- PixelFormat fmt=0;
+ sp<CpuConsumer> consumer = new CpuConsumer(1);
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt, 64, 64, 0,
- 0x7fffffff));
- ASSERT_TRUE(heap != NULL);
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
+ 64, 64, 0, 0x7fffffff, true));
// Set the PROTECTED usage bit and verify that the screenshot fails. Note
// that we need to dequeue a buffer in order for it to actually get
@@ -116,11 +119,8 @@
&buf));
ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1));
}
- heap = 0;
- w = h = fmt = 0;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &heap, &w, &h, &fmt,
- 64, 64, 0, 0x7fffffff));
- ASSERT_TRUE(heap != NULL);
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
+ 64, 64, 0, 0x7fffffff, true));
}
TEST_F(SurfaceTest, ConcreteTypeIsSurface) {
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 1a613f8..488fba3 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -530,9 +530,7 @@
}
if (result == false && !silent) {
reg.dump(name);
- CallStack stack;
- stack.update();
- stack.dump("");
+ CallStack stack(LOG_TAG);
}
return result;
}
diff --git a/libs/utils/CallStack.cpp b/libs/utils/CallStack.cpp
index 66fabeb..e60f5d8 100644
--- a/libs/utils/CallStack.cpp
+++ b/libs/utils/CallStack.cpp
@@ -30,6 +30,11 @@
mCount(0) {
}
+CallStack::CallStack(const char* logtag, int32_t ignoreDepth, int32_t maxDepth) {
+ this->update(ignoreDepth+1, maxDepth);
+ this->dump(logtag);
+}
+
CallStack::CallStack(const CallStack& rhs) :
mCount(rhs.mCount) {
if (mCount) {
@@ -96,7 +101,7 @@
mCount = count > 0 ? count : 0;
}
-void CallStack::dump(const char* prefix) const {
+void CallStack::dump(const char* logtag, const char* prefix) const {
backtrace_symbol_t symbols[mCount];
get_backtrace_symbols(mStack, mCount, symbols);
@@ -104,7 +109,9 @@
char line[MAX_BACKTRACE_LINE_LENGTH];
format_backtrace_line(i, &mStack[i], &symbols[i],
line, MAX_BACKTRACE_LINE_LENGTH);
- ALOGD("%s%s", prefix, line);
+ ALOG(LOG_DEBUG, logtag, "%s%s",
+ prefix ? prefix : "",
+ line);
}
free_backtrace_symbols(symbols, mCount);
}
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 0623f46..e538f68 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -15,7 +15,7 @@
*/
#define LOG_TAG "RefBase"
-#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <utils/RefBase.h>
@@ -35,10 +35,18 @@
// compile with refcounting debugging enabled
#define DEBUG_REFS 0
-#define DEBUG_REFS_FATAL_SANITY_CHECKS 0
-#define DEBUG_REFS_ENABLED_BY_DEFAULT 1
+
+// whether ref-tracking is enabled by default, if not, trackMe(true, false)
+// needs to be called explicitly
+#define DEBUG_REFS_ENABLED_BY_DEFAULT 0
+
+// whether callstack are collected (significantly slows things down)
#define DEBUG_REFS_CALLSTACK_ENABLED 1
+// folder where stack traces are saved when DEBUG_REFS is enabled
+// this folder needs to exist and be writable
+#define DEBUG_REFS_CALLSTACK_PATH "/data/debug"
+
// log all reference counting operations
#define PRINT_REFS 0
@@ -96,17 +104,13 @@
bool dumpStack = false;
if (!mRetain && mStrongRefs != NULL) {
dumpStack = true;
-#if DEBUG_REFS_FATAL_SANITY_CHECKS
- LOG_ALWAYS_FATAL("Strong references remain!");
-#else
ALOGE("Strong references remain:");
-#endif
ref_entry* refs = mStrongRefs;
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.dump();
+ refs->stack.dump(LOG_TAG);
#endif
refs = refs->next;
}
@@ -114,26 +118,20 @@
if (!mRetain && mWeakRefs != NULL) {
dumpStack = true;
-#if DEBUG_REFS_FATAL_SANITY_CHECKS
- LOG_ALWAYS_FATAL("Weak references remain:");
-#else
ALOGE("Weak references remain!");
-#endif
ref_entry* refs = mWeakRefs;
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
ALOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
#if DEBUG_REFS_CALLSTACK_ENABLED
- refs->stack.dump();
+ refs->stack.dump(LOG_TAG);
#endif
refs = refs->next;
}
}
if (dumpStack) {
ALOGE("above errors at:");
- CallStack stack;
- stack.update();
- stack.dump();
+ CallStack stack(LOG_TAG);
}
}
@@ -199,7 +197,7 @@
{
char name[100];
- snprintf(name, 100, "/data/%p.stack", this);
+ snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
write(rc, text.string(), text.length());
@@ -258,12 +256,6 @@
ref = *refs;
}
-#if DEBUG_REFS_FATAL_SANITY_CHECKS
- LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
- "(weakref_type %p) that doesn't exist!",
- id, mBase, this);
-#endif
-
ALOGE("RefBase: removing id %p on RefBase %p"
"(weakref_type %p) that doesn't exist!",
id, mBase, this);
@@ -275,9 +267,7 @@
ref = ref->next;
}
- CallStack stack;
- stack.update();
- stack.dump();
+ CallStack stack(LOG_TAG);
}
}
@@ -637,21 +627,27 @@
// ---------------------------------------------------------------------------
-void RefBase::moveReferences(void* dst, void const* src, size_t n,
- const ReferenceConverterBase& caster)
-{
+void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) {
#if DEBUG_REFS
- const size_t itemSize = caster.getReferenceTypeSize();
for (size_t i=0 ; i<n ; i++) {
- void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize);
- void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
- RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
- ref->mRefs->renameStrongRefId(s, d);
- ref->mRefs->renameWeakRefId(s, d);
+ renamer(i);
}
#endif
}
+void RefBase::renameRefId(weakref_type* ref,
+ const void* old_id, const void* new_id) {
+ weakref_impl* const impl = static_cast<weakref_impl*>(ref);
+ impl->renameStrongRefId(old_id, new_id);
+ impl->renameWeakRefId(old_id, new_id);
+}
+
+void RefBase::renameRefId(RefBase* ref,
+ const void* old_id, const void* new_id) {
+ ref->mRefs->renameStrongRefId(old_id, new_id);
+ ref->mRefs->renameWeakRefId(old_id, new_id);
+}
+
// ---------------------------------------------------------------------------
TextOutput& printStrongPointer(TextOutput& to, const void* val)
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index a8691b5..a6e91e0 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -222,9 +222,7 @@
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.callstack", value, "0");
if (atoi(value)) {
- CallStack stack;
- stack.update();
- stack.dump();
+ CallStack stack(LOG_TAG);
}
}
return 0;
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index 41cfae1..52312a2 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -78,9 +78,7 @@
char value[PROPERTY_VALUE_MAX];
property_get("debug.egl.callstack", value, "0");
if (atoi(value)) {
- CallStack stack;
- stack.update();
- stack.dump();
+ CallStack stack(LOG_TAG);
}
}
tls->error = error;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index eeb1fef..8599a29 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -99,7 +99,7 @@
bool needVSyncThread = true;
// Note: some devices may insist that the FB HAL be opened before HWC.
- loadFbHalModule();
+ int fberr = loadFbHalModule();
loadHwcModule();
if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
@@ -113,7 +113,8 @@
// If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
&& !mFbDev) {
- ALOGE("ERROR: failed to open framebuffer, aborting");
+ ALOGE("ERROR: failed to open framebuffer (%s), aborting",
+ strerror(-fberr));
abort();
}
@@ -234,20 +235,17 @@
}
// Load and prepare the FB HAL, which uses the gralloc module. Sets mFbDev.
-void HWComposer::loadFbHalModule()
+int HWComposer::loadFbHalModule()
{
hw_module_t const* module;
- if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
+ int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+ if (err != 0) {
ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
- return;
+ return err;
}
- int err = framebuffer_open(module, &mFbDev);
- if (err) {
- ALOGE("framebuffer_open failed (%s)", strerror(-err));
- return;
- }
+ return framebuffer_open(module, &mFbDev);
}
status_t HWComposer::initCheck() const {
@@ -514,6 +512,7 @@
&disp.framebufferTarget->displayFrame;
disp.framebufferTarget->acquireFenceFd = -1;
disp.framebufferTarget->releaseFenceFd = -1;
+ disp.framebufferTarget->planeAlpha = 0xFF;
}
disp.list->retireFenceFd = -1;
disp.list->flags = HWC_GEOMETRY_CHANGED;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 92e4cbf..fdbd2d9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -265,7 +265,7 @@
private:
void loadHwcModule();
- void loadFbHalModule();
+ int loadFbHalModule();
LayerListIterator getLayerIterator(int32_t id, size_t index);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7fcbd2e..0e5d602 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -109,6 +109,9 @@
// debugging stuff...
char value[PROPERTY_VALUE_MAX];
+ property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
+ mGpuToCpuSupported = !atoi(value);
+
property_get("debug.sf.showupdates", value, "0");
mDebugRegion = atoi(value);
@@ -489,6 +492,10 @@
mEGLConfig = selectEGLConfig(mEGLDisplay, format);
mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
+ // figure out which format we got
+ eglGetConfigAttrib(mEGLDisplay, mEGLConfig,
+ EGL_NATIVE_VISUAL_ID, &mEGLNativeVisualId);
+
LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext");
@@ -2328,13 +2335,18 @@
" transaction-flags : %08x\n"
" refresh-rate : %f fps\n"
" x-dpi : %f\n"
- " y-dpi : %f\n",
+ " y-dpi : %f\n"
+ " EGL_NATIVE_VISUAL_ID : %d\n"
+ " gpu_to_cpu_unsupported : %d\n"
+ ,
mLastSwapBufferTime/1000.0,
mLastTransactionTime/1000.0,
mTransactionFlags,
1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
hwc.getDpiX(HWC_DISPLAY_PRIMARY),
- hwc.getDpiY(HWC_DISPLAY_PRIMARY));
+ hwc.getDpiY(HWC_DISPLAY_PRIMARY),
+ mEGLNativeVisualId,
+ !mGpuToCpuSupported);
result.append(buffer);
snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n",
@@ -2416,7 +2428,6 @@
break;
}
case CAPTURE_SCREEN:
- case CAPTURE_SCREEN_DEPRECATED:
{
// codes that require permission check
IPCThreadState* ipc = IPCThreadState::self();
@@ -2511,7 +2522,8 @@
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ) {
+ uint32_t minLayerZ, uint32_t maxLayerZ,
+ bool isCpuConsumer) {
if (CC_UNLIKELY(display == 0))
return BAD_VALUE;
@@ -2525,16 +2537,18 @@
sp<IGraphicBufferProducer> producer;
uint32_t reqWidth, reqHeight;
uint32_t minLayerZ,maxLayerZ;
+ bool isCpuConsumer;
status_t result;
public:
MessageCaptureScreen(SurfaceFlinger* flinger,
const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
+ uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer)
: flinger(flinger), display(display), producer(producer),
reqWidth(reqWidth), reqHeight(reqHeight),
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
+ isCpuConsumer(isCpuConsumer),
result(PERMISSION_DENIED)
{
}
@@ -2544,14 +2558,40 @@
virtual bool handler() {
Mutex::Autolock _l(flinger->mStateLock);
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
- result = flinger->captureScreenImplLocked(hw, producer,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
+
+ bool useReadPixels = false;
+ if (isCpuConsumer) {
+ bool formatSupportedBytBitmap =
+ (flinger->mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBA_8888) ||
+ (flinger->mEGLNativeVisualId == HAL_PIXEL_FORMAT_RGBX_8888);
+ if (formatSupportedBytBitmap == false) {
+ // the pixel format we have is not compatible with
+ // Bitmap.java, which is the likely client of this API,
+ // so we just revert to glReadPixels() in that case.
+ useReadPixels = true;
+ }
+ if (flinger->mGpuToCpuSupported == false) {
+ // When we know the GL->CPU path works, we can call
+ // captureScreenImplLocked() directly, instead of using the
+ // glReadPixels() workaround.
+ useReadPixels = true;
+ }
+ }
+
+ if (!useReadPixels) {
+ result = flinger->captureScreenImplLocked(hw,
+ producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ } else {
+ result = flinger->captureScreenImplCpuConsumerLocked(hw,
+ producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ }
return true;
}
};
sp<MessageBase> msg = new MessageCaptureScreen(this,
- display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
+ display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ,
+ isCpuConsumer);
status_t res = postMessageSync(msg);
if (res == NO_ERROR) {
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
@@ -2655,18 +2695,15 @@
}
eglDestroySurface(mEGLDisplay, eglSurface);
+
return NO_ERROR;
}
-// ---------------------------------------------------------------------------
-// Capture screen into an IMemoryHeap (legacy)
-// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::captureScreenImplLocked(
+status_t SurfaceFlinger::captureScreenImplCpuConsumerLocked(
const sp<const DisplayDevice>& hw,
- sp<IMemoryHeap>* heap,
- uint32_t* w, uint32_t* h, PixelFormat* f,
- uint32_t sw, uint32_t sh,
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ)
{
ATRACE_CALL();
@@ -2689,7 +2726,7 @@
// call the new screenshot taking code, passing a BufferQueue to it
status_t result = captureScreenImplLocked(hw,
- consumer->getBufferQueue(), sw, sh, minLayerZ, maxLayerZ);
+ consumer->getBufferQueue(), reqWidth, reqHeight, minLayerZ, maxLayerZ);
if (result == NO_ERROR) {
result = consumer->updateTexImage();
@@ -2701,31 +2738,64 @@
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
- sp<GraphicBuffer> buf(consumer->getCurrentBuffer());
- sw = buf->getWidth();
- sh = buf->getHeight();
- size_t size = sw * sh * 4;
+ reqWidth = consumer->getCurrentBuffer()->getWidth();
+ reqHeight = consumer->getCurrentBuffer()->getHeight();
- // allocate shared memory large enough to hold the
- // screen capture
- sp<MemoryHeapBase> base(
- new MemoryHeapBase(size, 0, "screen-capture") );
- void* const ptr = base->getBase();
- if (ptr != MAP_FAILED) {
- // capture the screen with glReadPixels()
- ScopedTrace _t(ATRACE_TAG, "glReadPixels");
- glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
- if (glGetError() == GL_NO_ERROR) {
- *heap = base;
- *w = sw;
- *h = sh;
- *f = PIXEL_FORMAT_RGBA_8888;
- result = NO_ERROR;
- } else {
- result = NO_MEMORY;
+ {
+ // in this block we render the screenshot into the
+ // CpuConsumer using glReadPixels from our GLConsumer,
+ // Some older drivers don't support the GL->CPU path so
+ // have to wrap it with a CPU->CPU path, which is what
+ // glReadPixels essentially is
+
+ sp<Surface> sur = new Surface(producer);
+ ANativeWindow* window = sur.get();
+ ANativeWindowBuffer* buffer;
+ void* vaddr;
+
+ if (native_window_api_connect(window,
+ NATIVE_WINDOW_API_CPU) == NO_ERROR) {
+ int err = 0;
+ err = native_window_set_buffers_dimensions(window,
+ reqWidth, reqHeight);
+ err |= native_window_set_buffers_format(window,
+ HAL_PIXEL_FORMAT_RGBA_8888);
+ err |= native_window_set_usage(window,
+ GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+
+ if (err == NO_ERROR) {
+ if (native_window_dequeue_buffer_and_wait(window,
+ &buffer) == NO_ERROR) {
+ sp<GraphicBuffer> buf =
+ static_cast<GraphicBuffer*>(buffer);
+ if (buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &vaddr) == NO_ERROR) {
+ if (buffer->stride != int(reqWidth)) {
+ // we're unlucky here, glReadPixels is
+ // not able to deal with a stride not
+ // equal to the width.
+ uint32_t* tmp = new uint32_t[reqWidth*reqHeight];
+ if (tmp != NULL) {
+ glReadPixels(0, 0, reqWidth, reqHeight,
+ GL_RGBA, GL_UNSIGNED_BYTE, tmp);
+ for (size_t y=0 ; y<reqHeight ; y++) {
+ memcpy((uint32_t*)vaddr + y*buffer->stride,
+ tmp + y*reqWidth, reqWidth*4);
+ }
+ delete [] tmp;
+ }
+ } else {
+ glReadPixels(0, 0, reqWidth, reqHeight,
+ GL_RGBA, GL_UNSIGNED_BYTE, vaddr);
+ }
+ buf->unlock();
+ }
+ window->queueBuffer(window, buffer, -1);
+ }
+ }
+ native_window_api_disconnect(window, NATIVE_WINDOW_API_CPU);
}
- } else {
- result = NO_MEMORY;
}
// back to main framebuffer
@@ -2742,63 +2812,6 @@
return result;
}
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
- sp<IMemoryHeap>* heap,
- uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
- uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
-{
- if (CC_UNLIKELY(display == 0))
- return BAD_VALUE;
-
- class MessageCaptureScreen : public MessageBase {
- SurfaceFlinger* flinger;
- sp<IBinder> display;
- sp<IMemoryHeap>* heap;
- uint32_t* outWidth;
- uint32_t* outHeight;
- PixelFormat* outFormat;
- uint32_t reqWidth;
- uint32_t reqHeight;
- uint32_t minLayerZ;
- uint32_t maxLayerZ;
- status_t result;
- public:
- MessageCaptureScreen(SurfaceFlinger* flinger,
- const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
- uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ)
- : flinger(flinger), display(display), heap(heap),
- outWidth(outWidth), outHeight(outHeight), outFormat(outFormat),
- reqWidth(reqWidth), reqHeight(reqHeight),
- minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
- result(PERMISSION_DENIED)
- {
- }
- status_t getResult() const {
- return result;
- }
- virtual bool handler() {
- Mutex::Autolock _l(flinger->mStateLock);
- sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
- result = flinger->captureScreenImplLocked(hw, heap,
- outWidth, outHeight, outFormat,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
- return true;
- }
- };
-
- sp<MessageBase> msg = new MessageCaptureScreen(this, display, heap,
- outWidth, outHeight, outFormat,
- reqWidth, reqHeight, minLayerZ, maxLayerZ);
- status_t res = postMessageSync(msg);
- if (res == NO_ERROR) {
- res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
- }
- return res;
-}
-
// ---------------------------------------------------------------------------
SurfaceFlinger::LayerVector::LayerVector() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e6734d2..1017560 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -185,14 +185,10 @@
virtual bool authenticateSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer) const;
virtual sp<IDisplayEventConnection> createDisplayEventConnection();
- virtual status_t captureScreen(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
- uint32_t maxLayerZ);
virtual status_t captureScreen(const sp<IBinder>& display,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
- uint32_t minLayerZ, uint32_t maxLayerZ);
+ uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer);
// called when screen needs to turn off
virtual void blank(const sp<IBinder>& display);
// called when screen is turning back on
@@ -297,17 +293,17 @@
status_t captureScreenImplLocked(
const sp<const DisplayDevice>& hw,
- sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format,
- uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
- uint32_t maxLayerZ);
+ const sp<IGraphicBufferProducer>& producer,
+ uint32_t reqWidth, uint32_t reqHeight,
+ uint32_t minLayerZ, uint32_t maxLayerZ);
- status_t captureScreenImplLocked(
+ status_t captureScreenImplCpuConsumerLocked(
const sp<const DisplayDevice>& hw,
const sp<IGraphicBufferProducer>& producer,
uint32_t reqWidth, uint32_t reqHeight,
uint32_t minLayerZ, uint32_t maxLayerZ);
+
/* ------------------------------------------------------------------------
* EGL
*/
@@ -416,12 +412,14 @@
HWComposer* mHwc;
GLuint mProtectedTexName;
nsecs_t mBootTime;
+ bool mGpuToCpuSupported;
sp<EventThread> mEventThread;
GLint mMaxViewportDims[2];
GLint mMaxTextureSize;
EGLContext mEGLContext;
EGLConfig mEGLConfig;
EGLDisplay mEGLDisplay;
+ EGLint mEGLNativeVisualId;
sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_DISPLAY_TYPES];
// Can only accessed from the main thread, these members