Merge "Add Hebrew bold and regular font files"
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
index 15a199f..67dd9f8 100644
--- a/cmds/keystore/Android.mk
+++ b/cmds/keystore/Android.mk
@@ -19,14 +19,14 @@
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := keystore.c
+LOCAL_SRC_FILES := keystore.cpp
 LOCAL_C_INCLUDES := external/openssl/include
 LOCAL_SHARED_LIBRARIES := libcutils libcrypto
 LOCAL_MODULE:= keystore
 include $(BUILD_EXECUTABLE)
 
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES := keystore_cli.c
+LOCAL_SRC_FILES := keystore_cli.cpp
 LOCAL_C_INCLUDES := external/openssl/include
 LOCAL_SHARED_LIBRARIES := libcutils libcrypto
 LOCAL_MODULE:= keystore_cli
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
deleted file mode 100644
index e34053b..0000000
--- a/cmds/keystore/keystore.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <arpa/inet.h>
-
-#include <openssl/aes.h>
-#include <openssl/evp.h>
-#include <openssl/md5.h>
-
-#define LOG_TAG "keystore"
-#include <cutils/log.h>
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
-
-#include "keystore.h"
-
-/* KeyStore is a secured storage for key-value pairs. In this implementation,
- * each file stores one key-value pair. Keys are encoded in file names, and
- * values are encrypted with checksums. The encryption key is protected by a
- * user-defined password. To keep things simple, buffers are always larger than
- * the maximum space we needed, so boundary checks on buffers are omitted. */
-
-#define KEY_SIZE        ((NAME_MAX - 15) / 2)
-#define VALUE_SIZE      32768
-#define PASSWORD_SIZE   VALUE_SIZE
-
-/* Here is the encoding of keys. This is necessary in order to allow arbitrary
- * characters in keys. Characters in [0-~] are not encoded. Others are encoded
- * into two bytes. The first byte is one of [+-.] which represents the first
- * two bits of the character. The second byte encodes the rest of the bits into
- * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
- * that Base64 cannot be used here due to the need of prefix match on keys. */
-
-static int encode_key(char *out, uint8_t *in, int length)
-{
-    int i;
-    for (i = length; i > 0; --i, ++in, ++out) {
-        if (*in >= '0' && *in <= '~') {
-            *out = *in;
-        } else {
-            *out = '+' + (*in >> 6);
-            *++out = '0' + (*in & 0x3F);
-            ++length;
-        }
-    }
-    *out = 0;
-    return length;
-}
-
-static int decode_key(uint8_t *out, char *in, int length)
-{
-    int i;
-    for (i = 0; i < length; ++i, ++in, ++out) {
-        if (*in >= '0' && *in <= '~') {
-            *out = *in;
-        } else {
-            *out = (*in - '+') << 6;
-            *out |= (*++in - '0') & 0x3F;
-            --length;
-        }
-    }
-    *out = 0;
-    return length;
-}
-
-/* Here is the protocol used in both requests and responses:
- *     code [length_1 message_1 ... length_n message_n] end-of-file
- * where code is one byte long and lengths are unsigned 16-bit integers in
- * network order. Thus the maximum length of a message is 65535 bytes. */
-
-static int the_socket = -1;
-
-static int recv_code(int8_t *code)
-{
-    return recv(the_socket, code, 1, 0) == 1;
-}
-
-static int recv_message(uint8_t *message, int length)
-{
-    uint8_t bytes[2];
-    if (recv(the_socket, &bytes[0], 1, 0) != 1 ||
-        recv(the_socket, &bytes[1], 1, 0) != 1) {
-        return -1;
-    } else {
-        int offset = bytes[0] << 8 | bytes[1];
-        if (length < offset) {
-            return -1;
-        }
-        length = offset;
-        offset = 0;
-        while (offset < length) {
-            int n = recv(the_socket, &message[offset], length - offset, 0);
-            if (n <= 0) {
-                return -1;
-            }
-            offset += n;
-        }
-    }
-    return length;
-}
-
-static int recv_end_of_file()
-{
-    uint8_t byte;
-    return recv(the_socket, &byte, 1, 0) == 0;
-}
-
-static void send_code(int8_t code)
-{
-    send(the_socket, &code, 1, 0);
-}
-
-static void send_message(uint8_t *message, int length)
-{
-    uint16_t bytes = htons(length);
-    send(the_socket, &bytes, 2, 0);
-    send(the_socket, message, length, 0);
-}
-
-/* Here is the file format. There are two parts in blob.value, the secret and
- * the description. The secret is stored in ciphertext, and its original size
- * can be found in blob.length. The description is stored after the secret in
- * plaintext, and its size is specified in blob.info. The total size of the two
- * parts must be no more than VALUE_SIZE bytes. The first three bytes of the
- * file are reserved for future use and are always set to zero. Fields other
- * than blob.info, blob.length, and blob.value are modified by encrypt_blob()
- * and decrypt_blob(). Thus they should not be accessed from outside. */
-
-static int the_entropy = -1;
-
-static struct __attribute__((packed)) {
-    uint8_t reserved[3];
-    uint8_t info;
-    uint8_t vector[AES_BLOCK_SIZE];
-    uint8_t encrypted[0];
-    uint8_t digest[MD5_DIGEST_LENGTH];
-    uint8_t digested[0];
-    int32_t length;
-    uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE];
-} blob;
-
-static int8_t encrypt_blob(char *name, AES_KEY *aes_key)
-{
-    uint8_t vector[AES_BLOCK_SIZE];
-    int length;
-    int fd;
-
-    if (read(the_entropy, blob.vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) {
-        return SYSTEM_ERROR;
-    }
-
-    length = blob.length + (blob.value - blob.encrypted);
-    length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
-
-    if (blob.info != 0) {
-        memmove(&blob.encrypted[length], &blob.value[blob.length], blob.info);
-    }
-
-    blob.length = htonl(blob.length);
-    MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest);
-
-    memcpy(vector, blob.vector, AES_BLOCK_SIZE);
-    AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector,
-                    AES_ENCRYPT);
-
-    memset(blob.reserved, 0, sizeof(blob.reserved));
-    length += (blob.encrypted - (uint8_t *)&blob) + blob.info;
-
-    fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
-    length -= write(fd, &blob, length);
-    close(fd);
-    return (length || rename(".tmp", name)) ? SYSTEM_ERROR : NO_ERROR;
-}
-
-static int8_t decrypt_blob(char *name, AES_KEY *aes_key)
-{
-    int fd = open(name, O_RDONLY);
-    int length;
-
-    if (fd == -1) {
-        return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR;
-    }
-    length = read(fd, &blob, sizeof(blob));
-    close(fd);
-
-    length -= (blob.encrypted - (uint8_t *)&blob) + blob.info;
-    if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) {
-        return VALUE_CORRUPTED;
-    }
-
-    AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key,
-                    blob.vector, AES_DECRYPT);
-    length -= blob.digested - blob.encrypted;
-    if (memcmp(blob.digest, MD5(blob.digested, length, NULL),
-               MD5_DIGEST_LENGTH)) {
-        return VALUE_CORRUPTED;
-    }
-
-    length -= blob.value - blob.digested;
-    blob.length = ntohl(blob.length);
-    if (blob.length < 0 || blob.length > length) {
-        return VALUE_CORRUPTED;
-    }
-    if (blob.info != 0) {
-        memmove(&blob.value[blob.length], &blob.value[length], blob.info);
-    }
-    return NO_ERROR;
-}
-
-/* Here are the actions. Each of them is a function without arguments. All
- * information is defined in global variables, which are set properly before
- * performing an action. The number of parameters required by each action is
- * fixed and defined in a table. If the return value of an action is positive,
- * it will be treated as a response code and transmitted to the client. Note
- * that the lengths of parameters are checked when they are received, so
- * boundary checks on parameters are omitted. */
-
-#define MAX_PARAM   2
-#define MAX_RETRY   4
-
-static uid_t uid = -1;
-static int8_t state = UNINITIALIZED;
-static int8_t retry = MAX_RETRY;
-
-static struct {
-    int length;
-    uint8_t value[VALUE_SIZE];
-} params[MAX_PARAM];
-
-static AES_KEY encryption_key;
-static AES_KEY decryption_key;
-
-static int8_t test()
-{
-    return state;
-}
-
-static int8_t get()
-{
-    char name[NAME_MAX];
-    int n = sprintf(name, "%u_", uid);
-    encode_key(&name[n], params[0].value, params[0].length);
-    n = decrypt_blob(name, &decryption_key);
-    if (n != NO_ERROR) {
-        return n;
-    }
-    send_code(NO_ERROR);
-    send_message(blob.value, blob.length);
-    return -NO_ERROR;
-}
-
-static int8_t insert()
-{
-    char name[NAME_MAX];
-    int n = sprintf(name, "%u_", uid);
-    encode_key(&name[n], params[0].value, params[0].length);
-    blob.info = 0;
-    blob.length = params[1].length;
-    memcpy(blob.value, params[1].value, params[1].length);
-    return encrypt_blob(name, &encryption_key);
-}
-
-static int8_t delete()
-{
-    char name[NAME_MAX];
-    int n = sprintf(name, "%u_", uid);
-    encode_key(&name[n], params[0].value, params[0].length);
-    return (unlink(name) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
-}
-
-static int8_t exist()
-{
-    char name[NAME_MAX];
-    int n = sprintf(name, "%u_", uid);
-    encode_key(&name[n], params[0].value, params[0].length);
-    if (access(name, R_OK) == -1) {
-        return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
-    }
-    return NO_ERROR;
-}
-
-static int8_t saw()
-{
-    DIR *dir = opendir(".");
-    struct dirent *file;
-    char name[NAME_MAX];
-    int n;
-
-    if (!dir) {
-        return SYSTEM_ERROR;
-    }
-    n = sprintf(name, "%u_", uid);
-    n += encode_key(&name[n], params[0].value, params[0].length);
-    send_code(NO_ERROR);
-    while ((file = readdir(dir)) != NULL) {
-        if (!strncmp(name, file->d_name, n)) {
-            char *p = &file->d_name[n];
-            params[0].length = decode_key(params[0].value, p, strlen(p));
-            send_message(params[0].value, params[0].length);
-        }
-    }
-    closedir(dir);
-    return -NO_ERROR;
-}
-
-static int8_t reset()
-{
-    DIR *dir = opendir(".");
-    struct dirent *file;
-
-    memset(&encryption_key, 0, sizeof(encryption_key));
-    memset(&decryption_key, 0, sizeof(decryption_key));
-    state = UNINITIALIZED;
-    retry = MAX_RETRY;
-
-    if (!dir) {
-        return SYSTEM_ERROR;
-    }
-    while ((file = readdir(dir)) != NULL) {
-        unlink(file->d_name);
-    }
-    closedir(dir);
-    return NO_ERROR;
-}
-
-#define MASTER_KEY_FILE ".masterkey"
-#define MASTER_KEY_SIZE 16
-#define SALT_SIZE       16
-
-static void set_key(uint8_t *key, uint8_t *password, int length, uint8_t *salt)
-{
-    if (salt) {
-        PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, salt, SALT_SIZE,
-                               8192, MASTER_KEY_SIZE, key);
-    } else {
-        PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
-                               sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
-    }
-}
-
-/* Here is the history. To improve the security, the parameters to generate the
- * master key has been changed. To make a seamless transition, we update the
- * file using the same password when the user unlock it for the first time. If
- * any thing goes wrong during the transition, the new file will not overwrite
- * the old one. This avoids permanent damages of the existing data. */
-
-static int8_t password()
-{
-    uint8_t key[MASTER_KEY_SIZE];
-    AES_KEY aes_key;
-    int8_t response = SYSTEM_ERROR;
-
-    if (state == UNINITIALIZED) {
-        if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) {
-           return SYSTEM_ERROR;
-        }
-    } else {
-        int fd = open(MASTER_KEY_FILE, O_RDONLY);
-        uint8_t *salt = NULL;
-        if (fd != -1) {
-            int length = read(fd, &blob, sizeof(blob));
-            close(fd);
-            if (length > SALT_SIZE && blob.info == SALT_SIZE) {
-                salt = (uint8_t *)&blob + length - SALT_SIZE;
-            }
-        }
-
-        set_key(key, params[0].value, params[0].length, salt);
-        AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
-        response = decrypt_blob(MASTER_KEY_FILE, &aes_key);
-        if (response == SYSTEM_ERROR) {
-            return SYSTEM_ERROR;
-        }
-        if (response != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
-            if (retry <= 0) {
-                reset();
-                return UNINITIALIZED;
-            }
-            return WRONG_PASSWORD + --retry;
-        }
-
-        if (!salt && params[1].length == -1) {
-            params[1] = params[0];
-        }
-    }
-
-    if (params[1].length == -1) {
-        memcpy(key, blob.value, MASTER_KEY_SIZE);
-    } else {
-        uint8_t *salt = &blob.value[MASTER_KEY_SIZE];
-        if (read(the_entropy, salt, SALT_SIZE) != SALT_SIZE) {
-            return SYSTEM_ERROR;
-        }
-
-        set_key(key, params[1].value, params[1].length, salt);
-        AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
-        memcpy(key, blob.value, MASTER_KEY_SIZE);
-        blob.info = SALT_SIZE;
-        blob.length = MASTER_KEY_SIZE;
-        response = encrypt_blob(MASTER_KEY_FILE, &aes_key);
-    }
-
-    if (response == NO_ERROR) {
-        AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key);
-        AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key);
-        state = NO_ERROR;
-        retry = MAX_RETRY;
-    }
-    return response;
-}
-
-static int8_t lock()
-{
-    memset(&encryption_key, 0, sizeof(encryption_key));
-    memset(&decryption_key, 0, sizeof(decryption_key));
-    state = LOCKED;
-    return NO_ERROR;
-}
-
-static int8_t unlock()
-{
-    params[1].length = -1;
-    return password();
-}
-
-/* Here are the permissions, actions, users, and the main function. */
-
-enum perm {
-    TEST     =   1,
-    GET      =   2,
-    INSERT   =   4,
-    DELETE   =   8,
-    EXIST    =  16,
-    SAW      =  32,
-    RESET    =  64,
-    PASSWORD = 128,
-    LOCK     = 256,
-    UNLOCK   = 512,
-};
-
-static struct action {
-    int8_t (*run)();
-    int8_t code;
-    int8_t state;
-    uint32_t perm;
-    int lengths[MAX_PARAM];
-} actions[] = {
-    {test,     't', 0,        TEST,     {0}},
-    {get,      'g', NO_ERROR, GET,      {KEY_SIZE}},
-    {insert,   'i', NO_ERROR, INSERT,   {KEY_SIZE, VALUE_SIZE}},
-    {delete,   'd', 0,        DELETE,   {KEY_SIZE}},
-    {exist,    'e', 0,        EXIST,    {KEY_SIZE}},
-    {saw,      's', 0,        SAW,      {KEY_SIZE}},
-    {reset,    'r', 0,        RESET,    {0}},
-    {password, 'p', 0,        PASSWORD, {PASSWORD_SIZE, PASSWORD_SIZE}},
-    {lock,     'l', NO_ERROR, LOCK,     {0}},
-    {unlock,   'u', LOCKED,   UNLOCK,   {PASSWORD_SIZE}},
-    {NULL,      0 , 0,        0,        {0}},
-};
-
-static struct user {
-    uid_t uid;
-    uid_t euid;
-    uint32_t perms;
-} users[] = {
-    {AID_SYSTEM,   ~0,         ~GET},
-    {AID_VPN,      AID_SYSTEM, GET},
-    {AID_WIFI,     AID_SYSTEM, GET},
-    {AID_ROOT,     AID_SYSTEM, GET},
-    {AID_KEYCHAIN, AID_SYSTEM, TEST | GET | SAW},
-    {~0,           ~0,         TEST | GET | INSERT | DELETE | EXIST | SAW},
-};
-
-static int8_t process(int8_t code) {
-    struct user *user = users;
-    struct action *action = actions;
-    int i;
-
-    while (~user->uid && user->uid != uid) {
-        ++user;
-    }
-    while (action->code && action->code != code) {
-        ++action;
-    }
-    if (!action->code) {
-        return UNDEFINED_ACTION;
-    }
-    if (!(action->perm & user->perms)) {
-        return PERMISSION_DENIED;
-    }
-    if (action->state && action->state != state) {
-        return state;
-    }
-    if (~user->euid) {
-        uid = user->euid;
-    }
-    for (i = 0; i < MAX_PARAM && action->lengths[i]; ++i) {
-        params[i].length = recv_message(params[i].value, action->lengths[i]);
-        if (params[i].length == -1) {
-            return PROTOCOL_ERROR;
-        }
-    }
-    if (!recv_end_of_file()) {
-        return PROTOCOL_ERROR;
-    }
-    return action->run();
-}
-
-#define RANDOM_DEVICE   "/dev/urandom"
-
-int main(int argc, char **argv)
-{
-    int control_socket = android_get_control_socket("keystore");
-    if (argc < 2) {
-        LOGE("A directory must be specified!");
-        return 1;
-    }
-    if (chdir(argv[1]) == -1) {
-        LOGE("chdir: %s: %s", argv[1], strerror(errno));
-        return 1;
-    }
-    if ((the_entropy = open(RANDOM_DEVICE, O_RDONLY)) == -1) {
-        LOGE("open: %s: %s", RANDOM_DEVICE, strerror(errno));
-        return 1;
-    }
-    if (listen(control_socket, 3) == -1) {
-        LOGE("listen: %s", strerror(errno));
-        return 1;
-    }
-
-    signal(SIGPIPE, SIG_IGN);
-    if (access(MASTER_KEY_FILE, R_OK) == 0) {
-        state = LOCKED;
-    }
-
-    while ((the_socket = accept(control_socket, NULL, 0)) != -1) {
-        struct timeval tv = {.tv_sec = 3};
-        struct ucred cred;
-        socklen_t size = sizeof(cred);
-        int8_t request;
-
-        setsockopt(the_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
-        setsockopt(the_socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-
-        if (getsockopt(the_socket, SOL_SOCKET, SO_PEERCRED, &cred, &size)) {
-            LOGW("getsockopt: %s", strerror(errno));
-        } else if (recv_code(&request)) {
-            int8_t old_state = state;
-            int8_t response;
-            uid = cred.uid;
-
-            if ((response = process(request)) > 0) {
-                send_code(response);
-                response = -response;
-            }
-
-            LOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d",
-                 cred.uid, request, -response, old_state, state, retry);
-        }
-        close(the_socket);
-    }
-    LOGE("accept: %s", strerror(errno));
-    return 1;
-}
diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp
new file mode 100644
index 0000000..1c1f37a
--- /dev/null
+++ b/cmds/keystore/keystore.cpp
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+#define LOG_TAG "keystore"
+#include <cutils/log.h>
+#include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
+
+#include "keystore.h"
+
+/* KeyStore is a secured storage for key-value pairs. In this implementation,
+ * each file stores one key-value pair. Keys are encoded in file names, and
+ * values are encrypted with checksums. The encryption key is protected by a
+ * user-defined password. To keep things simple, buffers are always larger than
+ * the maximum space we needed, so boundary checks on buffers are omitted. */
+
+#define KEY_SIZE        ((NAME_MAX - 15) / 2)
+#define VALUE_SIZE      32768
+#define PASSWORD_SIZE   VALUE_SIZE
+
+struct Value {
+    int length;
+    uint8_t value[VALUE_SIZE];
+};
+
+/* Here is the encoding of keys. This is necessary in order to allow arbitrary
+ * characters in keys. Characters in [0-~] are not encoded. Others are encoded
+ * into two bytes. The first byte is one of [+-.] which represents the first
+ * two bits of the character. The second byte encodes the rest of the bits into
+ * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
+ * that Base64 cannot be used here due to the need of prefix match on keys. */
+
+static int encode_key(char* out, uid_t uid, const Value* key) {
+    int n = snprintf(out, NAME_MAX, "%u_", uid);
+    out += n;
+    const uint8_t* in = key->value;
+    int length = key->length;
+    for (int i = length; i > 0; --i, ++in, ++out) {
+        if (*in >= '0' && *in <= '~') {
+            *out = *in;
+        } else {
+            *out = '+' + (*in >> 6);
+            *++out = '0' + (*in & 0x3F);
+            ++length;
+        }
+    }
+    *out = '\0';
+    return n + length;
+}
+
+static int decode_key(uint8_t* out, char* in, int length) {
+    for (int i = 0; i < length; ++i, ++in, ++out) {
+        if (*in >= '0' && *in <= '~') {
+            *out = *in;
+        } else {
+            *out = (*in - '+') << 6;
+            *out |= (*++in - '0') & 0x3F;
+            --length;
+        }
+    }
+    *out = '\0';
+    return length;
+}
+
+static size_t readFully(int fd, uint8_t* data, size_t size) {
+    size_t remaining = size;
+    while (remaining > 0) {
+        ssize_t n = TEMP_FAILURE_RETRY(read(fd, data, size));
+        if (n == -1 || n == 0) {
+            return size-remaining;
+        }
+        data += n;
+        remaining -= n;
+    }
+    return size;
+}
+
+static size_t writeFully(int fd, uint8_t* data, size_t size) {
+    size_t remaining = size;
+    while (remaining > 0) {
+        ssize_t n = TEMP_FAILURE_RETRY(write(fd, data, size));
+        if (n == -1 || n == 0) {
+            return size-remaining;
+        }
+        data += n;
+        remaining -= n;
+    }
+    return size;
+}
+
+class Entropy {
+public:
+    Entropy() : mRandom(-1) {}
+    ~Entropy() {
+        if (mRandom != -1) {
+            close(mRandom);
+        }
+    }
+
+    bool open() {
+        const char* randomDevice = "/dev/urandom";
+        mRandom = ::open(randomDevice, O_RDONLY);
+        if (mRandom == -1) {
+            LOGE("open: %s: %s", randomDevice, strerror(errno));
+            return false;
+        }
+        return true;
+    }
+
+    bool generate_random_data(uint8_t* data, size_t size) {
+        return (readFully(mRandom, data, size) == size);
+    }
+
+private:
+    int mRandom;
+};
+
+/* Here is the file format. There are two parts in blob.value, the secret and
+ * the description. The secret is stored in ciphertext, and its original size
+ * can be found in blob.length. The description is stored after the secret in
+ * plaintext, and its size is specified in blob.info. The total size of the two
+ * parts must be no more than VALUE_SIZE bytes. The first three bytes of the
+ * file are reserved for future use and are always set to zero. Fields other
+ * than blob.info, blob.length, and blob.value are modified by encryptBlob()
+ * and decryptBlob(). Thus they should not be accessed from outside. */
+
+struct __attribute__((packed)) blob {
+    uint8_t reserved[3];
+    uint8_t info;
+    uint8_t vector[AES_BLOCK_SIZE];
+    uint8_t encrypted[0];
+    uint8_t digest[MD5_DIGEST_LENGTH];
+    uint8_t digested[0];
+    int32_t length; // in network byte order when encrypted
+    uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE];
+};
+
+class Blob {
+public:
+    Blob(uint8_t* value, int32_t valueLength, uint8_t* info, uint8_t infoLength) {
+        mBlob.length = valueLength;
+        memcpy(mBlob.value, value, valueLength);
+
+        mBlob.info = infoLength;
+        memcpy(mBlob.value + valueLength, info, infoLength);
+    }
+
+    Blob(blob b) {
+        mBlob = b;
+    }
+
+    Blob() {}
+
+    uint8_t* getValue() {
+        return mBlob.value;
+    }
+
+    int32_t getLength() {
+        return mBlob.length;
+    }
+
+    uint8_t getInfo() {
+        return mBlob.info;
+    }
+
+    ResponseCode encryptBlob(const char* filename, AES_KEY *aes_key, Entropy* entropy) {
+        if (!entropy->generate_random_data(mBlob.vector, AES_BLOCK_SIZE)) {
+            return SYSTEM_ERROR;
+        }
+
+        // data includes the value and the value's length
+        size_t dataLength = mBlob.length + sizeof(mBlob.length);
+        // pad data to the AES_BLOCK_SIZE
+        size_t digestedLength = ((dataLength + AES_BLOCK_SIZE - 1)
+                                 / AES_BLOCK_SIZE * AES_BLOCK_SIZE);
+        // encrypted data includes the digest value
+        size_t encryptedLength = digestedLength + MD5_DIGEST_LENGTH;
+        // move info after space for padding
+        memmove(&mBlob.encrypted[encryptedLength], &mBlob.value[mBlob.length], mBlob.info);
+        // zero padding area
+        memset(mBlob.value + mBlob.length, 0, digestedLength - dataLength);
+
+        mBlob.length = htonl(mBlob.length);
+        MD5(mBlob.digested, digestedLength, mBlob.digest);
+
+        uint8_t vector[AES_BLOCK_SIZE];
+        memcpy(vector, mBlob.vector, AES_BLOCK_SIZE);
+        AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength,
+                        aes_key, vector, AES_ENCRYPT);
+
+        memset(mBlob.reserved, 0, sizeof(mBlob.reserved));
+        size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob);
+        size_t fileLength = encryptedLength + headerLength + mBlob.info;
+
+        const char* tmpFileName = ".tmp";
+        int out = open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+        if (out == -1) {
+            return SYSTEM_ERROR;
+        }
+        size_t writtenBytes = writeFully(out, (uint8_t*) &mBlob, fileLength);
+        if (close(out) != 0) {
+            return SYSTEM_ERROR;
+        }
+        if (writtenBytes != fileLength) {
+            unlink(tmpFileName);
+            return SYSTEM_ERROR;
+        }
+        return (rename(tmpFileName, filename) == 0) ? NO_ERROR : SYSTEM_ERROR;
+    }
+
+    ResponseCode decryptBlob(const char* filename, AES_KEY *aes_key) {
+        int in = open(filename, O_RDONLY);
+        if (in == -1) {
+            return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR;
+        }
+        // fileLength may be less than sizeof(mBlob) since the in
+        // memory version has extra padding to tolerate rounding up to
+        // the AES_BLOCK_SIZE
+        size_t fileLength = readFully(in, (uint8_t*) &mBlob, sizeof(mBlob));
+        if (close(in) != 0) {
+            return SYSTEM_ERROR;
+        }
+        size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob);
+        if (fileLength < headerLength) {
+            return VALUE_CORRUPTED;
+        }
+
+        ssize_t encryptedLength = fileLength - (headerLength + mBlob.info);
+        if (encryptedLength < 0 || encryptedLength % AES_BLOCK_SIZE != 0) {
+            return VALUE_CORRUPTED;
+        }
+        AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, aes_key,
+                        mBlob.vector, AES_DECRYPT);
+        size_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
+        uint8_t computedDigest[MD5_DIGEST_LENGTH];
+        MD5(mBlob.digested, digestedLength, computedDigest);
+        if (memcmp(mBlob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
+            return VALUE_CORRUPTED;
+        }
+
+        ssize_t maxValueLength = digestedLength - sizeof(mBlob.length);
+        mBlob.length = ntohl(mBlob.length);
+        if (mBlob.length < 0 || mBlob.length > maxValueLength) {
+            return VALUE_CORRUPTED;
+        }
+        if (mBlob.info != 0) {
+            // move info from after padding to after data
+            memmove(&mBlob.value[mBlob.length], &mBlob.value[maxValueLength], mBlob.info);
+        }
+        return NO_ERROR;
+    }
+
+private:
+    struct blob mBlob;
+};
+
+class KeyStore {
+public:
+    KeyStore(Entropy* entropy) : mEntropy(entropy), mRetry(MAX_RETRY) {
+        if (access(MASTER_KEY_FILE, R_OK) == 0) {
+            setState(STATE_LOCKED);
+        } else {
+            setState(STATE_UNINITIALIZED);
+        }
+    }
+
+    State getState() {
+        return mState;
+    }
+
+    int8_t getRetry() {
+        return mRetry;
+    }
+
+    ResponseCode initialize(Value* pw) {
+        if (!generateMasterKey()) {
+            return SYSTEM_ERROR;
+        }
+        ResponseCode response = writeMasterKey(pw);
+        if (response != NO_ERROR) {
+            return response;
+        }
+        setupMasterKeys();
+        return NO_ERROR;
+    }
+
+    ResponseCode writeMasterKey(Value* pw) {
+        uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
+        generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
+        AES_KEY passwordAesKey;
+        AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
+        Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt));
+        return masterKeyBlob.encryptBlob(MASTER_KEY_FILE, &passwordAesKey, mEntropy);
+    }
+
+    ResponseCode readMasterKey(Value* pw) {
+        int in = open(MASTER_KEY_FILE, O_RDONLY);
+        if (in == -1) {
+            return SYSTEM_ERROR;
+        }
+
+        // we read the raw blob to just to get the salt to generate
+        // the AES key, then we create the Blob to use with decryptBlob
+        blob rawBlob;
+        size_t length = readFully(in, (uint8_t*) &rawBlob, sizeof(rawBlob));
+        if (close(in) != 0) {
+            return SYSTEM_ERROR;
+        }
+        // find salt at EOF if present, otherwise we have an old file
+        uint8_t* salt;
+        if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
+            salt = (uint8_t*) &rawBlob + length - SALT_SIZE;
+        } else {
+            salt = NULL;
+        }
+        uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
+        generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt);
+        AES_KEY passwordAesKey;
+        AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
+        Blob masterKeyBlob(rawBlob);
+        ResponseCode response = masterKeyBlob.decryptBlob(MASTER_KEY_FILE, &passwordAesKey);
+        if (response == SYSTEM_ERROR) {
+            return SYSTEM_ERROR;
+        }
+        if (response == NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
+            // if salt was missing, generate one and write a new master key file with the salt.
+            if (salt == NULL) {
+                if (!generateSalt()) {
+                    return SYSTEM_ERROR;
+                }
+                response = writeMasterKey(pw);
+            }
+            if (response == NO_ERROR) {
+                memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
+                setupMasterKeys();
+            }
+            return response;
+        }
+        if (mRetry <= 0) {
+            reset();
+            return UNINITIALIZED;
+        }
+        --mRetry;
+        switch (mRetry) {
+            case 0: return WRONG_PASSWORD_0;
+            case 1: return WRONG_PASSWORD_1;
+            case 2: return WRONG_PASSWORD_2;
+            case 3: return WRONG_PASSWORD_3;
+            default: return WRONG_PASSWORD_3;
+        }
+    }
+
+    bool reset() {
+        clearMasterKeys();
+        setState(STATE_UNINITIALIZED);
+
+        DIR* dir = opendir(".");
+        struct dirent* file;
+
+        if (!dir) {
+            return false;
+        }
+        while ((file = readdir(dir)) != NULL) {
+            unlink(file->d_name);
+        }
+        closedir(dir);
+        return true;
+    }
+
+    bool isEmpty() {
+        DIR* dir = opendir(".");
+        struct dirent* file;
+        if (!dir) {
+            return true;
+        }
+        bool result = true;
+        while ((file = readdir(dir)) != NULL) {
+            if (isKeyFile(file->d_name)) {
+                result = false;
+                break;
+            }
+        }
+        closedir(dir);
+        return result;
+    }
+
+    void lock() {
+        clearMasterKeys();
+        setState(STATE_LOCKED);
+    }
+
+    ResponseCode get(const char* filename, Blob* keyBlob) {
+        return keyBlob->decryptBlob(filename, &mMasterKeyDecryption);
+    }
+
+    ResponseCode put(const char* filename, Blob* keyBlob) {
+        return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy);
+    }
+
+private:
+    static const char* MASTER_KEY_FILE;
+    static const int MASTER_KEY_SIZE_BYTES = 16;
+    static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
+
+    static const int MAX_RETRY = 4;
+    static const size_t SALT_SIZE = 16;
+
+    Entropy* mEntropy;
+
+    State mState;
+    int8_t mRetry;
+
+    uint8_t mMasterKey[MASTER_KEY_SIZE_BYTES];
+    uint8_t mSalt[SALT_SIZE];
+
+    AES_KEY mMasterKeyEncryption;
+    AES_KEY mMasterKeyDecryption;
+
+    void setState(State state) {
+        mState = state;
+        if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
+            mRetry = MAX_RETRY;
+        }
+    }
+
+    bool generateSalt() {
+        return mEntropy->generate_random_data(mSalt, sizeof(mSalt));
+    }
+
+    bool generateMasterKey() {
+        if (!mEntropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) {
+            return false;
+        }
+        if (!generateSalt()) {
+            return false;
+        }
+        return true;
+    }
+
+    void setupMasterKeys() {
+        AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption);
+        AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption);
+        setState(STATE_NO_ERROR);
+    }
+
+    void clearMasterKeys() {
+        memset(mMasterKey, 0, sizeof(mMasterKey));
+        memset(mSalt, 0, sizeof(mSalt));
+        memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption));
+        memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
+    }
+
+    static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, Value* pw, uint8_t* salt) {
+        size_t saltSize;
+        if (salt != NULL) {
+            saltSize = SALT_SIZE;
+        } else {
+            // pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
+            salt = (uint8_t*) "keystore";
+            // sizeof = 9, not strlen = 8
+            saltSize = sizeof("keystore");
+        }
+        PKCS5_PBKDF2_HMAC_SHA1((char*) pw->value, pw->length, salt, saltSize, 8192, keySize, key);
+    }
+
+    static bool isKeyFile(const char* filename) {
+        return ((strcmp(filename, MASTER_KEY_FILE) != 0)
+                && (strcmp(filename, ".") != 0)
+                && (strcmp(filename, "..") != 0));
+    }
+};
+
+const char* KeyStore::MASTER_KEY_FILE = ".masterkey";
+
+/* Here is the protocol used in both requests and responses:
+ *     code [length_1 message_1 ... length_n message_n] end-of-file
+ * where code is one byte long and lengths are unsigned 16-bit integers in
+ * network order. Thus the maximum length of a message is 65535 bytes. */
+
+static int recv_code(int sock, int8_t* code) {
+    return recv(sock, code, 1, 0) == 1;
+}
+
+static int recv_message(int sock, uint8_t* message, int length) {
+    uint8_t bytes[2];
+    if (recv(sock, &bytes[0], 1, 0) != 1 ||
+        recv(sock, &bytes[1], 1, 0) != 1) {
+        return -1;
+    } else {
+        int offset = bytes[0] << 8 | bytes[1];
+        if (length < offset) {
+            return -1;
+        }
+        length = offset;
+        offset = 0;
+        while (offset < length) {
+            int n = recv(sock, &message[offset], length - offset, 0);
+            if (n <= 0) {
+                return -1;
+            }
+            offset += n;
+        }
+    }
+    return length;
+}
+
+static int recv_end_of_file(int sock) {
+    uint8_t byte;
+    return recv(sock, &byte, 1, 0) == 0;
+}
+
+static void send_code(int sock, int8_t code) {
+    send(sock, &code, 1, 0);
+}
+
+static void send_message(int sock, uint8_t* message, int length) {
+    uint16_t bytes = htons(length);
+    send(sock, &bytes, 2, 0);
+    send(sock, message, length, 0);
+}
+
+/* Here are the actions. Each of them is a function without arguments. All
+ * information is defined in global variables, which are set properly before
+ * performing an action. The number of parameters required by each action is
+ * fixed and defined in a table. If the return value of an action is positive,
+ * it will be treated as a response code and transmitted to the client. Note
+ * that the lengths of parameters are checked when they are received, so
+ * boundary checks on parameters are omitted. */
+
+static const ResponseCode NO_ERROR_RESPONSE_CODE_SENT = (ResponseCode) 0;
+
+static ResponseCode test(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
+    return (ResponseCode) keyStore->getState();
+}
+
+static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) {
+    char filename[NAME_MAX];
+    encode_key(filename, uid, keyName);
+    Blob keyBlob;
+    ResponseCode responseCode = keyStore->get(filename, &keyBlob);
+    if (responseCode != NO_ERROR) {
+        return responseCode;
+    }
+    send_code(sock, NO_ERROR);
+    send_message(sock, keyBlob.getValue(), keyBlob.getLength());
+    return NO_ERROR_RESPONSE_CODE_SENT;
+}
+
+static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val) {
+    char filename[NAME_MAX];
+    encode_key(filename, uid, keyName);
+    Blob keyBlob(val->value, val->length, 0, NULL);
+    return keyStore->put(filename, &keyBlob);
+}
+
+static ResponseCode del(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) {
+    char filename[NAME_MAX];
+    encode_key(filename, uid, keyName);
+    return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
+}
+
+static ResponseCode exist(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) {
+    char filename[NAME_MAX];
+    encode_key(filename, uid, keyName);
+    if (access(filename, R_OK) == -1) {
+        return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
+static ResponseCode saw(KeyStore* keyStore, int sock, uid_t uid, Value* keyPrefix, Value*) {
+    DIR* dir = opendir(".");
+    if (!dir) {
+        return SYSTEM_ERROR;
+    }
+    char filename[NAME_MAX];
+    int n = encode_key(filename, uid, keyPrefix);
+    send_code(sock, NO_ERROR);
+
+    struct dirent* file;
+    while ((file = readdir(dir)) != NULL) {
+        if (!strncmp(filename, file->d_name, n)) {
+            char* p = &file->d_name[n];
+            keyPrefix->length = decode_key(keyPrefix->value, p, strlen(p));
+            send_message(sock, keyPrefix->value, keyPrefix->length);
+        }
+    }
+    closedir(dir);
+    return NO_ERROR_RESPONSE_CODE_SENT;
+}
+
+static ResponseCode reset(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
+    return keyStore->reset() ? NO_ERROR : SYSTEM_ERROR;
+}
+
+/* Here is the history. To improve the security, the parameters to generate the
+ * master key has been changed. To make a seamless transition, we update the
+ * file using the same password when the user unlock it for the first time. If
+ * any thing goes wrong during the transition, the new file will not overwrite
+ * the old one. This avoids permanent damages of the existing data. */
+
+static ResponseCode password(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value*) {
+    switch (keyStore->getState()) {
+        case STATE_UNINITIALIZED: {
+            // generate master key, encrypt with password, write to file, initialize mMasterKey*.
+            return keyStore->initialize(pw);
+        }
+        case STATE_NO_ERROR: {
+            // rewrite master key with new password.
+            return keyStore->writeMasterKey(pw);
+        }
+        case STATE_LOCKED: {
+            // read master key, decrypt with password, initialize mMasterKey*.
+            return keyStore->readMasterKey(pw);
+        }
+    }
+    return SYSTEM_ERROR;
+}
+
+static ResponseCode lock(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
+    keyStore->lock();
+    return NO_ERROR;
+}
+
+static ResponseCode unlock(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value* unused) {
+    return password(keyStore, sock, uid, pw, unused);
+}
+
+static ResponseCode zero(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) {
+    return keyStore->isEmpty() ? KEY_NOT_FOUND : NO_ERROR;
+}
+
+/* Here are the permissions, actions, users, and the main function. */
+
+enum perm {
+    TEST     =    1,
+    GET      =    2,
+    INSERT   =    4,
+    DELETE   =    8,
+    EXIST    =   16,
+    SAW      =   32,
+    RESET    =   64,
+    PASSWORD =  128,
+    LOCK     =  256,
+    UNLOCK   =  512,
+    ZERO     = 1024,
+};
+
+static const int MAX_PARAM = 2;
+
+static const State STATE_ANY = (State) 0;
+
+static struct action {
+    ResponseCode (*run)(KeyStore* keyStore, int sock, uid_t uid, Value* param1, Value* param2);
+    int8_t code;
+    State state;
+    uint32_t perm;
+    int lengths[MAX_PARAM];
+} actions[] = {
+    {test,     't', STATE_ANY,      TEST,     {0, 0}},
+    {get,      'g', STATE_NO_ERROR, GET,      {KEY_SIZE, 0}},
+    {insert,   'i', STATE_NO_ERROR, INSERT,   {KEY_SIZE, VALUE_SIZE}},
+    {del,      'd', STATE_ANY,      DELETE,   {KEY_SIZE, 0}},
+    {exist,    'e', STATE_ANY,      EXIST,    {KEY_SIZE, 0}},
+    {saw,      's', STATE_ANY,      SAW,      {KEY_SIZE, 0}},
+    {reset,    'r', STATE_ANY,      RESET,    {0, 0}},
+    {password, 'p', STATE_ANY,      PASSWORD, {PASSWORD_SIZE, 0}},
+    {lock,     'l', STATE_NO_ERROR, LOCK,     {0, 0}},
+    {unlock,   'u', STATE_LOCKED,   UNLOCK,   {PASSWORD_SIZE, 0}},
+    {zero,     'z', STATE_ANY,      ZERO,     {0, 0}},
+    {NULL,      0 , STATE_ANY,      0,        {0, 0}},
+};
+
+static struct user {
+    uid_t uid;
+    uid_t euid;
+    uint32_t perms;
+} users[] = {
+    {AID_SYSTEM,   ~0,         ~0},
+    {AID_VPN,      AID_SYSTEM, GET},
+    {AID_WIFI,     AID_SYSTEM, GET},
+    {AID_ROOT,     AID_SYSTEM, GET},
+    {AID_KEYCHAIN, AID_SYSTEM, TEST | GET | SAW},
+    {~0,           ~0,         TEST | GET | INSERT | DELETE | EXIST | SAW},
+};
+
+static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code) {
+    struct user* user = users;
+    struct action* action = actions;
+    int i;
+
+    while (~user->uid && user->uid != uid) {
+        ++user;
+    }
+    while (action->code && action->code != code) {
+        ++action;
+    }
+    if (!action->code) {
+        return UNDEFINED_ACTION;
+    }
+    if (!(action->perm & user->perms)) {
+        return PERMISSION_DENIED;
+    }
+    if (action->state != STATE_ANY && action->state != keyStore->getState()) {
+        return (ResponseCode) keyStore->getState();
+    }
+    if (~user->euid) {
+        uid = user->euid;
+    }
+    Value params[MAX_PARAM];
+    for (i = 0; i < MAX_PARAM && action->lengths[i] != 0; ++i) {
+        params[i].length = recv_message(sock, params[i].value, action->lengths[i]);
+        if (params[i].length < 0) {
+            return PROTOCOL_ERROR;
+        }
+    }
+    if (!recv_end_of_file(sock)) {
+        return PROTOCOL_ERROR;
+    }
+    return action->run(keyStore, sock, uid, &params[0], &params[1]);
+}
+
+int main(int argc, char* argv[]) {
+    int controlSocket = android_get_control_socket("keystore");
+    if (argc < 2) {
+        LOGE("A directory must be specified!");
+        return 1;
+    }
+    if (chdir(argv[1]) == -1) {
+        LOGE("chdir: %s: %s", argv[1], strerror(errno));
+        return 1;
+    }
+
+    Entropy entropy;
+    if (!entropy.open()) {
+        return 1;
+    }
+    if (listen(controlSocket, 3) == -1) {
+        LOGE("listen: %s", strerror(errno));
+        return 1;
+    }
+
+    signal(SIGPIPE, SIG_IGN);
+
+    KeyStore keyStore(&entropy);
+    int sock;
+    while ((sock = accept(controlSocket, NULL, 0)) != -1) {
+        struct timeval tv;
+        tv.tv_sec = 3;
+        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+        setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+
+        struct ucred cred;
+        socklen_t size = sizeof(cred);
+        int credResult = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &size);
+        if (credResult != 0) {
+            LOGW("getsockopt: %s", strerror(errno));
+        } else {
+            int8_t request;
+            if (recv_code(sock, &request)) {
+                State old_state = keyStore.getState();
+                ResponseCode response = process(&keyStore, sock, cred.uid, request);
+                if (response == NO_ERROR_RESPONSE_CODE_SENT) {
+                    response = NO_ERROR;
+                } else {
+                    send_code(sock, response);
+                }
+                LOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d",
+                     cred.uid,
+                     request, response,
+                     old_state, keyStore.getState(),
+                     keyStore.getRetry());
+            }
+        }
+        close(sock);
+    }
+    LOGE("accept: %s", strerror(errno));
+    return 1;
+}
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
index 5ef51e9..5ae3d24 100644
--- a/cmds/keystore/keystore.h
+++ b/cmds/keystore/keystore.h
@@ -17,17 +17,27 @@
 #ifndef __KEYSTORE_H__
 #define __KEYSTORE_H__
 
-enum response_code {
-    NO_ERROR          =  1,
-    LOCKED            =  2,
-    UNINITIALIZED     =  3,
+// note state values overlap with ResponseCode for the purposes of the state() API
+enum State {
+    STATE_NO_ERROR      = 1,
+    STATE_LOCKED        = 2,
+    STATE_UNINITIALIZED = 3,
+};
+
+enum ResponseCode {
+    NO_ERROR          =  STATE_NO_ERROR, // 1
+    LOCKED            =  STATE_LOCKED, // 2
+    UNINITIALIZED     =  STATE_UNINITIALIZED, // 3
     SYSTEM_ERROR      =  4,
     PROTOCOL_ERROR    =  5,
     PERMISSION_DENIED =  6,
     KEY_NOT_FOUND     =  7,
     VALUE_CORRUPTED   =  8,
     UNDEFINED_ACTION  =  9,
-    WRONG_PASSWORD    = 10,
+    WRONG_PASSWORD_0  = 10,
+    WRONG_PASSWORD_1  = 11,
+    WRONG_PASSWORD_2  = 12,
+    WRONG_PASSWORD_3  = 13, // MAX_RETRY = 4
 };
 
 #endif
diff --git a/cmds/keystore/keystore_cli.c b/cmds/keystore/keystore_cli.cpp
similarity index 67%
rename from cmds/keystore/keystore_cli.c
rename to cmds/keystore/keystore_cli.cpp
index e8afb5a..dcd3bcb 100644
--- a/cmds/keystore/keystore_cli.c
+++ b/cmds/keystore/keystore_cli.cpp
@@ -24,44 +24,40 @@
 
 #include "keystore.h"
 
-char *responses[256] = {
-    [NO_ERROR]           = "No error",
-    [LOCKED]             = "Locked",
-    [UNINITIALIZED]      = "Uninitialized",
-    [SYSTEM_ERROR]       = "System error",
-    [PROTOCOL_ERROR]     = "Protocol error",
-    [PERMISSION_DENIED]  = "Permission denied",
-    [KEY_NOT_FOUND]      = "Key not found",
-    [VALUE_CORRUPTED]    = "Value corrupted",
-    [UNDEFINED_ACTION]   = "Undefined action",
-    [WRONG_PASSWORD]     = "Wrong password (last chance)",
-    [WRONG_PASSWORD + 1] = "Wrong password (2 tries left)",
-    [WRONG_PASSWORD + 2] = "Wrong password (3 tries left)",
-    [WRONG_PASSWORD + 3] = "Wrong password (4 tries left)",
+static const char* responses[] = {
+    NULL,
+    /* [NO_ERROR]           = */ "No error",
+    /* [LOCKED]             = */ "Locked",
+    /* [UNINITIALIZED]      = */ "Uninitialized",
+    /* [SYSTEM_ERROR]       = */ "System error",
+    /* [PROTOCOL_ERROR]     = */ "Protocol error",
+    /* [PERMISSION_DENIED]  = */ "Permission denied",
+    /* [KEY_NOT_FOUND]      = */ "Key not found",
+    /* [VALUE_CORRUPTED]    = */ "Value corrupted",
+    /* [UNDEFINED_ACTION]   = */ "Undefined action",
+    /* [WRONG_PASSWORD]     = */ "Wrong password (last chance)",
+    /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)",
+    /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)",
+    /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)",
 };
 
-#define MAX_RESPONSE (WRONG_PASSWORD + 3)
-
-int main(int argc, char **argv)
+int main(int argc, char* argv[])
 {
-    uint8_t bytes[65536];
-    uint8_t code;
-    int sock, i;
-
     if (argc < 2) {
         printf("Usage: %s action [parameter ...]\n", argv[0]);
         return 0;
     }
 
-    sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
-                               SOCK_STREAM);
+    int sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
+                                   SOCK_STREAM);
     if (sock == -1) {
         puts("Failed to connect");
         return 1;
     }
 
     send(sock, argv[1], 1, 0);
-    for (i = 2; i < argc; ++i) {
+    uint8_t bytes[65536];
+    for (int i = 2; i < argc; ++i) {
         uint16_t length = strlen(argv[i]);
         bytes[0] = length >> 8;
         bytes[1] = length;
@@ -70,11 +66,13 @@
     }
     shutdown(sock, SHUT_WR);
 
+    uint8_t code;
     if (recv(sock, &code, 1, 0) != 1) {
         puts("Failed to receive");
         return 1;
     }
     printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown");
+    int i;
     while ((i = recv(sock, &bytes[0], 1, 0)) == 1) {
         int length;
         int offset;
diff --git a/cmds/keystore/test-keystore b/cmds/keystore/test-keystore
new file mode 100755
index 0000000..3be51b3
--- /dev/null
+++ b/cmds/keystore/test-keystore
@@ -0,0 +1,273 @@
+#!/bin/bash
+#
+# Copyright 2011, 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.
+
+set -e
+
+prefix=$0
+log_file=$prefix.log
+baseline_file=$prefix.baseline
+
+function cleanup_output() {
+    rm -f $log_file
+    rm -f $baseline_file
+}
+
+function log() {
+    echo "$@"
+    append $log_file \# "$@"
+    append $baseline_file \# "$@"
+}
+
+function expect() {
+    append $baseline_file "$@"
+}
+
+function append() {
+    declare -r file=$1
+    shift
+    echo "$@" >> $file
+}
+
+function run() {
+    # strip out carriage returns from adb
+    # strip out date/time from ls -l
+    "$@" | tr --delete '\r' | sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} +[0-9]{1,2}:[0-9]{2} //' >> $log_file
+}
+
+function keystore() {
+    declare -r user=$1
+    shift
+    run adb shell su $user keystore_cli "$@"
+}
+
+function list_keystore_directory() {
+    run adb shell ls -al /data/misc/keystore
+}
+
+function compare() {
+    log "comparing $baseline_file and $log_file"
+    diff $baseline_file $log_file || (log $tag FAILED && exit 1)
+}
+
+function test_basic() {
+
+    #
+    # reset
+    #
+    log "reset keystore as system user"
+    keystore system r
+    expect "1 No error"
+    list_keystore_directory
+
+    #
+    # basic tests as system/root
+    #
+    log "root does not have permission to run test"
+    keystore root t
+    expect "6 Permission denied"
+    
+    log "but system user does"
+    keystore system t
+    expect "3 Uninitialized"
+    list_keystore_directory
+
+    log "password is now bar"
+    keystore system p bar
+    expect "1 No error"
+    list_keystore_directory
+    expect "-rw------- keystore keystore       84 .masterkey"
+    
+    log "no error implies initialized and unlocked"
+    keystore system t
+    expect "1 No error"
+    
+    log "saw with no argument"
+    keystore system s
+    expect "5 Protocol error"
+
+    log "saw nothing"
+    keystore system s ""
+    expect "1 No error"
+
+    log "add key baz"
+    keystore system i baz quux
+    expect "1 No error"
+
+    log "1000 is uid of system"
+    list_keystore_directory
+    expect "-rw------- keystore keystore       84 .masterkey"
+    expect "-rw------- keystore keystore       52 1000_baz"
+
+    log "saw baz"
+    keystore system s ""
+    expect "1 No error"
+    expect "baz"
+
+    log "get baz"
+    keystore system g baz
+    expect "1 No error"
+    expect "quux"
+
+    log "root can read system user keys (as can wifi or vpn users)"
+    keystore root g baz
+    expect "1 No error"
+    expect "quux"
+
+    #
+    # app user tests
+    #
+
+    # app_0 has uid 10000, as seen below
+    log "other uses cannot see the system keys"
+    keystore app_0 g baz
+    expect "7 Key not found"
+    
+    log "app user cannot use reset, password, lock, unlock"
+    keystore app_0 r
+    expect "6 Permission denied"
+    keystore app_0 p
+    expect "6 Permission denied"
+    keystore app_0 l
+    expect "6 Permission denied"
+    keystore app_0 u
+    expect "6 Permission denied"
+
+    log "install app_0 key"
+    keystore app_0 i 0x deadbeef
+    expect 1 No error
+    list_keystore_directory
+    expect "-rw------- keystore keystore       84 .masterkey"
+    expect "-rw------- keystore keystore       52 10000_0x"
+    expect "-rw------- keystore keystore       52 1000_baz"
+
+    log "get with no argument"
+    keystore app_0 g
+    expect "5 Protocol error"
+    
+    keystore app_0 g 0x
+    expect "1 No error"
+    expect "deadbeef"
+    
+    keystore app_0 i fred barney
+    expect "1 No error"
+    
+    keystore app_0 s ""
+    expect "1 No error"
+    expect "0x"
+    expect "fred"
+
+    log "note that saw returns the suffix of prefix matches"
+    keystore app_0 s fr # fred
+    expect "1 No error"
+    expect "ed" # fred
+
+    #
+    # lock tests
+    #
+    log "lock the store as system"
+    keystore system l
+    expect "1 No error"
+    keystore system t
+    expect "2 Locked"
+    
+    log "saw works while locked"
+    keystore app_0 s ""
+    expect "1 No error"
+    expect "0x"
+    expect "fred"
+
+    log "...but cannot read keys..."
+    keystore app_0 g 0x
+    expect "2 Locked"
+    
+    log "...but they can be deleted."
+    keystore app_0 e 0x
+    expect "1 No error"
+    keystore app_0 d 0x
+    expect "1 No error"
+    keystore app_0 e 0x
+    expect "7 Key not found"
+
+    #
+    # password
+    #
+    log "wrong password"
+    keystore system u foo
+    expect "13 Wrong password (4 tries left)"
+    log "right password"
+    keystore system u bar
+    expect "1 No error"
+    
+    log "make the password foo"
+    keystore system p foo
+    expect "1 No error"
+    
+    #
+    # final reset
+    #
+    log "reset wipes everything for all users"
+    keystore system r
+    expect "1 No error"
+    list_keystore_directory
+    
+    keystore system t
+    expect "3 Uninitialized"
+
+}
+
+function test_4599735() {
+    # http://b/4599735
+    log "start regression test for b/4599735"
+    keystore system r
+    expect "1 No error"
+
+    keystore system p foo
+    expect "1 No error"
+
+    keystore system i baz quux
+    expect "1 No error"
+    
+    keystore root g baz
+    expect "1 No error"
+    expect "quux"
+
+    keystore system l
+    expect "1 No error"
+
+    keystore system p foo
+    expect "1 No error"
+
+    log "after unlock, regression led to result of '8 Value corrupted'"
+    keystore root g baz
+    expect "1 No error"
+    expect "quux"
+
+    keystore system r
+    expect "1 No error"
+    log "end regression test for b/4599735"
+}
+
+function main() {
+    cleanup_output
+    log $tag START
+    test_basic
+    test_4599735
+    compare
+    log $tag PASSED
+    cleanup_output
+}
+
+main
diff --git a/include/binder/IMemory.h b/include/binder/IMemory.h
index 74d2cc7..2d0db00 100644
--- a/include/binder/IMemory.h
+++ b/include/binder/IMemory.h
@@ -43,6 +43,7 @@
     virtual void*       getBase() const = 0;
     virtual size_t      getSize() const = 0;
     virtual uint32_t    getFlags() const = 0;
+    virtual uint32_t    getOffset() const = 0;
 
     // these are there just for backward source compatibility
     int32_t heapID() const { return getHeapID(); }
diff --git a/include/binder/MemoryHeapBase.h b/include/binder/MemoryHeapBase.h
index 2f2e31b..bbbda9c 100644
--- a/include/binder/MemoryHeapBase.h
+++ b/include/binder/MemoryHeapBase.h
@@ -27,7 +27,7 @@
 
 // ---------------------------------------------------------------------------
 
-class MemoryHeapBase : public virtual BnMemoryHeap 
+class MemoryHeapBase : public virtual BnMemoryHeap
 {
 public:
     enum {
@@ -38,12 +38,12 @@
         NO_CACHING = 0x00000200
     };
 
-    /* 
+    /*
      * maps the memory referenced by fd. but DOESN'T take ownership
      * of the filedescriptor (it makes a copy with dup()
      */
     MemoryHeapBase(int fd, size_t size, uint32_t flags = 0, uint32_t offset = 0);
-    
+
     /*
      * maps memory from the given device
      */
@@ -61,9 +61,10 @@
     virtual void*       getBase() const;
     virtual size_t      getSize() const;
     virtual uint32_t    getFlags() const;
+    virtual uint32_t      getOffset() const;
 
     const char*         getDevice() const;
-    
+
     /* this closes this heap -- use carefully */
     void dispose();
 
@@ -74,12 +75,12 @@
             mDevice = device;
         return mDevice ? NO_ERROR : ALREADY_EXISTS;
     }
-    
+
 protected:
             MemoryHeapBase();
     // init() takes ownership of fd
     status_t init(int fd, void *base, int size,
-            int flags = 0, const char* device = NULL);    
+            int flags = 0, const char* device = NULL);
 
 private:
     status_t mapfd(int fd, size_t size, uint32_t offset = 0);
@@ -90,6 +91,7 @@
     uint32_t    mFlags;
     const char* mDevice;
     bool        mNeedUnmap;
+    uint32_t    mOffset;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/binder/Permission.h b/include/binder/Permission.h
deleted file mode 100644
index 9542d50..0000000
--- a/include/binder/Permission.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 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 BINDER_PERMISSION_H
-#define BINDER_PERMISSION_H
-
-#include <stdint.h>
-#include <unistd.h>
-
-#include <utils/SortedVector.h>
-#include <utils/String16.h>
-#include <utils/threads.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-/*
- * Permission caches the result of the permission check for the given
- * permission name and the provided uid/pid. It also handles a few
- * known cases efficiently (caller is in the same process or is root).
- * The package manager does something similar but lives in dalvik world
- * and is therefore extremely slow to access.
- */
-
-class Permission
-{
-public:
-            Permission(char const* name);
-            Permission(const String16& name);
-            Permission(const Permission& rhs);
-    virtual ~Permission();
-
-    bool operator < (const Permission& rhs) const;
-
-    // checks the current binder call's caller has access to this permission
-    bool checkCalling() const;
-    
-    // checks the specified pid/uid has access to this permission
-    bool check(pid_t pid, uid_t uid) const;
-    
-protected:
-    virtual bool doCheckPermission(pid_t pid, uid_t uid) const;
-
-private:
-    Permission& operator = (const Permission& rhs) const;
-    const String16 mPermissionName;
-    mutable SortedVector<uid_t> mGranted;
-    const pid_t mPid;
-    mutable Mutex mLock;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif /* BINDER_PERMISSION_H */
diff --git a/include/binder/PermissionCache.h b/include/binder/PermissionCache.h
new file mode 100644
index 0000000..1171d48
--- /dev/null
+++ b/include/binder/PermissionCache.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2009 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 BINDER_PERMISSION_H
+#define BINDER_PERMISSION_H
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <utils/String16.h>
+#include <utils/Singleton.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * PermissionCache caches permission checks for a given uid.
+ *
+ * Currently the cache is not updated when there is a permission change,
+ * for instance when an application is uninstalled.
+ *
+ * IMPORTANT: for the reason stated above, only system permissions are safe
+ * to cache. This restriction may be lifted at a later time.
+ *
+ */
+
+class PermissionCache : Singleton<PermissionCache> {
+    struct Entry {
+        String16    name;
+        uid_t       uid;
+        bool        granted;
+        inline bool operator < (const Entry& e) const {
+            return (uid == e.uid) ? (name < e.name) : (uid < e.uid);
+        }
+    };
+    mutable Mutex mLock;
+    // we pool all the permission names we see, as many permissions checks
+    // will have identical names
+    SortedVector< String16 > mPermissionNamesPool;
+    // this is our cache per say. it stores pooled names.
+    SortedVector< Entry > mCache;
+
+    // free the whole cache, but keep the permission name pool
+    void purge();
+
+    status_t check(bool* granted,
+            const String16& permission, uid_t uid) const;
+
+    void cache(const String16& permission, uid_t uid, bool granted);
+
+public:
+    PermissionCache();
+
+    static bool checkCallingPermission(const String16& permission);
+
+    static bool checkCallingPermission(const String16& permission,
+                                int32_t* outPid, int32_t* outUid);
+
+    static bool checkPermission(const String16& permission,
+            pid_t pid, uid_t uid);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif /* BINDER_PERMISSION_H */
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 2de07b1..e59757a 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -21,8 +21,9 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
-#include <utils/String8.h>
 #include <utils/Flattenable.h>
+#include <utils/String8.h>
+#include <utils/Timers.h>
 
 #include <hardware/sensors.h>
 
@@ -64,6 +65,8 @@
     float getResolution() const;
     float getPowerUsage() const;
     int32_t getMinDelay() const;
+    nsecs_t getMinDelayNs() const;
+    int32_t getVersion() const;
 
     // Flattenable interface
     virtual size_t getFlattenedSize() const;
@@ -83,6 +86,7 @@
     float   mResolution;
     float   mPower;
     int32_t mMinDelay;
+    int32_t mVersion;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2b31462..c82fb9b 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -46,17 +46,20 @@
     enum { NUM_BUFFER_SLOTS = 32 };
 
     struct FrameAvailableListener : public virtual RefBase {
-        // onFrameAvailable() is called from queueBuffer() is the FIFO is
-        // empty. You can use SurfaceTexture::getQueuedCount() to
-        // figure out if there are more frames waiting.
-        // This is called without any lock held can be called concurrently by
-        // multiple threads.
+        // onFrameAvailable() is called from queueBuffer() each time an
+        // additional frame becomes available for consumption. This means that
+        // frames that are queued while in asynchronous mode only trigger the
+        // callback if no previous frames are pending. Frames queued while in
+        // synchronous mode always trigger the callback.
+        //
+        // This is called without any lock held and can be called concurrently
+        // by multiple threads.
         virtual void onFrameAvailable() = 0;
     };
 
     // tex indicates the name OpenGL texture to which images are to be streamed.
     // This texture name cannot be changed once the SurfaceTexture is created.
-    SurfaceTexture(GLuint tex);
+    SurfaceTexture(GLuint tex, bool allowSynchronousMode = true);
 
     virtual ~SurfaceTexture();
 
@@ -101,11 +104,6 @@
     // target texture belongs is bound to the calling thread.
     status_t updateTexImage();
 
-    // getqueuedCount returns the number of queued frames waiting in the
-    // FIFO. In asynchronous mode, this always returns 0 or 1 since
-    // frames are not accumulating in the FIFO.
-    size_t getQueuedCount() const;
-
     // setBufferCountServer set the buffer count. If the client has requested
     // a buffer count using setBufferCount, the server-buffer count will
     // take effect once the client sets the count back to zero.
@@ -188,6 +186,11 @@
 
     status_t setBufferCountServerLocked(int bufferCount);
 
+    // computeCurrentTransformMatrix computes the transform matrix for the
+    // current texture.  It uses mCurrentTransform and the current GraphicBuffer
+    // to compute this matrix and stores it in mCurrentTransformMatrix.
+    void computeCurrentTransformMatrix();
+
     enum { INVALID_BUFFER_SLOT = -1 };
 
     struct BufferSlot {
@@ -288,9 +291,9 @@
     // by calling setBufferCount or setBufferCountServer
     int mBufferCount;
 
-    // mRequestedBufferCount is the number of buffer slots requested by the
-    // client. The default is zero, which means the client doesn't care how
-    // many buffers there is.
+    // mClientBufferCount is the number of buffer slots requested by the client.
+    // The default is zero, which means the client doesn't care how many buffers
+    // there is.
     int mClientBufferCount;
 
     // mServerBufferCount buffer count requested by the server-side
@@ -322,6 +325,11 @@
     // gets set to mLastQueuedTransform each time updateTexImage is called.
     uint32_t mCurrentTransform;
 
+    // mCurrentTransformMatrix is the transform matrix for the current texture.
+    // It gets computed by computeTransformMatrix each time updateTexImage is
+    // called.
+    float mCurrentTransformMatrix[16];
+
     // mCurrentTimestamp is the timestamp for the current texture. It
     // gets set to mLastQueuedTimestamp each time updateTexImage is called.
     int64_t mCurrentTimestamp;
@@ -351,6 +359,9 @@
     // mSynchronousMode whether we're in synchronous mode or not
     bool mSynchronousMode;
 
+    // mAllowSynchronousMode whether we allow synchronous mode or not
+    const bool mAllowSynchronousMode;
+
     // mDequeueCondition condition used for dequeueBuffer in synchronous mode
     mutable Condition mDequeueCondition;
 
@@ -362,6 +373,7 @@
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
     mutable Mutex mMutex;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index e7c6e24..6ce44fc 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -80,6 +80,7 @@
     int setUsage(uint32_t reqUsage);
 
     void freeAllBuffers();
+    int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
 
     int getConnectedApi() const;
 
diff --git a/include/pim/EventRecurrence.h b/include/pim/EventRecurrence.h
deleted file mode 100644
index 1ceda41..0000000
--- a/include/pim/EventRecurrence.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2006 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 _PIM_EVENT_RECURRENCE_H
-#define _PIM_EVENT_RECURRENCE_H
-
-#include <utils/String16.h>
-
-namespace android {
-
-struct EventRecurrence
-{
-public:
-                EventRecurrence();
-                ~EventRecurrence();
-    
-    status_t    parse(const String16&);
-
-
-    enum freq_t {
-        SECONDLY = 1,
-        MINUTELY = 2,
-        HOURLY = 3,
-        DAILY = 4,
-        WEEKLY = 5,
-        MONTHLY = 6,
-        YEARLY = 7
-    };
-
-    enum {
-        SU = 0x00010000,
-        MO = 0x00020000,
-        TU = 0x00040000,
-        WE = 0x00080000,
-        TH = 0x00100000,
-        FR = 0x00200000,
-        SA = 0x00400000
-    };
-    
-    freq_t    freq;
-    String16  until;
-    int       count;
-    int       interval;
-    int*      bysecond;
-    int       bysecondCount;
-    int*      byminute;
-    int       byminuteCount;
-    int*      byhour;
-    int       byhourCount;
-    int*      byday;
-    int*      bydayNum;
-    int       bydayCount;   
-    int*      bymonthday;
-    int       bymonthdayCount;
-    int*      byyearday;
-    int       byyeardayCount;
-    int*      byweekno;
-    int       byweeknoCount;
-    int*      bymonth;
-    int       bymonthCount;
-    int*      bysetpos;
-    int       bysetposCount;
-    int       wkst;
-};
-
-}; // namespace android
-
-#endif // _PIM_EVENT_RECURRENCE_H
diff --git a/include/private/surfaceflinger/LayerState.h b/include/private/surfaceflinger/LayerState.h
index d7fe572..d2fed41 100644
--- a/include/private/surfaceflinger/LayerState.h
+++ b/include/private/surfaceflinger/LayerState.h
@@ -29,6 +29,7 @@
 namespace android {
 
 class Parcel;
+class ISurfaceComposerClient;
 
 struct layer_state_t {
 
@@ -68,6 +69,13 @@
             Region          transparentRegion;
 };
 
+struct ComposerState {
+    sp<ISurfaceComposerClient> client;
+    layer_state_t state;
+    status_t    write(Parcel& output) const;
+    status_t    read(const Parcel& input);
+};
+
 }; // namespace android
 
 #endif // ANDROID_SF_LAYER_STATE_H
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index 717f837..0da03d1 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -20,355 +20,12 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <cutils/compiler.h>
-
 #include <utils/Debug.h>
-#include <utils/threads.h>
-#include <utils/String8.h>
-
-#include <ui/Rect.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
 
-/*
- * These classes manage a stack of buffers in shared memory.
- * 
- * SharedClient: represents a client with several stacks
- * SharedBufferStack: represents a stack of buffers
- * SharedBufferClient: manipulates the SharedBufferStack from the client side 
- * SharedBufferServer: manipulates the SharedBufferStack from the server side 
- *
- * Buffers can be dequeued until there are none available, they can be locked
- * unless they are in use by the server, which is only the case for the last 
- * dequeue-able buffer. When these various conditions are not met, the caller
- * waits until the condition is met.
- * 
- */
-
-// ----------------------------------------------------------------------------
-
-class Region;
-class SharedBufferStack;
-class SharedClient;
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferStack
-{
-    friend class SharedClient;
-    friend class SharedBufferBase;
-    friend class SharedBufferClient;
-    friend class SharedBufferServer;
-
-public:
-    // When changing these values, the COMPILE_TIME_ASSERT at the end of this
-    // file need to be updated.
-    static const unsigned int NUM_LAYERS_MAX  = 31;
-    static const unsigned int NUM_BUFFER_MAX  = 32;
-    static const unsigned int NUM_BUFFER_MIN  = 2;
-    static const unsigned int NUM_DISPLAY_MAX = 4;
-
-    struct Statistics { // 4 longs
-        typedef int32_t usecs_t;
-        usecs_t  totalTime;
-        usecs_t  reserved[3];
-    };
-
-    struct SmallRect {
-        uint16_t l, t, r, b;
-    };
-
-    struct FlatRegion { // 52 bytes = 4 * (1 + 2*N)
-        static const unsigned int NUM_RECT_MAX = 5;
-        uint32_t    count;
-        SmallRect   rects[NUM_RECT_MAX];
-    };
-    
-    struct BufferData {
-        FlatRegion dirtyRegion;
-        SmallRect  crop;
-        uint8_t transform;
-        uint8_t reserved[3];
-    };
-    
-    SharedBufferStack();
-    void init(int32_t identity);
-    status_t setDirtyRegion(int buffer, const Region& reg);
-    status_t setCrop(int buffer, const Rect& reg);
-    status_t setTransform(int buffer, uint8_t transform);
-    Region getDirtyRegion(int buffer) const;
-    Rect getCrop(int buffer) const;
-    uint32_t getTransform(int buffer) const;
-
-    // these attributes are part of the conditions/updates
-    volatile int32_t head;      // server's current front buffer
-    volatile int32_t available; // number of dequeue-able buffers
-    volatile int32_t queued;    // number of buffers waiting for post
-    volatile int32_t reserved1;
-    volatile status_t status;   // surface's status code
-
-    // not part of the conditions
-    volatile int32_t reallocMask;
-    volatile int8_t index[NUM_BUFFER_MAX];
-
-    int32_t     identity;       // surface's identity (const)
-    int32_t     token;          // surface's token (for debugging)
-    Statistics  stats;
-    int8_t      headBuf;        // last retired buffer
-    uint8_t     reservedBytes[3];
-    int32_t     reserved;
-    BufferData  buffers[NUM_BUFFER_MAX];     // 1024 bytes
-};
-
-// ----------------------------------------------------------------------------
-
-// 64 KB max
-class SharedClient
-{
-public:
-    SharedClient();
-    ~SharedClient();
-    status_t validate(size_t token) const;
-
-private:
-    friend class SharedBufferBase;
-    friend class SharedBufferClient;
-    friend class SharedBufferServer;
-
-    // FIXME: this should be replaced by a lock-less primitive
-    Mutex lock;
-    Condition cv;
-    SharedBufferStack surfaces[ SharedBufferStack::NUM_LAYERS_MAX ];
-};
-
-// ============================================================================
-
-class SharedBufferBase
-{
-public:
-    SharedBufferBase(SharedClient* sharedClient, int surface,
-            int32_t identity);
-    ~SharedBufferBase();
-    status_t getStatus() const;
-    int32_t getIdentity() const;
-    String8 dump(char const* prefix) const;
-
-protected:
-    SharedClient* const mSharedClient;
-    SharedBufferStack* const mSharedStack;
-    const int mIdentity;
-
-    friend struct Update;
-    friend struct QueueUpdate;
-
-    struct ConditionBase {
-        SharedBufferStack& stack;
-        inline ConditionBase(SharedBufferBase* sbc) 
-            : stack(*sbc->mSharedStack) { }
-        virtual ~ConditionBase() { };
-        virtual bool operator()() const = 0;
-        virtual const char* name() const = 0;
-    };
-    status_t waitForCondition(const ConditionBase& condition);
-
-    struct UpdateBase {
-        SharedBufferStack& stack;
-        inline UpdateBase(SharedBufferBase* sbb) 
-            : stack(*sbb->mSharedStack) { }
-    };
-    template <typename T>
-    status_t updateCondition(T update);
-};
-
-template <typename T>
-status_t SharedBufferBase::updateCondition(T update) {
-    SharedClient& client( *mSharedClient );
-    Mutex::Autolock _l(client.lock);
-    ssize_t result = update();
-    client.cv.broadcast();    
-    return result;
-}
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferClient : public SharedBufferBase
-{
-public:
-    SharedBufferClient(SharedClient* sharedClient, int surface, int num,
-            int32_t identity);
-
-    ssize_t dequeue();
-    status_t undoDequeue(int buf);
-    
-    status_t lock(int buf);
-    status_t cancel(int buf);
-    status_t queue(int buf);
-    bool needNewBuffer(int buffer) const;
-    status_t setDirtyRegion(int buffer, const Region& reg);
-    status_t setCrop(int buffer, const Rect& reg);
-    status_t setTransform(int buffer, uint32_t transform);
-
-    class SetBufferCountCallback {
-        friend class SharedBufferClient;
-        virtual status_t operator()(int bufferCount) const = 0;
-    protected:
-        virtual ~SetBufferCountCallback() { }
-    };
-    status_t setBufferCount(int bufferCount, const SetBufferCountCallback& ipc);
-
-private:
-    friend struct Condition;
-    friend struct DequeueCondition;
-    friend struct LockCondition;
-
-    struct QueueUpdate : public UpdateBase {
-        inline QueueUpdate(SharedBufferBase* sbb);
-        inline ssize_t operator()();
-    };
-
-    struct DequeueUpdate : public UpdateBase {
-        inline DequeueUpdate(SharedBufferBase* sbb);
-        inline ssize_t operator()();
-    };
-
-    struct CancelUpdate : public UpdateBase {
-        int tail, buf;
-        inline CancelUpdate(SharedBufferBase* sbb, int tail, int buf);
-        inline ssize_t operator()();
-    };
-
-    // --
-
-    struct DequeueCondition : public ConditionBase {
-        inline DequeueCondition(SharedBufferClient* sbc);
-        inline bool operator()() const;
-        inline const char* name() const { return "DequeueCondition"; }
-    };
-
-    struct LockCondition : public ConditionBase {
-        int buf;
-        inline LockCondition(SharedBufferClient* sbc, int buf);
-        inline bool operator()() const;
-        inline const char* name() const { return "LockCondition"; }
-    };
-
-    int32_t computeTail() const;
-
-    mutable RWLock mLock;
-    int mNumBuffers;
-
-    int32_t tail;
-    int32_t queued_head;
-    // statistics...
-    nsecs_t mDequeueTime[SharedBufferStack::NUM_BUFFER_MAX];
-};
-
-// ----------------------------------------------------------------------------
-
-class SharedBufferServer
-    : public SharedBufferBase,
-      public LightRefBase<SharedBufferServer>
-{
-public:
-    SharedBufferServer(SharedClient* sharedClient, int surface, int num,
-            int32_t identity);
-
-    ssize_t retireAndLock();
-    void setStatus(status_t status);
-    status_t reallocateAll();
-    status_t reallocateAllExcept(int buffer);
-    int32_t getQueuedCount() const;
-    Region getDirtyRegion(int buffer) const;
-    Rect getCrop(int buffer) const;
-    uint32_t getTransform(int buffer) const;
-
-    status_t resize(int newNumBuffers);
-    status_t grow(int newNumBuffers);
-    status_t shrink(int newNumBuffers);
-
-    SharedBufferStack::Statistics getStats() const;
-    
-
-private:
-    friend class LightRefBase<SharedBufferServer>;
-    ~SharedBufferServer();
-
-    /*
-     * BufferList is basically a fixed-capacity sorted-vector of
-     * unsigned 5-bits ints using a 32-bits int as storage.
-     * it has efficient iterators to find items in the list and not in the list.
-     */
-    class BufferList {
-        size_t mCapacity;
-        uint32_t mList;
-    public:
-        BufferList(size_t c = SharedBufferStack::NUM_BUFFER_MAX)
-            : mCapacity(c), mList(0) { }
-        status_t add(int value);
-        status_t remove(int value);
-        uint32_t getMask() const { return mList; }
-
-        class const_iterator {
-            friend class BufferList;
-            uint32_t mask, curr;
-            const_iterator(uint32_t mask) :
-                mask(mask), curr(__builtin_clz(mask)) {
-            }
-        public:
-            inline bool operator == (const const_iterator& rhs) const {
-                return mask == rhs.mask;
-            }
-            inline bool operator != (const const_iterator& rhs) const {
-                return mask != rhs.mask;
-            }
-            inline int operator *() const { return curr; }
-            inline const const_iterator& operator ++() {
-                mask &= ~(1<<(31-curr));
-                curr = __builtin_clz(mask);
-                return *this;
-            }
-        };
-
-        inline const_iterator begin() const {
-            return const_iterator(mList);
-        }
-        inline const_iterator end() const   {
-            return const_iterator(0);
-        }
-        inline const_iterator free_begin() const {
-            uint32_t mask = (1 << (32-mCapacity)) - 1;
-            return const_iterator( ~(mList | mask) );
-        }
-    };
-
-    // this protects mNumBuffers and mBufferList
-    mutable RWLock mLock;
-    int mNumBuffers;
-    BufferList mBufferList;
-
-    struct BuffersAvailableCondition : public ConditionBase {
-        int mNumBuffers;
-        inline BuffersAvailableCondition(SharedBufferServer* sbs,
-                int numBuffers);
-        inline bool operator()() const;
-        inline const char* name() const { return "BuffersAvailableCondition"; }
-    };
-
-    struct RetireUpdate : public UpdateBase {
-        const int numBuffers;
-        inline RetireUpdate(SharedBufferBase* sbb, int numBuffers);
-        inline ssize_t operator()();
-    };
-
-    struct StatusUpdate : public UpdateBase {
-        const status_t status;
-        inline StatusUpdate(SharedBufferBase* sbb, status_t status);
-        inline ssize_t operator()();
-    };
-};
-
-// ===========================================================================
+#define NUM_DISPLAY_MAX 4
 
 struct display_cblk_t
 {
@@ -389,12 +46,11 @@
     uint8_t         connected;
     uint8_t         reserved[3];
     uint32_t        pad[7];
-    display_cblk_t  displays[SharedBufferStack::NUM_DISPLAY_MAX];
+    display_cblk_t  displays[NUM_DISPLAY_MAX];
 };
 
 // ---------------------------------------------------------------------------
 
-COMPILE_TIME_ASSERT(sizeof(SharedClient) <= 65536)
 COMPILE_TIME_ASSERT(sizeof(surface_flinger_cblk_t) <= 4096)
 
 // ---------------------------------------------------------------------------
diff --git a/include/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h
index 01e4bd9..e1b6b57 100644
--- a/include/surfaceflinger/IGraphicBufferAlloc.h
+++ b/include/surfaceflinger/IGraphicBufferAlloc.h
@@ -27,6 +27,8 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+class GraphicBuffer;
+
 class IGraphicBufferAlloc : public IInterface
 {
 public:
diff --git a/include/surfaceflinger/ISurface.h b/include/surfaceflinger/ISurface.h
index cd0ee40..5fdf234 100644
--- a/include/surfaceflinger/ISurface.h
+++ b/include/surfaceflinger/ISurface.h
@@ -27,42 +27,23 @@
 
 #include <ui/PixelFormat.h>
 
-#include <hardware/hardware.h>
-#include <hardware/gralloc.h>
-
 namespace android {
 
 typedef int32_t    SurfaceID;
 
-class GraphicBuffer;
+class ISurfaceTexture;
 
 class ISurface : public IInterface
 {
 protected:
     enum {
-        RESERVED0 = IBinder::FIRST_CALL_TRANSACTION,
-        RESERVED1,
-        RESERVED2,
-        REQUEST_BUFFER,
-        SET_BUFFER_COUNT,
+        GET_SURFACE_TEXTURE = IBinder::FIRST_CALL_TRANSACTION,
     };
 
 public: 
     DECLARE_META_INTERFACE(Surface);
 
-    /*
-     * requests a new buffer for the given index. If w, h, or format are
-     * null the buffer is created with the parameters assigned to the
-     * surface it is bound to. Otherwise the buffer's parameters are
-     * set to those specified.
-     */
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) = 0;
-
-    /*
-     * sets the number of buffers dequeuable for this surface.
-     */
-    virtual status_t setBufferCount(int bufferCount) = 0;
+    virtual sp<ISurfaceTexture> getSurfaceTexture() const = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index dea1b10..dba98a3 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -33,6 +33,9 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+class IMemoryHeap;
+class ComposerState;
+
 class ISurfaceComposer : public IInterface
 {
 public:
@@ -95,10 +98,6 @@
      */
     virtual sp<ISurfaceComposerClient> createConnection() = 0;
 
-    /* create a client connection with surface flinger
-     */
-    virtual sp<ISurfaceComposerClient> createClientConnection() = 0;
-
     /* create a graphic buffer allocator
      */
     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc() = 0;
@@ -107,8 +106,7 @@
     virtual sp<IMemoryHeap> getCblk() const = 0;
 
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
-    virtual void openGlobalTransaction() = 0;
-    virtual void closeGlobalTransaction() = 0;
+    virtual void setTransactionState(const Vector<ComposerState>& state) = 0;
 
     /* [un]freeze display. requires ACCESS_SURFACE_FLINGER permission */
     virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) = 0;
@@ -134,11 +132,6 @@
     virtual status_t turnElectronBeamOff(int32_t mode) = 0;
     virtual status_t turnElectronBeamOn(int32_t mode) = 0;
 
-    /* Signal surfaceflinger that there might be some work to do
-     * This is an ASYNCHRONOUS call.
-     */
-    virtual void signal() const = 0;
-
     /* verify that an ISurface was created by SurfaceFlinger.
      */
     virtual bool authenticateSurface(const sp<ISurface>& surface) const = 0;
@@ -154,15 +147,12 @@
         // Java by ActivityManagerService.
         BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
         CREATE_CONNECTION,
-        CREATE_CLIENT_CONNECTION,
         CREATE_GRAPHIC_BUFFER_ALLOC,
         GET_CBLK,
-        OPEN_GLOBAL_TRANSACTION,
-        CLOSE_GLOBAL_TRANSACTION,
+        SET_TRANSACTION_STATE,
         SET_ORIENTATION,
         FREEZE_DISPLAY,
         UNFREEZE_DISPLAY,
-        SIGNAL,
         CAPTURE_SCREEN,
         TURN_ELECTRON_BEAM_OFF,
         TURN_ELECTRON_BEAM_ON,
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index 46b1bb7..6e9a654 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -33,15 +33,10 @@
 
 // ----------------------------------------------------------------------------
 
-class IMemoryHeap;
-
-typedef int32_t    ClientID;
 typedef int32_t    DisplayID;
 
 // ----------------------------------------------------------------------------
 
-class layer_state_t;
-
 class ISurfaceComposerClient : public IInterface
 {
 public:
@@ -57,9 +52,6 @@
         status_t writeToParcel(Parcel* parcel) const;
     };
 
-    virtual sp<IMemoryHeap> getControlBlock() const = 0;
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const = 0;
-
     /*
      * Requires ACCESS_SURFACE_FLINGER permission
      */
@@ -75,11 +67,6 @@
      * Requires ACCESS_SURFACE_FLINGER permission
      */
     virtual status_t    destroySurface(SurfaceID sid) = 0;
-
-    /*
-     * Requires ACCESS_SURFACE_FLINGER permission
-     */
-    virtual status_t    setState(int32_t count, const layer_state_t* states) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/Surface.h b/include/surfaceflinger/Surface.h
index ab30f45..dc2a845 100644
--- a/include/surfaceflinger/Surface.h
+++ b/include/surfaceflinger/Surface.h
@@ -40,12 +40,11 @@
 class GraphicBuffer;
 class GraphicBufferMapper;
 class IOMX;
+class ISurfaceTexture;
 class Rect;
 class Surface;
 class SurfaceComposerClient;
-class SharedClient;
-class SharedBufferClient;
-class SurfaceClient;
+class SurfaceTextureClient;
 
 // ---------------------------------------------------------------------------
 
@@ -156,15 +155,13 @@
     bool        isValid();
     uint32_t    getFlags() const    { return mFlags; }
     uint32_t    getIdentity() const { return mIdentity; }
+    sp<ISurfaceTexture> getSurfaceTexture();
 
     // the lock/unlock APIs must be used from the same thread
     status_t    lock(SurfaceInfo* info, bool blocking = true);
     status_t    lock(SurfaceInfo* info, Region* dirty, bool blocking = true);
     status_t    unlockAndPost();
 
-    // setSwapRectangle() is intended to be used by GL ES clients
-    void        setSwapRectangle(const Rect& r);
-
     sp<IBinder> asBinder() const;
 
 private:
@@ -209,6 +206,7 @@
     static int query(const ANativeWindow* window, int what, int* value);
     static int perform(ANativeWindow* window, int operation, ...);
 
+    int setSwapInterval(int interval);
     int dequeueBuffer(ANativeWindowBuffer** buffer);
     int lockBuffer(ANativeWindowBuffer* buffer);
     int queueBuffer(ANativeWindowBuffer* buffer);
@@ -216,83 +214,23 @@
     int query(int what, int* value) const;
     int perform(int operation, va_list args);
 
-    void dispatch_setUsage(va_list args);
-    int  dispatch_connect(va_list args);
-    int  dispatch_disconnect(va_list args);
-    int  dispatch_crop(va_list args);
-    int  dispatch_set_buffer_count(va_list args);
-    int  dispatch_set_buffers_geometry(va_list args);
-    int  dispatch_set_buffers_transform(va_list args);
-    int  dispatch_set_buffers_timestamp(va_list args);
-
-    void setUsage(uint32_t reqUsage);
-    int  connect(int api);
-    int  disconnect(int api);
-    int  crop(Rect const* rect);
-    int  setBufferCount(int bufferCount);
-    int  setBuffersGeometry(int w, int h, int format);
-    int  setBuffersTransform(int transform);
-    int  setBuffersTimestamp(int64_t timestamp);
-
     /*
      *  private stuff...
      */
     void init();
     status_t validate(bool inCancelBuffer = false) const;
 
-    // When the buffer pool is a fixed size we want to make sure SurfaceFlinger
-    // won't stall clients, so we require an extra buffer.
-    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
-
-    inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
-    inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
-
-    status_t getBufferLocked(int index,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-    int getBufferIndex(const sp<GraphicBuffer>& buffer) const;
-
     int getConnectedApi() const;
     
-    bool needNewBuffer(int bufIdx,
-            uint32_t *pWidth, uint32_t *pHeight,
-            uint32_t *pFormat, uint32_t *pUsage) const;
-
     static void cleanCachedSurfacesLocked();
 
-    class BufferInfo {
-        uint32_t mWidth;
-        uint32_t mHeight;
-        uint32_t mFormat;
-        uint32_t mUsage;
-        mutable uint32_t mDirty;
-        enum {
-            GEOMETRY = 0x01
-        };
-    public:
-        BufferInfo();
-        void set(uint32_t w, uint32_t h, uint32_t format);
-        void set(uint32_t usage);
-        void get(uint32_t *pWidth, uint32_t *pHeight,
-                uint32_t *pFormat, uint32_t *pUsage) const;
-        bool validateBuffer(const sp<GraphicBuffer>& buffer) const;
-    };
-
     // constants
-    GraphicBufferMapper&        mBufferMapper;
-    SurfaceClient&              mClient;
-    SharedBufferClient*         mSharedBufferClient;
     status_t                    mInitCheck;
     sp<ISurface>                mSurface;
+    sp<SurfaceTextureClient>    mSurfaceTextureClient;
     uint32_t                    mIdentity;
     PixelFormat                 mFormat;
     uint32_t                    mFlags;
-
-    // protected by mSurfaceLock
-    Rect                        mSwapRectangle;
-    int                         mConnected;
-    Rect                        mNextBufferCrop;
-    uint32_t                    mNextBufferTransform;
-    BufferInfo                  mBufferInfo;
     
     // protected by mSurfaceLock. These are also used from lock/unlock
     // but in that case, they must be called form the same thread.
@@ -304,9 +242,6 @@
     mutable Region              mOldDirtyRegion;
     bool                        mReserved;
 
-    // only used from dequeueBuffer()
-    Vector< sp<GraphicBuffer> > mBuffers;
-
     // query() must be called from dequeueBuffer() thread
     uint32_t                    mWidth;
     uint32_t                    mHeight;
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index c61a5bf..7fbbfb2 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -36,11 +36,13 @@
 
 // ---------------------------------------------------------------------------
 
-class Region;
-class SharedClient;
-class ISurfaceComposer;
 class DisplayInfo;
+class Composer;
+class IMemoryHeap;
+class ISurfaceComposer;
+class Region;
 class surface_flinger_cblk_t;
+struct layer_state_t;
 
 // ---------------------------------------------------------------------------
 
@@ -59,8 +61,11 @@
 
 // ---------------------------------------------------------------------------
 
+class Composer;
+
 class SurfaceComposerClient : public RefBase
 {
+    friend class Composer;
 public:    
                 SurfaceComposerClient();
     virtual     ~SurfaceComposerClient();
@@ -101,13 +106,7 @@
     // All composer parameters must be changed within a transaction
     // several surfaces can be updated in one transaction, all changes are
     // committed at once when the transaction is closed.
-    // CloseTransaction() usually requires an IPC with the server.
-    
-    //! Open a composer transaction
-    status_t    openTransaction();
-
-    //! commit the transaction
-    status_t    closeTransaction();
+    // closeGlobalTransaction() usually requires an IPC with the server.
 
     //! Open a composer transaction on all active SurfaceComposerClients.
     static void openGlobalTransaction();
@@ -152,19 +151,12 @@
 
 private:
     virtual void onFirstRef();
-    inline layer_state_t*   get_state_l(SurfaceID id);
-    layer_state_t*          lockLayerState(SurfaceID id);
-    inline void             unlockLayerState();
+    Composer& getComposer();
 
-    mutable     Mutex                               mLock;
-                SortedVector<layer_state_t>         mStates;
-                int32_t                             mTransactionOpen;
-                layer_state_t*                      mPrebuiltLayerState;
-
-                // these don't need to be protected because they never change
-                // after assignment
+    mutable     Mutex                       mLock;
                 status_t                    mStatus;
                 sp<ISurfaceComposerClient>  mClient;
+                Composer&                   mComposer;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/ui/Input.h b/include/ui/Input.h
index ba1c6b4..c9f694a 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -655,11 +655,6 @@
     // Oldest sample to consider when calculating the velocity.
     static const nsecs_t MAX_AGE = 200 * 1000000; // 200 ms
 
-    // When the total duration of the window of samples being averaged is less
-    // than the window size, the resulting velocity is scaled to reduce the impact
-    // of overestimation in short traces.
-    static const nsecs_t MIN_WINDOW = 100 * 1000000; // 100 ms
-
     // The minimum duration between samples when estimating velocity.
     static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms
 
@@ -674,6 +669,87 @@
     int32_t mActivePointerId;
 };
 
+
+/*
+ * Specifies parameters that govern pointer or wheel acceleration.
+ */
+struct VelocityControlParameters {
+    // A scale factor that is multiplied with the raw velocity deltas
+    // prior to applying any other velocity control factors.  The scale
+    // factor should be used to adapt the input device resolution
+    // (eg. counts per inch) to the output device resolution (eg. pixels per inch).
+    //
+    // Must be a positive value.
+    // Default is 1.0 (no scaling).
+    float scale;
+
+    // The scaled speed at which acceleration begins to be applied.
+    // This value establishes the upper bound of a low speed regime for
+    // small precise motions that are performed without any acceleration.
+    //
+    // Must be a non-negative value.
+    // Default is 0.0 (no low threshold).
+    float lowThreshold;
+
+    // The scaled speed at which maximum acceleration is applied.
+    // The difference between highThreshold and lowThreshold controls
+    // the range of speeds over which the acceleration factor is interpolated.
+    // The wider the range, the smoother the acceleration.
+    //
+    // Must be a non-negative value greater than or equal to lowThreshold.
+    // Default is 0.0 (no high threshold).
+    float highThreshold;
+
+    // The acceleration factor.
+    // When the speed is above the low speed threshold, the velocity will scaled
+    // by an interpolated value between 1.0 and this amount.
+    //
+    // Must be a positive greater than or equal to 1.0.
+    // Default is 1.0 (no acceleration).
+    float acceleration;
+
+    VelocityControlParameters() :
+            scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) {
+    }
+
+    VelocityControlParameters(float scale, float lowThreshold,
+            float highThreshold, float acceleration) :
+            scale(scale), lowThreshold(lowThreshold),
+            highThreshold(highThreshold), acceleration(acceleration) {
+    }
+};
+
+/*
+ * Implements mouse pointer and wheel speed control and acceleration.
+ */
+class VelocityControl {
+public:
+    VelocityControl();
+
+    /* Sets the various parameters. */
+    void setParameters(const VelocityControlParameters& parameters);
+
+    /* Resets the current movement counters to zero.
+     * This has the effect of nullifying any acceleration. */
+    void reset();
+
+    /* Translates a raw movement delta into an appropriately
+     * scaled / accelerated delta based on the current velocity. */
+    void move(nsecs_t eventTime, float* deltaX, float* deltaY);
+
+private:
+    // If no movements are received within this amount of time,
+    // we assume the movement has stopped and reset the movement counters.
+    static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms
+
+    VelocityControlParameters mParameters;
+
+    nsecs_t mLastMovementTime;
+    VelocityTracker::Position mRawPosition;
+    VelocityTracker mVelocityTracker;
+};
+
+
 /*
  * Describes the characteristics and capabilities of an input device.
  */
diff --git a/include/utils/BlobCache.h b/include/utils/BlobCache.h
new file mode 100644
index 0000000..dc45ff0
--- /dev/null
+++ b/include/utils/BlobCache.h
@@ -0,0 +1,184 @@
+/*
+ ** Copyright 2011, 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 ANDROID_BLOB_CACHE_H
+#define ANDROID_BLOB_CACHE_H
+
+#include <stddef.h>
+
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// A BlobCache is an in-memory cache for binary key/value pairs. All the public
+// methods are thread-safe.
+//
+// The cache contents can be serialized to a file and reloaded in a subsequent
+// execution of the program. This serialization is non-portable and should only
+// be loaded by the device that generated it.
+class BlobCache : public RefBase {
+public:
+
+    // Create an empty blob cache. The blob cache will cache key/value pairs
+    // with key and value sizes less than or equal to maxKeySize and
+    // maxValueSize, respectively. The total combined size of ALL cache entries
+    // (key sizes plus value sizes) will not exceed maxTotalSize.
+    BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize);
+
+    // set inserts a new binary value into the cache and associates it with the
+    // given binary key.  If the key or value are too large for the cache then
+    // the cache remains unchanged.  This includes the case where a different
+    // value was previously associated with the given key - the old value will
+    // remain in the cache.  If the given key and value are small enough to be
+    // put in the cache (based on the maxKeySize, maxValueSize, and maxTotalSize
+    // values specified to the BlobCache constructor), then the key/value pair
+    // will be in the cache after set returns.  Note, however, that a subsequent
+    // call to set may evict old key/value pairs from the cache.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   value != NULL
+    //   0 < valueSize
+    void set(const void* key, size_t keySize, const void* value,
+            size_t valueSize);
+
+    // The get function retrieves from the cache the binary value associated
+    // with a given binary key.  If the key is present in the cache then the
+    // length of the binary value associated with that key is returned.  If the
+    // value argument is non-NULL and the size of the cached value is less than
+    // valueSize bytes then the cached value is copied into the buffer pointed
+    // to by the value argument.  If the key is not present in the cache then 0
+    // is returned and the buffer pointed to by the value argument is not
+    // modified.
+    //
+    // Note that when calling get multiple times with the same key, the later
+    // calls may fail, returning 0, even if earlier calls succeeded.  The return
+    // value must be checked for each call.
+    //
+    // Preconditions:
+    //   key != NULL
+    //   0 < keySize
+    //   0 <= valueSize
+    size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
+
+private:
+    // Copying is disallowed.
+    BlobCache(const BlobCache&);
+    void operator=(const BlobCache&);
+
+    // A random function helper to get around MinGW not having nrand48()
+    long int blob_random();
+
+    // clean evicts a randomly chosen set of entries from the cache such that
+    // the total size of all remaining entries is less than mMaxTotalSize/2.
+    void clean();
+
+    // isCleanable returns true if the cache is full enough for the clean method
+    // to have some effect, and false otherwise.
+    bool isCleanable() const;
+
+    // A Blob is an immutable sized unstructured data blob.
+    class Blob : public RefBase {
+    public:
+        Blob(const void* data, size_t size, bool copyData);
+        ~Blob();
+
+        bool operator<(const Blob& rhs) const;
+
+        const void* getData() const;
+        size_t getSize() const;
+
+    private:
+        // Copying is not allowed.
+        Blob(const Blob&);
+        void operator=(const Blob&);
+
+        // mData points to the buffer containing the blob data.
+        const void* mData;
+
+        // mSize is the size of the blob data in bytes.
+        size_t mSize;
+
+        // mOwnsData indicates whether or not this Blob object should free the
+        // memory pointed to by mData when the Blob gets destructed.
+        bool mOwnsData;
+    };
+
+    // A CacheEntry is a single key/value pair in the cache.
+    class CacheEntry {
+    public:
+        CacheEntry();
+        CacheEntry(const sp<Blob>& key, const sp<Blob>& value);
+        CacheEntry(const CacheEntry& ce);
+
+        bool operator<(const CacheEntry& rhs) const;
+        const CacheEntry& operator=(const CacheEntry&);
+
+        sp<Blob> getKey() const;
+        sp<Blob> getValue() const;
+
+        void setValue(const sp<Blob>& value);
+
+    private:
+
+        // mKey is the key that identifies the cache entry.
+        sp<Blob> mKey;
+
+        // mValue is the cached data associated with the key.
+        sp<Blob> mValue;
+    };
+
+    // mMaxKeySize is the maximum key size that will be cached. Calls to
+    // BlobCache::set with a keySize parameter larger than mMaxKeySize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxKeySize;
+
+    // mMaxValueSize is the maximum value size that will be cached. Calls to
+    // BlobCache::set with a valueSize parameter larger than mMaxValueSize will
+    // simply not add the key/value pair to the cache.
+    const size_t mMaxValueSize;
+
+    // mMaxTotalSize is the maximum size that all cache entries can occupy. This
+    // includes space for both keys and values. When a call to BlobCache::set
+    // would otherwise cause this limit to be exceeded, either the key/value
+    // pair passed to BlobCache::set will not be cached or other cache entries
+    // will be evicted from the cache to make room for the new entry.
+    const size_t mMaxTotalSize;
+
+    // mTotalSize is the total combined size of all keys and values currently in
+    // the cache.
+    size_t mTotalSize;
+
+    // mRandState is the pseudo-random number generator state. It is passed to
+    // nrand48 to generate random numbers when needed. It must be protected by
+    // mMutex.
+    unsigned short mRandState[3];
+
+    // mCacheEntries stores all the cache entries that are resident in memory.
+    // Cache entries are added to it by the 'set' method.
+    SortedVector<CacheEntry> mCacheEntries;
+
+    // mMutex is used to synchronize access to all member variables.  It must be
+    // locked any time the member variables are written or read.
+    Mutex mMutex;
+};
+
+}
+
+#endif // ANDROID_BLOB_CACHE_H
diff --git a/include/utils/LinearTransform.h b/include/utils/LinearTransform.h
new file mode 100644
index 0000000..04cb355
--- /dev/null
+++ b/include/utils/LinearTransform.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 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 _LIBS_UTILS_LINEAR_TRANSFORM_H
+#define _LIBS_UTILS_LINEAR_TRANSFORM_H
+
+#include <stdint.h>
+
+namespace android {
+
+// LinearTransform defines a structure which hold the definition of a
+// transformation from single dimensional coordinate system A into coordinate
+// system B (and back again).  Values in A and in B are 64 bit, the linear
+// scale factor is expressed as a rational number using two 32 bit values.
+//
+// Specifically, let
+// f(a) = b
+// F(b) = f^-1(b) = a
+// then
+//
+// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
+//
+// and
+//
+// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
+//
+struct LinearTransform {
+  int64_t  a_zero;
+  int64_t  b_zero;
+  int32_t  a_to_b_numer;
+  uint32_t a_to_b_denom;
+
+  // Transform from A->B
+  // Returns true on success, or false in the case of a singularity or an
+  // overflow.
+  bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
+
+  // Transform from B->A
+  // Returns true on success, or false in the case of a singularity or an
+  // overflow.
+  bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
+
+  // Helpers which will reduce the fraction N/D using Euclid's method.
+  template <class T> static void reduce(T* N, T* D);
+  static void reduce(int32_t* N, uint32_t* D);
+};
+
+
+}
+
+#endif  // _LIBS_UTILS_LINEAR_TRANSFORM_H
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 4126225..ca17082 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -116,17 +116,24 @@
 
     typedef RefBase basetype;
 
+    // used to override the RefBase destruction.
+    class Destroyer {
+        friend class RefBase;
+        friend class weakref_type;
+    public:
+        virtual ~Destroyer();
+    private:
+        virtual void destroy(RefBase const* base) = 0;
+    };
+
+    // Make sure to never acquire a strong reference from this function. The
+    // same restrictions than for destructors apply.
+    void setDestroyer(Destroyer* destroyer);
+
 protected:
                             RefBase();
     virtual                 ~RefBase();
 
-    // called when the last reference goes away. this is responsible for
-    // calling the destructor. The default implementation just does
-    // "delete this;".
-    // Make sure to never acquire a strong reference from this function. The
-    // same restrictions than for destructors apply.
-    virtual void            destroy() const;
-
     //! Flags for extendObjectLifetime()
     enum {
         OBJECT_LIFETIME_WEAK    = 0x0001,
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 2c7cf75..612ff93 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -841,6 +841,7 @@
         DENSITY_DEFAULT = ACONFIGURATION_DENSITY_DEFAULT,
         DENSITY_LOW = ACONFIGURATION_DENSITY_LOW,
         DENSITY_MEDIUM = ACONFIGURATION_DENSITY_MEDIUM,
+        DENSITY_TV = ACONFIGURATION_DENSITY_TV,
         DENSITY_HIGH = ACONFIGURATION_DENSITY_HIGH,
         DENSITY_NONE = ACONFIGURATION_DENSITY_NONE
     };
@@ -1452,24 +1453,20 @@
     // settings is the requested settings
     inline bool match(const ResTable_config& settings) const {
         if (imsi != 0) {
-            if ((settings.mcc != 0 && mcc != 0
-                 && mcc != settings.mcc) || 
-                (settings.mcc == 0 && mcc != 0)) {
+            if (mcc != 0 && mcc != settings.mcc) {
                 return false;
             }
-            if ((settings.mnc != 0 && mnc != 0
-                 && mnc != settings.mnc) ||
-                (settings.mnc == 0 && mnc != 0)) {
+            if (mnc != 0 && mnc != settings.mnc) {
                 return false;
             }
         }
         if (locale != 0) {
-            if (settings.language[0] != 0 && language[0] != 0
+            if (language[0] != 0
                 && (language[0] != settings.language[0]
                     || language[1] != settings.language[1])) {
                 return false;
             }
-            if (settings.country[0] != 0 && country[0] != 0
+            if (country[0] != 0
                 && (country[0] != settings.country[0]
                     || country[1] != settings.country[1])) {
                 return false;
@@ -1480,66 +1477,56 @@
             const int setScreenSize = settings.screenLayout&MASK_SCREENSIZE;
             // Any screen sizes for larger screens than the setting do not
             // match.
-            if ((setScreenSize != 0 && screenSize != 0
-                    && screenSize > setScreenSize) ||
-                    (setScreenSize == 0 && screenSize != 0)) {
+            if (screenSize != 0 && screenSize > setScreenSize) {
                 return false;
             }
             
             const int screenLong = screenLayout&MASK_SCREENLONG;
             const int setScreenLong = settings.screenLayout&MASK_SCREENLONG;
-            if (setScreenLong != 0 && screenLong != 0
-                    && screenLong != setScreenLong) {
+            if (screenLong != 0 && screenLong != setScreenLong) {
                 return false;
             }
 
             const int uiModeType = uiMode&MASK_UI_MODE_TYPE;
             const int setUiModeType = settings.uiMode&MASK_UI_MODE_TYPE;
-            if (setUiModeType != 0 && uiModeType != 0
-                    && uiModeType != setUiModeType) {
+            if (uiModeType != 0 && uiModeType != setUiModeType) {
                 return false;
             }
 
             const int uiModeNight = uiMode&MASK_UI_MODE_NIGHT;
             const int setUiModeNight = settings.uiMode&MASK_UI_MODE_NIGHT;
-            if (setUiModeNight != 0 && uiModeNight != 0
-                    && uiModeNight != setUiModeNight) {
+            if (uiModeNight != 0 && uiModeNight != setUiModeNight) {
                 return false;
             }
 
-            if (settings.smallestScreenWidthDp != 0 && smallestScreenWidthDp != 0
+            if (smallestScreenWidthDp != 0
                     && smallestScreenWidthDp > settings.smallestScreenWidthDp) {
                 return false;
             }
         }
         if (screenSizeDp != 0) {
-            if (settings.screenWidthDp != 0 && screenWidthDp != 0
-                    && screenWidthDp > settings.screenWidthDp) {
+            if (screenWidthDp != 0 && screenWidthDp > settings.screenWidthDp) {
                 //LOGI("Filtering out width %d in requested %d", screenWidthDp, settings.screenWidthDp);
                 return false;
             }
-            if (settings.screenHeightDp != 0 && screenHeightDp != 0
-                    && screenHeightDp > settings.screenHeightDp) {
+            if (screenHeightDp != 0 && screenHeightDp > settings.screenHeightDp) {
                 //LOGI("Filtering out height %d in requested %d", screenHeightDp, settings.screenHeightDp);
                 return false;
             }
         }
         if (screenType != 0) {
-            if (settings.orientation != 0 && orientation != 0
-                && orientation != settings.orientation) {
+            if (orientation != 0 && orientation != settings.orientation) {
                 return false;
             }
             // density always matches - we can scale it.  See isBetterThan
-            if (settings.touchscreen != 0 && touchscreen != 0
-                && touchscreen != settings.touchscreen) {
+            if (touchscreen != 0 && touchscreen != settings.touchscreen) {
                 return false;
             }
         }
         if (input != 0) {
             const int keysHidden = inputFlags&MASK_KEYSHIDDEN;
             const int setKeysHidden = settings.inputFlags&MASK_KEYSHIDDEN;
-            if (setKeysHidden != 0 && keysHidden != 0
-                && keysHidden != setKeysHidden) {
+            if (keysHidden != 0 && keysHidden != setKeysHidden) {
                 // For compatibility, we count a request for KEYSHIDDEN_NO as also
                 // matching the more recent KEYSHIDDEN_SOFT.  Basically
                 // KEYSHIDDEN_NO means there is some kind of keyboard available.
@@ -1551,36 +1538,29 @@
             }
             const int navHidden = inputFlags&MASK_NAVHIDDEN;
             const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
-            if (setNavHidden != 0 && navHidden != 0
-                && navHidden != setNavHidden) {
+            if (navHidden != 0 && navHidden != setNavHidden) {
                 return false;
             }
-            if (settings.keyboard != 0 && keyboard != 0
-                && keyboard != settings.keyboard) {
+            if (keyboard != 0 && keyboard != settings.keyboard) {
                 return false;
             }
-            if (settings.navigation != 0 && navigation != 0
-                && navigation != settings.navigation) {
+            if (navigation != 0 && navigation != settings.navigation) {
                 return false;
             }
         }
         if (screenSize != 0) {
-            if (settings.screenWidth != 0 && screenWidth != 0
-                && screenWidth > settings.screenWidth) {
+            if (screenWidth != 0 && screenWidth > settings.screenWidth) {
                 return false;
             }
-            if (settings.screenHeight != 0 && screenHeight != 0
-                && screenHeight > settings.screenHeight) {
+            if (screenHeight != 0 && screenHeight > settings.screenHeight) {
                 return false;
             }
         }
         if (version != 0) {
-            if (settings.sdkVersion != 0 && sdkVersion != 0
-                && sdkVersion > settings.sdkVersion) {
+            if (sdkVersion != 0 && sdkVersion > settings.sdkVersion) {
                 return false;
             }
-            if (settings.minorVersion != 0 && minorVersion != 0
-                && minorVersion != settings.minorVersion) {
+            if (minorVersion != 0 && minorVersion != settings.minorVersion) {
                 return false;
             }
         }
@@ -2008,7 +1988,8 @@
                                   String16* outName,
                                   const String16* defType = NULL,
                                   const String16* defPackage = NULL,
-                                  const char** outErrorMsg = NULL);
+                                  const char** outErrorMsg = NULL,
+                                  bool* outPublicOnly = NULL);
 
     static bool stringToInt(const char16_t* s, size_t len, Res_value* outValue);
     static bool stringToFloat(const char16_t* s, size_t len, Res_value* outValue);
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 8beec57..0e98aeb 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -32,6 +32,8 @@
 template <class TYPE>
 class SortedVector : private SortedVectorImpl
 {
+    friend class Vector<TYPE>;
+
 public:
             typedef TYPE    value_type;
     
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index f1e87e6..b908e2a 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -29,6 +29,9 @@
 
 namespace android {
 
+template <typename TYPE>
+class SortedVector;
+
 /*!
  * The main templated vector class ensuring type safety
  * while making use of VectorImpl.
@@ -47,13 +50,17 @@
     
                             Vector();
                             Vector(const Vector<TYPE>& rhs);
+    explicit                Vector(const SortedVector<TYPE>& rhs);
     virtual                 ~Vector();
 
     /*! copy operator */
             const Vector<TYPE>&     operator = (const Vector<TYPE>& rhs) const;
             Vector<TYPE>&           operator = (const Vector<TYPE>& rhs);    
 
-    /*
+            const Vector<TYPE>&     operator = (const SortedVector<TYPE>& rhs) const;
+            Vector<TYPE>&           operator = (const SortedVector<TYPE>& rhs);
+
+            /*
      * empty the vector
      */
 
@@ -215,6 +222,11 @@
 }
 
 template<class TYPE> inline
+Vector<TYPE>::Vector(const SortedVector<TYPE>& rhs)
+    : VectorImpl(static_cast<const VectorImpl&>(rhs)) {
+}
+
+template<class TYPE> inline
 Vector<TYPE>::~Vector() {
     finish_vector();
 }
@@ -227,6 +239,18 @@
 
 template<class TYPE> inline
 const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
+    VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+    return *this;
+}
+
+template<class TYPE> inline
+Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+    VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+    return *this;
+}
+
+template<class TYPE> inline
+const Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
     VectorImpl::operator = (rhs);
     return *this; 
 }
diff --git a/include/utils/threads.h b/include/utils/threads.h
index 41e5766..0bd69cf 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -526,6 +526,7 @@
     Thread& operator=(const Thread&);
     static  int             _threadLoop(void* user);
     const   bool            mCanCallJava;
+    // always hold mLock when reading or writing
             thread_id_t     mThread;
     mutable Mutex           mLock;
             Condition       mThreadExitedCondition;
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index f9d9f25..3a12e96 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -27,7 +27,7 @@
     MemoryHeapBase.cpp \
     MemoryHeapPmem.cpp \
     Parcel.cpp \
-    Permission.cpp \
+    PermissionCache.cpp \
     ProcessState.cpp \
     Static.cpp
 
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index bc8c412..1ace8f8 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -42,11 +42,11 @@
 public:
     HeapCache();
     virtual ~HeapCache();
-    
+
     virtual void binderDied(const wp<IBinder>& who);
 
-    sp<IMemoryHeap> find_heap(const sp<IBinder>& binder); 
-    void free_heap(const sp<IBinder>& binder); 
+    sp<IMemoryHeap> find_heap(const sp<IBinder>& binder);
+    void free_heap(const sp<IBinder>& binder);
     sp<IMemoryHeap> get_heap(const sp<IBinder>& binder);
     void dump_heaps();
 
@@ -57,7 +57,7 @@
         int32_t         count;
     };
 
-    void free_heap(const wp<IBinder>& binder); 
+    void free_heap(const wp<IBinder>& binder);
 
     Mutex mHeapCacheLock;
     KeyedVector< wp<IBinder>, heap_info_t > mHeapCache;
@@ -81,11 +81,12 @@
     virtual void* getBase() const;
     virtual size_t getSize() const;
     virtual uint32_t getFlags() const;
+    virtual uint32_t getOffset() const;
 
 private:
     friend class IMemory;
     friend class HeapCache;
-    
+
     // for debugging in this module
     static inline sp<IMemoryHeap> find_heap(const sp<IBinder>& binder) {
         return gHeapCache->find_heap(binder);
@@ -97,7 +98,7 @@
         return gHeapCache->get_heap(binder);
     }
     static inline void dump_heaps() {
-        gHeapCache->dump_heaps();       
+        gHeapCache->dump_heaps();
     }
 
     void assertMapped() const;
@@ -107,6 +108,7 @@
     mutable void*       mBase;
     mutable size_t      mSize;
     mutable uint32_t    mFlags;
+    mutable uint32_t    mOffset;
     mutable bool        mRealHeap;
     mutable Mutex       mLock;
 };
@@ -123,7 +125,7 @@
     BpMemory(const sp<IBinder>& impl);
     virtual ~BpMemory();
     virtual sp<IMemoryHeap> getMemory(ssize_t* offset=0, size_t* size=0) const;
-    
+
 private:
     mutable sp<IMemoryHeap> mHeap;
     mutable ssize_t mOffset;
@@ -203,7 +205,7 @@
 BnMemory::BnMemory() {
 }
 
-BnMemory::~BnMemory() { 
+BnMemory::~BnMemory() {
 }
 
 status_t BnMemory::onTransact(
@@ -229,7 +231,7 @@
 
 BpMemoryHeap::BpMemoryHeap(const sp<IBinder>& impl)
     : BpInterface<IMemoryHeap>(impl),
-        mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mRealHeap(false)
+        mHeapId(-1), mBase(MAP_FAILED), mSize(0), mFlags(0), mOffset(0), mRealHeap(false)
 {
 }
 
@@ -242,7 +244,7 @@
                 sp<IBinder> binder = const_cast<BpMemoryHeap*>(this)->asBinder();
 
                 if (VERBOSE) {
-                    LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d", 
+                    LOGD("UNMAPPING binder=%p, heap=%p, size=%d, fd=%d",
                             binder.get(), this, mSize, mHeapId);
                     CallStack stack;
                     stack.update();
@@ -270,6 +272,7 @@
             if (mHeapId == -1) {
                 mBase   = heap->mBase;
                 mSize   = heap->mSize;
+                mOffset = heap->mOffset;
                 android_atomic_write( dup( heap->mHeapId ), &mHeapId );
             }
         } else {
@@ -286,13 +289,14 @@
         // remote call without mLock held, worse case scenario, we end up
         // calling transact() from multiple threads, but that's not a problem,
         // only mmap below must be in the critical section.
-        
+
         Parcel data, reply;
         data.writeInterfaceToken(IMemoryHeap::getInterfaceDescriptor());
         status_t err = remote()->transact(HEAP_ID, data, &reply);
         int parcel_fd = reply.readFileDescriptor();
         ssize_t size = reply.readInt32();
         uint32_t flags = reply.readInt32();
+        uint32_t offset = reply.readInt32();
 
         LOGE_IF(err, "binder=%p transaction failed fd=%d, size=%ld, err=%d (%s)",
                 asBinder().get(), parcel_fd, size, err, strerror(-err));
@@ -309,7 +313,7 @@
         Mutex::Autolock _l(mLock);
         if (mHeapId == -1) {
             mRealHeap = true;
-            mBase = mmap(0, size, access, MAP_SHARED, fd, 0);
+            mBase = mmap(0, size, access, MAP_SHARED, fd, offset);
             if (mBase == MAP_FAILED) {
                 LOGE("cannot map BpMemoryHeap (binder=%p), size=%ld, fd=%d (%s)",
                         asBinder().get(), size, fd, strerror(errno));
@@ -317,6 +321,7 @@
             } else {
                 mSize = size;
                 mFlags = flags;
+                mOffset = offset;
                 android_atomic_write(fd, &mHeapId);
             }
         }
@@ -343,14 +348,19 @@
     return mFlags;
 }
 
+uint32_t BpMemoryHeap::getOffset() const {
+    assertMapped();
+    return mOffset;
+}
+
 // ---------------------------------------------------------------------------
 
 IMPLEMENT_META_INTERFACE(MemoryHeap, "android.utils.IMemoryHeap");
 
-BnMemoryHeap::BnMemoryHeap() { 
+BnMemoryHeap::BnMemoryHeap() {
 }
 
-BnMemoryHeap::~BnMemoryHeap() { 
+BnMemoryHeap::~BnMemoryHeap() {
 }
 
 status_t BnMemoryHeap::onTransact(
@@ -362,6 +372,7 @@
             reply->writeFileDescriptor(getHeapID());
             reply->writeInt32(getSize());
             reply->writeInt32(getFlags());
+            reply->writeInt32(getOffset());
             return NO_ERROR;
         } break;
         default:
@@ -383,17 +394,17 @@
 void HeapCache::binderDied(const wp<IBinder>& binder)
 {
     //LOGD("binderDied binder=%p", binder.unsafe_get());
-    free_heap(binder); 
+    free_heap(binder);
 }
 
-sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder) 
+sp<IMemoryHeap> HeapCache::find_heap(const sp<IBinder>& binder)
 {
     Mutex::Autolock _l(mHeapCacheLock);
     ssize_t i = mHeapCache.indexOfKey(binder);
     if (i>=0) {
         heap_info_t& info = mHeapCache.editValueAt(i);
         LOGD_IF(VERBOSE,
-                "found binder=%p, heap=%p, size=%d, fd=%d, count=%d", 
+                "found binder=%p, heap=%p, size=%d, fd=%d, count=%d",
                 binder.get(), info.heap.get(),
                 static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
                 static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
@@ -415,7 +426,7 @@
     free_heap( wp<IBinder>(binder) );
 }
 
-void HeapCache::free_heap(const wp<IBinder>& binder) 
+void HeapCache::free_heap(const wp<IBinder>& binder)
 {
     sp<IMemoryHeap> rel;
     {
@@ -426,7 +437,7 @@
             int32_t c = android_atomic_dec(&info.count);
             if (c == 1) {
                 LOGD_IF(VERBOSE,
-                        "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d", 
+                        "removing binder=%p, heap=%p, size=%d, fd=%d, count=%d",
                         binder.unsafe_get(), info.heap.get(),
                         static_cast<BpMemoryHeap*>(info.heap.get())->mSize,
                         static_cast<BpMemoryHeap*>(info.heap.get())->mHeapId,
@@ -450,7 +461,7 @@
     return realHeap;
 }
 
-void HeapCache::dump_heaps() 
+void HeapCache::dump_heaps()
 {
     Mutex::Autolock _l(mHeapCacheLock);
     int c = mHeapCache.size();
@@ -459,7 +470,7 @@
         BpMemoryHeap const* h(static_cast<BpMemoryHeap const *>(info.heap.get()));
         LOGD("hey=%p, heap=%p, count=%d, (fd=%d, base=%p, size=%d)",
                 mHeapCache.keyAt(i).unsafe_get(),
-                info.heap.get(), info.count, 
+                info.heap.get(), info.count,
                 h->mHeapId, h->mBase, h->mSize);
     }
 }
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index 9f501e2..bf4a73f 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -40,15 +40,15 @@
 
 // ---------------------------------------------------------------------------
 
-MemoryHeapBase::MemoryHeapBase() 
+MemoryHeapBase::MemoryHeapBase()
     : mFD(-1), mSize(0), mBase(MAP_FAILED),
-      mDevice(NULL), mNeedUnmap(false) 
+      mDevice(NULL), mNeedUnmap(false), mOffset(0)
 {
 }
 
 MemoryHeapBase::MemoryHeapBase(size_t size, uint32_t flags, char const * name)
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
-      mDevice(0), mNeedUnmap(false)
+      mDevice(0), mNeedUnmap(false), mOffset(0)
 {
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
@@ -65,7 +65,7 @@
 
 MemoryHeapBase::MemoryHeapBase(const char* device, size_t size, uint32_t flags)
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
-      mDevice(0), mNeedUnmap(false)
+      mDevice(0), mNeedUnmap(false), mOffset(0)
 {
     int open_flags = O_RDWR;
     if (flags & NO_CACHING)
@@ -84,7 +84,7 @@
 
 MemoryHeapBase::MemoryHeapBase(int fd, size_t size, uint32_t flags, uint32_t offset)
     : mFD(-1), mSize(0), mBase(MAP_FAILED), mFlags(flags),
-      mDevice(0), mNeedUnmap(false)
+      mDevice(0), mNeedUnmap(false), mOffset(0)
 {
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
@@ -141,6 +141,7 @@
     }
     mFD = fd;
     mSize = size;
+    mOffset = offset;
     return NO_ERROR;
 }
 
@@ -183,5 +184,9 @@
     return mDevice;
 }
 
+uint32_t MemoryHeapBase::getOffset() const {
+    return mOffset;
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/binder/Permission.cpp b/libs/binder/Permission.cpp
deleted file mode 100644
index fd8fe69..0000000
--- a/libs/binder/Permission.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#include <stdint.h>
-#include <utils/Log.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/Permission.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-Permission::Permission(char const* name)
-    : mPermissionName(name), mPid(getpid())
-{
-}
-
-Permission::Permission(const String16& name)
-    : mPermissionName(name), mPid(getpid())
-{
-}
-
-Permission::Permission(const Permission& rhs)
-    : mPermissionName(rhs.mPermissionName),
-    mGranted(rhs.mGranted),
-    mPid(rhs.mPid)
-{
-}
-
-Permission::~Permission()
-{
-}
-
-bool Permission::operator < (const Permission& rhs) const
-{
-    return mPermissionName < rhs.mPermissionName;
-}
-
-bool Permission::checkCalling() const
-{
-    IPCThreadState* ipcState = IPCThreadState::self();
-    pid_t pid = ipcState->getCallingPid();
-    uid_t uid = ipcState->getCallingUid();
-    return doCheckPermission(pid, uid);
-}
-
-bool Permission::check(pid_t pid, uid_t uid) const
-{
-    return doCheckPermission(pid, uid);
-}
-
-bool Permission::doCheckPermission(pid_t pid, uid_t uid) const
-{
-    if ((uid == 0) || (pid == mPid)) {
-        // root and ourselves is always okay
-        return true;
-    } else {
-        // see if we already granted this permission for this uid
-        Mutex::Autolock _l(mLock);
-        if (mGranted.indexOf(uid) >= 0)
-            return true;
-    }
-
-    bool granted = checkPermission(mPermissionName, pid, uid);
-    if (granted) {
-        Mutex::Autolock _l(mLock);
-        // no need to check again, the old item will be replaced if it is
-        // already there.
-        mGranted.add(uid);
-    }
-    return granted;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/binder/PermissionCache.cpp b/libs/binder/PermissionCache.cpp
new file mode 100644
index 0000000..7278187
--- /dev/null
+++ b/libs/binder/PermissionCache.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2009 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 "PermissionCache"
+
+#include <stdint.h>
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+ANDROID_SINGLETON_STATIC_INSTANCE(PermissionCache) ;
+
+// ----------------------------------------------------------------------------
+
+PermissionCache::PermissionCache() {
+}
+
+status_t PermissionCache::check(bool* granted,
+        const String16& permission, uid_t uid) const {
+    Mutex::Autolock _l(mLock);
+    Entry e;
+    e.name = permission;
+    e.uid  = uid;
+    ssize_t index = mCache.indexOf(e);
+    if (index >= 0) {
+        *granted = mCache.itemAt(index).granted;
+        return NO_ERROR;
+    }
+    return NAME_NOT_FOUND;
+}
+
+void PermissionCache::cache(const String16& permission,
+        uid_t uid, bool granted) {
+    Mutex::Autolock _l(mLock);
+    Entry e;
+    ssize_t index = mPermissionNamesPool.indexOf(permission);
+    if (index > 0) {
+        e.name = mPermissionNamesPool.itemAt(index);
+    } else {
+        mPermissionNamesPool.add(permission);
+        e.name = permission;
+    }
+    // note, we don't need to store the pid, which is not actually used in
+    // permission checks
+    e.uid  = uid;
+    e.granted = granted;
+    index = mCache.indexOf(e);
+    if (index < 0) {
+        mCache.add(e);
+    }
+}
+
+void PermissionCache::purge() {
+    Mutex::Autolock _l(mLock);
+    mCache.clear();
+}
+
+bool PermissionCache::checkCallingPermission(const String16& permission) {
+    return PermissionCache::checkCallingPermission(permission, NULL, NULL);
+}
+
+bool PermissionCache::checkCallingPermission(
+        const String16& permission, int32_t* outPid, int32_t* outUid) {
+    IPCThreadState* ipcState = IPCThreadState::self();
+    pid_t pid = ipcState->getCallingPid();
+    uid_t uid = ipcState->getCallingUid();
+    if (outPid) *outPid = pid;
+    if (outUid) *outUid = uid;
+    return PermissionCache::checkPermission(permission, pid, uid);
+}
+
+bool PermissionCache::checkPermission(
+        const String16& permission, pid_t pid, uid_t uid) {
+    if ((uid == 0) || (pid == getpid())) {
+        // root and ourselves is always okay
+        return true;
+    }
+
+    PermissionCache& pc(PermissionCache::getInstance());
+    bool granted = false;
+    if (pc.check(&granted, permission, uid) != NO_ERROR) {
+        nsecs_t t = -systemTime();
+        granted = android::checkPermission(permission, pid, uid);
+        t += systemTime();
+        LOGD("checking %s for uid=%d => %s (%d us)",
+                String8(permission).string(), uid,
+                granted?"granted":"denied", (int)ns2us(t));
+        pc.cache(permission, uid, granted);
+    }
+    return granted;
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index b5737ff..4070eba 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -16,7 +16,6 @@
 	ISurfaceComposerClient.cpp \
 	IGraphicBufferAlloc.cpp \
 	LayerState.cpp \
-	SharedBufferStack.cpp \
 	Surface.cpp \
 	SurfaceComposerClient.cpp \
 
diff --git a/libs/gui/ISurface.cpp b/libs/gui/ISurface.cpp
index 23b90af..96155d7 100644
--- a/libs/gui/ISurface.cpp
+++ b/libs/gui/ISurface.cpp
@@ -22,9 +22,7 @@
 
 #include <binder/Parcel.h>
 
-#include <ui/GraphicBuffer.h>
-
-#include <surfaceflinger/Surface.h>
+#include <gui/ISurfaceTexture.h>
 #include <surfaceflinger/ISurface.h>
 
 namespace android {
@@ -39,30 +37,11 @@
     {
     }
 
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-    {
+    virtual sp<ISurfaceTexture> getSurfaceTexture() const {
         Parcel data, reply;
         data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
-        data.writeInt32(bufferIdx);
-        data.writeInt32(w);
-        data.writeInt32(h);
-        data.writeInt32(format);
-        data.writeInt32(usage);
-        remote()->transact(REQUEST_BUFFER, data, &reply);
-        sp<GraphicBuffer> buffer = new GraphicBuffer();
-        reply.read(*buffer);
-        return buffer;
-    }
-
-    virtual status_t setBufferCount(int bufferCount)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurface::getInterfaceDescriptor());
-        data.writeInt32(bufferCount);
-        remote()->transact(SET_BUFFER_COUNT, data, &reply);
-        status_t err = reply.readInt32();
-        return err;
+        remote()->transact(GET_SURFACE_TEXTURE, data, &reply);
+        return interface_cast<ISurfaceTexture>(reply.readStrongBinder());
     }
 };
 
@@ -74,23 +53,9 @@
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
     switch(code) {
-        case REQUEST_BUFFER: {
+        case GET_SURFACE_TEXTURE: {
             CHECK_INTERFACE(ISurface, data, reply);
-            int bufferIdx = data.readInt32();
-            uint32_t w = data.readInt32();
-            uint32_t h = data.readInt32();
-            uint32_t format = data.readInt32();
-            uint32_t usage = data.readInt32();
-            sp<GraphicBuffer> buffer(requestBuffer(bufferIdx, w, h, format, usage));
-            if (buffer == NULL)
-                return BAD_VALUE;
-            return reply->write(*buffer);
-        }
-        case SET_BUFFER_COUNT: {
-            CHECK_INTERFACE(ISurface, data, reply);
-            int bufferCount = data.readInt32();
-            status_t err = setBufferCount(bufferCount);
-            reply->writeInt32(err);
+            reply->writeStrongBinder( getSurfaceTexture()->asBinder() );
             return NO_ERROR;
         }
         default:
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 8951c3f..c1156d5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,6 +25,8 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 
+#include <private/surfaceflinger/LayerState.h>
+
 #include <surfaceflinger/ISurfaceComposer.h>
 
 #include <ui/DisplayInfo.h>
@@ -57,15 +59,6 @@
         return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
     }
 
-    virtual sp<ISurfaceComposerClient> createClientConnection()
-    {
-        uint32_t n;
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::CREATE_CLIENT_CONNECTION, data, &reply);
-        return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder());
-    }
-
     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc()
     {
         uint32_t n;
@@ -83,18 +76,17 @@
         return interface_cast<IMemoryHeap>(reply.readStrongBinder());
     }
 
-    virtual void openGlobalTransaction()
+    virtual void setTransactionState(const Vector<ComposerState>& state)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply);
-    }
-
-    virtual void closeGlobalTransaction()
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply);
+        Vector<ComposerState>::const_iterator b(state.begin());
+        Vector<ComposerState>::const_iterator e(state.end());
+        data.writeInt32(state.size());
+        for ( ; b != e ; ++b ) {
+            b->write(data);
+        }
+        remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
     virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags)
@@ -174,13 +166,6 @@
         return reply.readInt32();
     }
 
-    virtual void signal() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
-        remote()->transact(BnSurfaceComposer::SIGNAL, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
     virtual bool authenticateSurface(const sp<ISurface>& surface) const
     {
         Parcel data, reply;
@@ -229,23 +214,22 @@
             sp<IBinder> b = createConnection()->asBinder();
             reply->writeStrongBinder(b);
         } break;
-        case CREATE_CLIENT_CONNECTION: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            sp<IBinder> b = createClientConnection()->asBinder();
-            reply->writeStrongBinder(b);
-        } break;
         case CREATE_GRAPHIC_BUFFER_ALLOC: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
             reply->writeStrongBinder(b);
         } break;
-        case OPEN_GLOBAL_TRANSACTION: {
+        case SET_TRANSACTION_STATE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            openGlobalTransaction();
-        } break;
-        case CLOSE_GLOBAL_TRANSACTION: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            closeGlobalTransaction();
+            size_t count = data.readInt32();
+            ComposerState s;
+            Vector<ComposerState> state;
+            state.setCapacity(count);
+            for (size_t i=0 ; i<count ; i++) {
+                s.read(data);
+                state.add(s);
+            }
+            setTransactionState(state);
         } break;
         case SET_ORIENTATION: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
@@ -270,10 +254,6 @@
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             bootFinished();
         } break;
-        case SIGNAL: {
-            CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            signal();
-        } break;
         case GET_CBLK: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> b = getCblk()->asBinder();
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index ea38e08..bc97cac 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -50,11 +50,8 @@
 namespace android {
 
 enum {
-    GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
-    GET_TOKEN,
-    CREATE_SURFACE,
-    DESTROY_SURFACE,
-    SET_STATE
+    CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
+    DESTROY_SURFACE
 };
 
 class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
@@ -65,23 +62,6 @@
     {
     }
 
-    virtual sp<IMemoryHeap> getControlBlock() const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        remote()->transact(GET_CBLK, data, &reply);
-        return interface_cast<IMemoryHeap>(reply.readStrongBinder());
-    }
-
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeStrongBinder(sur->asBinder());
-        remote()->transact(GET_TOKEN, data, &reply);
-        return reply.readInt32();
-    }
-
     virtual sp<ISurface> createSurface( surface_data_t* params,
                                         const String8& name,
                                         DisplayID display,
@@ -111,17 +91,6 @@
         remote()->transact(DESTROY_SURFACE, data, &reply);
         return reply.readInt32();
     }
-
-    virtual status_t setState(int32_t count, const layer_state_t* states)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
-        data.writeInt32(count);
-        for (int i=0 ; i<count ; i++)
-            states[i].write(data);
-        remote()->transact(SET_STATE, data, &reply);
-        return reply.readInt32();
-    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
@@ -131,41 +100,6 @@
 status_t BnSurfaceComposerClient::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
-    // codes that don't require permission check
-
-    switch(code) {
-        case GET_CBLK: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<IMemoryHeap> ctl(getControlBlock());
-            reply->writeStrongBinder(ctl->asBinder());
-            return NO_ERROR;
-        } break;
-        case GET_TOKEN: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            sp<ISurface> sur = interface_cast<ISurface>(data.readStrongBinder());
-            ssize_t token = getTokenForSurface(sur);
-            reply->writeInt32(token);
-            return NO_ERROR;
-        } break;
-    }
-
-    // these must be checked
-
-     IPCThreadState* ipc = IPCThreadState::self();
-     const int pid = ipc->getCallingPid();
-     const int uid = ipc->getCallingUid();
-     const int self_pid = getpid();
-     if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
-         // we're called from a different process, do the real check
-         if (!checkCallingPermission(
-                 String16("android.permission.ACCESS_SURFACE_FLINGER")))
-         {
-             LOGE("Permission Denial: "
-                     "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
-             return PERMISSION_DENIED;
-         }
-     }
-
      switch(code) {
         case CREATE_SURFACE: {
             CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
@@ -187,17 +121,6 @@
             reply->writeInt32( destroySurface( data.readInt32() ) );
             return NO_ERROR;
         } break;
-        case SET_STATE: {
-            CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
-            int32_t count = data.readInt32();
-            layer_state_t* states = new layer_state_t[count];
-            for (int i=0 ; i<count ; i++)
-                states[i].read(data);
-            status_t err = setState(count, states);
-            delete [] states;
-            reply->writeInt32(err);
-            return NO_ERROR;
-        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 01c4c7e..87901e8 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -17,6 +17,7 @@
 #include <utils/Errors.h>
 #include <binder/Parcel.h>
 #include <private/surfaceflinger/LayerState.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
 
 namespace android {
 
@@ -58,4 +59,14 @@
     return NO_ERROR;
 }
 
+status_t ComposerState::write(Parcel& output) const {
+    output.writeStrongBinder(client->asBinder());
+    return state.write(output);
+}
+
+status_t ComposerState::read(const Parcel& input) {
+    client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder());
+    return state.read(input);
+}
+
 }; // namespace android
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index b1f37ff..f9a2c04 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -89,6 +89,14 @@
     return mMinDelay;
 }
 
+nsecs_t Sensor::getMinDelayNs() const {
+    return getMinDelay() * 1000;
+}
+
+int32_t Sensor::getVersion() const {
+    return mVersion;
+}
+
 size_t Sensor::getFlattenedSize() const
 {
     return  sizeof(int32_t) + ((mName.length() + 3) & ~3) +
diff --git a/libs/gui/SharedBufferStack.cpp b/libs/gui/SharedBufferStack.cpp
deleted file mode 100644
index 7505d53..0000000
--- a/libs/gui/SharedBufferStack.cpp
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * 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 "SharedBufferStack"
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Debug.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-
-#include <private/surfaceflinger/SharedBufferStack.h>
-
-#include <ui/Rect.h>
-#include <ui/Region.h>
-
-#define DEBUG_ATOMICS 0
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-SharedClient::SharedClient()
-    : lock(Mutex::SHARED), cv(Condition::SHARED)
-{
-}
-
-SharedClient::~SharedClient() {
-}
-
-
-// these functions are used by the clients
-status_t SharedClient::validate(size_t i) const {
-    if (uint32_t(i) >= uint32_t(SharedBufferStack::NUM_LAYERS_MAX))
-        return BAD_INDEX;
-    return surfaces[i].status;
-}
-
-// ----------------------------------------------------------------------------
-
-
-SharedBufferStack::SharedBufferStack()
-{
-}
-
-void SharedBufferStack::init(int32_t i)
-{
-    status = NO_ERROR;
-    identity = i;
-}
-
-status_t SharedBufferStack::setCrop(int buffer, const Rect& crop)
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return BAD_INDEX;
-
-    buffers[buffer].crop.l = uint16_t(crop.left);
-    buffers[buffer].crop.t = uint16_t(crop.top);
-    buffers[buffer].crop.r = uint16_t(crop.right);
-    buffers[buffer].crop.b = uint16_t(crop.bottom);
-    return NO_ERROR;
-}
-
-status_t SharedBufferStack::setTransform(int buffer, uint8_t transform)
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return BAD_INDEX;
-    buffers[buffer].transform = transform;
-    return NO_ERROR;
-}
-
-status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return BAD_INDEX;
-
-    FlatRegion& reg(buffers[buffer].dirtyRegion);
-    if (dirty.isEmpty()) {
-        reg.count = 0;
-        return NO_ERROR;
-    }
-
-    size_t count;
-    Rect const* r = dirty.getArray(&count);
-    if (count > FlatRegion::NUM_RECT_MAX) {
-        const Rect bounds(dirty.getBounds());
-        reg.count = 1;
-        reg.rects[0].l = uint16_t(bounds.left);
-        reg.rects[0].t = uint16_t(bounds.top);
-        reg.rects[0].r = uint16_t(bounds.right);
-        reg.rects[0].b = uint16_t(bounds.bottom);
-    } else {
-        reg.count = count;
-        for (size_t i=0 ; i<count ; i++) {
-            reg.rects[i].l = uint16_t(r[i].left);
-            reg.rects[i].t = uint16_t(r[i].top);
-            reg.rects[i].r = uint16_t(r[i].right);
-            reg.rects[i].b = uint16_t(r[i].bottom);
-        }
-    }
-    return NO_ERROR;
-}
-
-Region SharedBufferStack::getDirtyRegion(int buffer) const
-{
-    Region res;
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return res;
-
-    const FlatRegion& reg(buffers[buffer].dirtyRegion);
-    if (reg.count > FlatRegion::NUM_RECT_MAX)
-        return res;
-
-    if (reg.count == 1) {
-        const Rect r(
-                reg.rects[0].l,
-                reg.rects[0].t,
-                reg.rects[0].r,
-                reg.rects[0].b);
-        res.set(r);
-    } else {
-        for (size_t i=0 ; i<reg.count ; i++) {
-            const Rect r(
-                    reg.rects[i].l,
-                    reg.rects[i].t,
-                    reg.rects[i].r,
-                    reg.rects[i].b);
-            res.orSelf(r);
-        }
-    }
-    return res;
-}
-
-Rect SharedBufferStack::getCrop(int buffer) const
-{
-    Rect res(-1, -1);
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return res;
-    res.left = buffers[buffer].crop.l;
-    res.top = buffers[buffer].crop.t;
-    res.right = buffers[buffer].crop.r;
-    res.bottom = buffers[buffer].crop.b;
-    return res;
-}
-
-uint32_t SharedBufferStack::getTransform(int buffer) const
-{
-    if (uint32_t(buffer) >= NUM_BUFFER_MAX)
-        return 0;
-    return buffers[buffer].transform;
-}
-
-
-// ----------------------------------------------------------------------------
-
-SharedBufferBase::SharedBufferBase(SharedClient* sharedClient,
-        int surface, int32_t identity)
-    : mSharedClient(sharedClient), 
-      mSharedStack(sharedClient->surfaces + surface),
-      mIdentity(identity)
-{
-}
-
-SharedBufferBase::~SharedBufferBase()
-{
-}
-
-status_t SharedBufferBase::getStatus() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.status;
-}
-
-int32_t SharedBufferBase::getIdentity() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.identity;
-}
-
-String8 SharedBufferBase::dump(char const* prefix) const
-{
-    const size_t SIZE = 1024;
-    char buffer[SIZE];
-    String8 result;
-    SharedBufferStack& stack( *mSharedStack );
-    snprintf(buffer, SIZE, 
-            "%s[ head=%2d, available=%2d, queued=%2d ] "
-            "reallocMask=%08x, identity=%d, status=%d",
-            prefix, stack.head, stack.available, stack.queued,
-            stack.reallocMask, stack.identity, stack.status);
-    result.append(buffer);
-    result.append("\n");
-    return result;
-}
-
-status_t SharedBufferBase::waitForCondition(const ConditionBase& condition)
-{
-    const SharedBufferStack& stack( *mSharedStack );
-    SharedClient& client( *mSharedClient );
-    const nsecs_t TIMEOUT = s2ns(1);
-    const int identity = mIdentity;
-
-    Mutex::Autolock _l(client.lock);
-    while ((condition()==false) &&
-            (stack.identity == identity) &&
-            (stack.status == NO_ERROR))
-    {
-        status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
-        // handle errors and timeouts
-        if (CC_UNLIKELY(err != NO_ERROR)) {
-            if (err == TIMED_OUT) {
-                if (condition()) {
-                    LOGE("waitForCondition(%s) timed out (identity=%d), "
-                        "but condition is true! We recovered but it "
-                        "shouldn't happen." , condition.name(), stack.identity);
-                    break;
-                } else {
-                    LOGW("waitForCondition(%s) timed out "
-                        "(identity=%d, status=%d). "
-                        "CPU may be pegged. trying again.", condition.name(),
-                        stack.identity, stack.status);
-                }
-            } else {
-                LOGE("waitForCondition(%s) error (%s) ",
-                        condition.name(), strerror(-err));
-                return err;
-            }
-        }
-    }
-    return (stack.identity != mIdentity) ? status_t(BAD_INDEX) : stack.status;
-}
-// ============================================================================
-// conditions and updates
-// ============================================================================
-
-SharedBufferClient::DequeueCondition::DequeueCondition(
-        SharedBufferClient* sbc) : ConditionBase(sbc)  { 
-}
-bool SharedBufferClient::DequeueCondition::operator()() const {
-    return stack.available > 0;
-}
-
-SharedBufferClient::LockCondition::LockCondition(
-        SharedBufferClient* sbc, int buf) : ConditionBase(sbc), buf(buf) { 
-}
-bool SharedBufferClient::LockCondition::operator()() const {
-    // NOTE: if stack.head is messed up, we could crash the client
-    // or cause some drawing artifacts. This is okay, as long as it is
-    // limited to the client.
-    return (buf != stack.index[stack.head]);
-}
-
-SharedBufferServer::BuffersAvailableCondition::BuffersAvailableCondition(
-        SharedBufferServer* sbs, int numBuffers) : ConditionBase(sbs),
-        mNumBuffers(numBuffers) {
-}
-bool SharedBufferServer::BuffersAvailableCondition::operator()() const {
-    return stack.available == mNumBuffers;
-}
-
-// ----------------------------------------------------------------------------
-
-SharedBufferClient::QueueUpdate::QueueUpdate(SharedBufferBase* sbb)
-    : UpdateBase(sbb) {    
-}
-ssize_t SharedBufferClient::QueueUpdate::operator()() {
-    android_atomic_inc(&stack.queued);
-    return NO_ERROR;
-}
-
-SharedBufferClient::DequeueUpdate::DequeueUpdate(SharedBufferBase* sbb)
-    : UpdateBase(sbb) {
-}
-ssize_t SharedBufferClient::DequeueUpdate::operator()() {
-    if (android_atomic_dec(&stack.available) == 0) {
-        LOGW("dequeue probably called from multiple threads!");
-    }
-    return NO_ERROR;
-}
-
-SharedBufferClient::CancelUpdate::CancelUpdate(SharedBufferBase* sbb,
-        int tail, int buf)
-    : UpdateBase(sbb), tail(tail), buf(buf) {
-}
-ssize_t SharedBufferClient::CancelUpdate::operator()() {
-    stack.index[tail] = buf;
-    android_atomic_inc(&stack.available);
-    return NO_ERROR;
-}
-
-SharedBufferServer::RetireUpdate::RetireUpdate(
-        SharedBufferBase* sbb, int numBuffers)
-    : UpdateBase(sbb), numBuffers(numBuffers) {
-}
-ssize_t SharedBufferServer::RetireUpdate::operator()() {
-    int32_t head = stack.head;
-    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
-        return BAD_VALUE;
-
-    // Decrement the number of queued buffers 
-    int32_t queued;
-    do {
-        queued = stack.queued;
-        if (queued == 0) {
-            return NOT_ENOUGH_DATA;
-        }
-    } while (android_atomic_cmpxchg(queued, queued-1, &stack.queued));
-    
-    // lock the buffer before advancing head, which automatically unlocks
-    // the buffer we preventively locked upon entering this function
-
-    head = (head + 1) % numBuffers;
-    const int8_t headBuf = stack.index[head];
-    stack.headBuf = headBuf;
-
-    // head is only modified here, so we don't need to use cmpxchg
-    android_atomic_write(head, &stack.head);
-
-    // now that head has moved, we can increment the number of available buffers
-    android_atomic_inc(&stack.available);
-    return head;
-}
-
-SharedBufferServer::StatusUpdate::StatusUpdate(
-        SharedBufferBase* sbb, status_t status)
-    : UpdateBase(sbb), status(status) {
-}
-
-ssize_t SharedBufferServer::StatusUpdate::operator()() {
-    android_atomic_write(status, &stack.status);
-    return NO_ERROR;
-}
-
-// ============================================================================
-
-SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
-        int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, identity),
-      mNumBuffers(num), tail(0)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    tail = computeTail();
-    queued_head = stack.head;
-}
-
-int32_t SharedBufferClient::computeTail() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return (mNumBuffers + stack.head - stack.available + 1) % mNumBuffers;
-}
-
-ssize_t SharedBufferClient::dequeue()
-{
-    SharedBufferStack& stack( *mSharedStack );
-
-    RWLock::AutoRLock _rd(mLock);
-
-    const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
-
-    //LOGD("[%d] about to dequeue a buffer",
-    //        mSharedStack->identity);
-    DequeueCondition condition(this);
-    status_t err = waitForCondition(condition);
-    if (err != NO_ERROR)
-        return ssize_t(err);
-
-    DequeueUpdate update(this);
-    updateCondition( update );
-
-    int dequeued = stack.index[tail];
-    tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
-    LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail++=%d, %s",
-            dequeued, tail, dump("").string());
-
-    mDequeueTime[dequeued] = dequeueTime; 
-
-    return dequeued;
-}
-
-status_t SharedBufferClient::undoDequeue(int buf)
-{
-    return cancel(buf);
-}
-
-status_t SharedBufferClient::cancel(int buf)
-{
-    RWLock::AutoRLock _rd(mLock);
-
-    // calculate the new position of the tail index (essentially tail--)
-    int localTail = (tail + mNumBuffers - 1) % mNumBuffers;
-    CancelUpdate update(this, localTail, buf);
-    status_t err = updateCondition( update );
-    if (err == NO_ERROR) {
-        tail = localTail;
-    }
-    return err;
-}
-
-status_t SharedBufferClient::lock(int buf)
-{
-    RWLock::AutoRLock _rd(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-    LockCondition condition(this, buf);
-    status_t err = waitForCondition(condition);
-    return err;
-}
-
-status_t SharedBufferClient::queue(int buf)
-{
-    RWLock::AutoRLock _rd(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-
-    queued_head = (queued_head + 1) % mNumBuffers;
-    stack.index[queued_head] = buf;
-
-    QueueUpdate update(this);
-    status_t err = updateCondition( update );
-    LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
-
-    const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
-    stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
-
-    return err;
-}
-
-bool SharedBufferClient::needNewBuffer(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    const uint32_t mask = 1<<(31-buf);
-    return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0;
-}
-
-status_t SharedBufferClient::setCrop(int buf, const Rect& crop)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.setCrop(buf, crop);
-}
-
-status_t SharedBufferClient::setTransform(int buf, uint32_t transform)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.setTransform(buf, uint8_t(transform));
-}
-
-status_t SharedBufferClient::setDirtyRegion(int buf, const Region& reg)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.setDirtyRegion(buf, reg);
-}
-
-status_t SharedBufferClient::setBufferCount(
-        int bufferCount, const SetBufferCountCallback& ipc)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    if (uint32_t(bufferCount) >= SharedBufferStack::NUM_BUFFER_MAX)
-        return BAD_VALUE;
-
-    if (uint32_t(bufferCount) < SharedBufferStack::NUM_BUFFER_MIN)
-        return BAD_VALUE;
-
-    RWLock::AutoWLock _wr(mLock);
-
-    status_t err = ipc(bufferCount);
-    if (err == NO_ERROR) {
-        mNumBuffers = bufferCount;
-        queued_head = (stack.head + stack.queued) % mNumBuffers;
-        tail = computeTail();
-    }
-    return err;
-}
-
-// ----------------------------------------------------------------------------
-
-SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
-        int surface, int num, int32_t identity)
-    : SharedBufferBase(sharedClient, surface, identity),
-      mNumBuffers(num)
-{
-    mSharedStack->init(identity);
-    mSharedStack->token = surface;
-    mSharedStack->head = num-1;
-    mSharedStack->available = num;
-    mSharedStack->queued = 0;
-    mSharedStack->reallocMask = 0;
-    memset(mSharedStack->buffers, 0, sizeof(mSharedStack->buffers));
-    for (int i=0 ; i<num ; i++) {
-        mBufferList.add(i);
-        mSharedStack->index[i] = i;
-    }
-}
-
-SharedBufferServer::~SharedBufferServer()
-{
-}
-
-ssize_t SharedBufferServer::retireAndLock()
-{
-    RWLock::AutoRLock _l(mLock);
-
-    RetireUpdate update(this, mNumBuffers);
-    ssize_t buf = updateCondition( update );
-    if (buf >= 0) {
-        if (uint32_t(buf) >= SharedBufferStack::NUM_BUFFER_MAX)
-            return BAD_VALUE;
-        SharedBufferStack& stack( *mSharedStack );
-        buf = stack.index[buf];
-        LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s",
-                int(buf), dump("").string());
-    }
-    return buf;
-}
-
-void SharedBufferServer::setStatus(status_t status)
-{
-    if (status < NO_ERROR) {
-        StatusUpdate update(this, status);
-        updateCondition( update );
-    }
-}
-
-status_t SharedBufferServer::reallocateAll()
-{
-    RWLock::AutoRLock _l(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-    uint32_t mask = mBufferList.getMask();
-    android_atomic_or(mask, &stack.reallocMask);
-    return NO_ERROR;
-}
-
-status_t SharedBufferServer::reallocateAllExcept(int buffer)
-{
-    RWLock::AutoRLock _l(mLock);
-
-    SharedBufferStack& stack( *mSharedStack );
-    BufferList temp(mBufferList);
-    temp.remove(buffer);
-    uint32_t mask = temp.getMask();
-    android_atomic_or(mask, &stack.reallocMask);
-    return NO_ERROR;
-}
-
-int32_t SharedBufferServer::getQueuedCount() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.queued;
-}
-
-Region SharedBufferServer::getDirtyRegion(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.getDirtyRegion(buf);
-}
-
-Rect SharedBufferServer::getCrop(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.getCrop(buf);
-}
-
-uint32_t SharedBufferServer::getTransform(int buf) const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.getTransform(buf);
-}
-
-/*
- * NOTE: this is not thread-safe on the server-side, meaning
- * 'head' cannot move during this operation. The client-side
- * can safely operate an usual.
- *
- */
-status_t SharedBufferServer::resize(int newNumBuffers)
-{
-    if ((unsigned int)(newNumBuffers) < SharedBufferStack::NUM_BUFFER_MIN ||
-        (unsigned int)(newNumBuffers) > SharedBufferStack::NUM_BUFFER_MAX) {
-        return BAD_VALUE;
-    }
-
-    RWLock::AutoWLock _l(mLock);
-
-    if (newNumBuffers < mNumBuffers) {
-        return shrink(newNumBuffers);
-    } else {
-        return grow(newNumBuffers);
-    }
-}
-
-status_t SharedBufferServer::grow(int newNumBuffers)
-{
-    SharedBufferStack& stack( *mSharedStack );
-    const int numBuffers = mNumBuffers;
-    const int extra = newNumBuffers - numBuffers;
-
-    // read the head, make sure it's valid
-    int32_t head = stack.head;
-    if (uint32_t(head) >= SharedBufferStack::NUM_BUFFER_MAX)
-        return BAD_VALUE;
-
-    int base = numBuffers;
-    int32_t avail = stack.available;
-    int tail = head - avail + 1;
-
-    if (tail >= 0) {
-        int8_t* const index = const_cast<int8_t*>(stack.index);
-        const int nb = numBuffers - head;
-        memmove(&index[head + extra], &index[head], nb);
-        base = head;
-        // move head 'extra' ahead, this doesn't impact stack.index[head];
-        stack.head = head + extra;
-    }
-    stack.available += extra;
-
-    // fill the new free space with unused buffers
-    BufferList::const_iterator curr(mBufferList.free_begin());
-    for (int i=0 ; i<extra ; i++) {
-        stack.index[base+i] = *curr;
-        mBufferList.add(*curr);
-        ++curr;
-    }
-
-    mNumBuffers = newNumBuffers;
-    return NO_ERROR;
-}
-
-status_t SharedBufferServer::shrink(int newNumBuffers)
-{
-    SharedBufferStack& stack( *mSharedStack );
-
-    // Shrinking is only supported if there are no buffers currently dequeued.
-    int32_t avail = stack.available;
-    int32_t queued = stack.queued;
-    if (avail + queued != mNumBuffers) {
-        return INVALID_OPERATION;
-    }
-
-    // Wait for any queued buffers to be displayed.
-    BuffersAvailableCondition condition(this, mNumBuffers);
-    status_t err = waitForCondition(condition);
-    if (err < 0) {
-        return err;
-    }
-
-    // Reset head to index 0 and make it refer to buffer 0.  The same renaming
-    // (head -> 0) is done in the BufferManager.
-    int32_t head = stack.head;
-    int8_t* index = const_cast<int8_t*>(stack.index);
-    for (int8_t i = 0; i < newNumBuffers; i++) {
-        index[i] = i;
-    }
-    stack.head = 0;
-    stack.headBuf = 0;
-
-    // Free the buffers from the end of the list that are no longer needed.
-    for (int i = newNumBuffers; i < mNumBuffers; i++) {
-        mBufferList.remove(i);
-    }
-
-    // Tell the client to reallocate all the buffers.
-    reallocateAll();
-
-    mNumBuffers = newNumBuffers;
-    stack.available = newNumBuffers;
-
-    return NO_ERROR;
-}
-
-SharedBufferStack::Statistics SharedBufferServer::getStats() const
-{
-    SharedBufferStack& stack( *mSharedStack );
-    return stack.stats;
-}
-
-// ---------------------------------------------------------------------------
-status_t SharedBufferServer::BufferList::add(int value)
-{
-    if (uint32_t(value) >= mCapacity)
-        return BAD_VALUE;
-    uint32_t mask = 1<<(31-value);
-    if (mList & mask)
-        return ALREADY_EXISTS;
-    mList |= mask;
-    return NO_ERROR;
-}
-
-status_t SharedBufferServer::BufferList::remove(int value)
-{
-    if (uint32_t(value) >= mCapacity)
-        return BAD_VALUE;
-    uint32_t mask = 1<<(31-value);
-    if (!(mList & mask))
-        return NAME_NOT_FOUND;
-    mList &= ~mask;
-    return NO_ERROR;
-}
-
-
-// ---------------------------------------------------------------------------
-}; // namespace android
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 0c5767b..9185e1e 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -21,13 +21,15 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include <utils/Errors.h>
-#include <utils/threads.h>
 #include <utils/CallStack.h>
+#include <utils/Errors.h>
 #include <utils/Log.h>
+#include <utils/threads.h>
 
-#include <binder/IPCThreadState.h>
 #include <binder/IMemory.h>
+#include <binder/IPCThreadState.h>
+
+#include <gui/SurfaceTextureClient.h>
 
 #include <ui/DisplayInfo.h>
 #include <ui/GraphicBuffer.h>
@@ -35,12 +37,11 @@
 #include <ui/GraphicLog.h>
 #include <ui/Rect.h>
 
-#include <surfaceflinger/Surface.h>
 #include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 
-#include <private/surfaceflinger/SharedBufferStack.h>
 #include <private/surfaceflinger/LayerState.h>
 
 namespace android {
@@ -273,58 +274,10 @@
 //  Surface
 // ============================================================================
 
-class SurfaceClient : public Singleton<SurfaceClient>
-{
-    // all these attributes are constants
-    sp<ISurfaceComposer> mComposerService;
-    sp<ISurfaceComposerClient> mClient;
-    status_t mStatus;
-    SharedClient* mControl;
-    sp<IMemoryHeap> mControlMemory;
-
-    SurfaceClient()
-        : Singleton<SurfaceClient>(), mStatus(NO_INIT)
-    {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        mComposerService = sf;
-        mClient = sf->createClientConnection();
-        if (mClient != NULL) {
-            mControlMemory = mClient->getControlBlock();
-            if (mControlMemory != NULL) {
-                mControl = static_cast<SharedClient *>(
-                        mControlMemory->getBase());
-                if (mControl) {
-                    mStatus = NO_ERROR;
-                }
-            }
-        }
-    }
-    friend class Singleton<SurfaceClient>;
-public:
-    status_t initCheck() const {
-        return mStatus;
-    }
-    SharedClient* getSharedClient() const {
-        return mControl;
-    }
-    ssize_t getTokenForSurface(const sp<ISurface>& sur) const {
-        // TODO: we could cache a few tokens here to avoid an IPC
-        return mClient->getTokenForSurface(sur);
-    }
-    void signalServer() const {
-        mComposerService->signal();
-    }
-};
-
-ANDROID_SINGLETON_STATIC_INSTANCE(SurfaceClient);
-
 // ---------------------------------------------------------------------------
 
 Surface::Surface(const sp<SurfaceControl>& surface)
-    : mBufferMapper(GraphicBufferMapper::get()),
-      mClient(SurfaceClient::getInstance()),
-      mSharedBufferClient(NULL),
-      mInitCheck(NO_INIT),
+    : mInitCheck(NO_INIT),
       mSurface(surface->mSurface),
       mIdentity(surface->mIdentity),
       mFormat(surface->mFormat), mFlags(surface->mFlags),
@@ -334,10 +287,7 @@
 }
 
 Surface::Surface(const Parcel& parcel, const sp<IBinder>& ref)
-    : mBufferMapper(GraphicBufferMapper::get()),
-      mClient(SurfaceClient::getInstance()),
-      mSharedBufferClient(NULL),
-      mInitCheck(NO_INIT)
+    : mInitCheck(NO_INIT)
 {
     mSurface    = interface_cast<ISurface>(ref);
     mIdentity   = parcel.readInt32();
@@ -382,7 +332,6 @@
 
 }
 
-
 Mutex Surface::sCachedSurfacesLock;
 DefaultKeyedVector<wp<IBinder>, wp<Surface> > Surface::sCachedSurfaces;
 
@@ -422,32 +371,29 @@
     ANativeWindow::query            = query;
     ANativeWindow::perform          = perform;
 
-    DisplayInfo dinfo;
-    SurfaceComposerClient::getDisplayInfo(0, &dinfo);
-    const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
-    const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
-    // FIXME: set real values here
-    const_cast<int&>(ANativeWindow::minSwapInterval) = 1;
-    const_cast<int&>(ANativeWindow::maxSwapInterval) = 1;
-    const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+    if (mSurface != NULL) {
+        sp<ISurfaceTexture> surfaceTexture(mSurface->getSurfaceTexture());
+        LOGE_IF(surfaceTexture==0, "got a NULL ISurfaceTexture from ISurface");
+        if (surfaceTexture != NULL) {
+            mSurfaceTextureClient = new SurfaceTextureClient(surfaceTexture);
+            mSurfaceTextureClient->setUsage(GraphicBuffer::USAGE_HW_RENDER);
+        }
 
-    mNextBufferTransform = 0;
-    mConnected = 0;
-    mSwapRectangle.makeInvalid();
-    mNextBufferCrop = Rect(0,0);
-    // two buffers by default
-    mBuffers.setCapacity(2);
-    mBuffers.insertAt(0, 2);
+        DisplayInfo dinfo;
+        SurfaceComposerClient::getDisplayInfo(0, &dinfo);
+        const_cast<float&>(ANativeWindow::xdpi) = dinfo.xdpi;
+        const_cast<float&>(ANativeWindow::ydpi) = dinfo.ydpi;
 
-    if (mSurface != 0 && mClient.initCheck() == NO_ERROR) {
-        int32_t token = mClient.getTokenForSurface(mSurface);
-        if (token >= 0) {
-            mSharedBufferClient = new SharedBufferClient(
-                    mClient.getSharedClient(), token, 2, mIdentity);
-            mInitCheck = mClient.getSharedClient()->validate(token);
-        } else {
-            LOGW("Not initializing the shared buffer client because token = %d",
-                    token);
+        const_cast<int&>(ANativeWindow::minSwapInterval) =
+                mSurfaceTextureClient->minSwapInterval;
+
+        const_cast<int&>(ANativeWindow::maxSwapInterval) =
+                mSurfaceTextureClient->maxSwapInterval;
+
+        const_cast<uint32_t&>(ANativeWindow::flags) = 0;
+
+        if (mSurfaceTextureClient != 0) {
+            mInitCheck = NO_ERROR;
         }
     }
 }
@@ -456,9 +402,8 @@
 {
     // clear all references and trigger an IPC now, to make sure things
     // happen without delay, since these resources are quite heavy.
-    mBuffers.clear();
+    mSurfaceTextureClient.clear();
     mSurface.clear();
-    delete mSharedBufferClient;
     IPCThreadState::self()->flushCommands();
 }
 
@@ -473,35 +418,13 @@
         LOGE("invalid token (identity=%u)", mIdentity);
         return mInitCheck;
     }
-
-    // verify the identity of this surface
-    uint32_t identity = mSharedBufferClient->getIdentity();
-    if (mIdentity != identity) {
-        LOGE("[Surface] using an invalid surface, "
-                "identity=%u should be %d",
-                mIdentity, identity);
-        CallStack stack;
-        stack.update();
-        stack.dump("Surface");
-        return BAD_INDEX;
-    }
-
-    // check the surface didn't become invalid
-    status_t err = mSharedBufferClient->getStatus();
-    if (err != NO_ERROR) {
-        if (!inCancelBuffer) {
-            LOGE("surface (identity=%u) is invalid, err=%d (%s)",
-                    mIdentity, err, strerror(-err));
-            CallStack stack;
-            stack.update();
-            stack.dump("Surface");
-        }
-        return err;
-    }
-
     return NO_ERROR;
 }
 
+sp<ISurfaceTexture> Surface::getSurfaceTexture() {
+    return mSurface != NULL ? mSurface->getSurfaceTexture() : NULL;
+}
+
 sp<IBinder> Surface::asBinder() const {
     return mSurface!=0 ? mSurface->asBinder() : 0;
 }
@@ -509,7 +432,8 @@
 // ----------------------------------------------------------------------------
 
 int Surface::setSwapInterval(ANativeWindow* window, int interval) {
-    return 0;
+    Surface* self = getSelf(window);
+    return self->setSwapInterval(interval);
 }
 
 int Surface::dequeueBuffer(ANativeWindow* window, 
@@ -554,383 +478,52 @@
 
 // ----------------------------------------------------------------------------
 
-bool Surface::needNewBuffer(int bufIdx,
-        uint32_t *pWidth, uint32_t *pHeight,
-        uint32_t *pFormat, uint32_t *pUsage) const
-{
-    Mutex::Autolock _l(mSurfaceLock);
-
-    // Always call needNewBuffer(), since it clears the needed buffers flags
-    bool needNewBuffer = mSharedBufferClient->needNewBuffer(bufIdx);
-    bool validBuffer = mBufferInfo.validateBuffer(mBuffers[bufIdx]);
-    bool newNeewBuffer = needNewBuffer || !validBuffer;
-    if (newNeewBuffer) {
-        mBufferInfo.get(pWidth, pHeight, pFormat, pUsage);
-    }
-    return newNeewBuffer;
+int Surface::setSwapInterval(int interval) {
+    return mSurfaceTextureClient->setSwapInterval(interval);
 }
 
-int Surface::dequeueBuffer(ANativeWindowBuffer** buffer)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    GraphicLog& logger(GraphicLog::getInstance());
-    logger.log(GraphicLog::SF_APP_DEQUEUE_BEFORE, mIdentity, -1);
-
-    ssize_t bufIdx = mSharedBufferClient->dequeue();
-
-    logger.log(GraphicLog::SF_APP_DEQUEUE_AFTER, mIdentity, bufIdx);
-
-    if (bufIdx < 0) {
-        LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
-        return bufIdx;
-    }
-
-    // grow the buffer array if needed
-    const size_t size = mBuffers.size();
-    const size_t needed = bufIdx+1;
-    if (size < needed) {
-        mBuffers.insertAt(size, needed-size);
-    }
-
-    uint32_t w, h, format, usage;
-    if (needNewBuffer(bufIdx, &w, &h, &format, &usage)) {
-        err = getBufferLocked(bufIdx, w, h, format, usage);
-        LOGE_IF(err, "getBufferLocked(%ld, %u, %u, %u, %08x) failed (%s)",
-                bufIdx, w, h, format, usage, strerror(-err));
-        if (err == NO_ERROR) {
-            // reset the width/height with the what we get from the buffer
-            const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
-            mWidth  = uint32_t(backBuffer->width);
-            mHeight = uint32_t(backBuffer->height);
-        }
-    }
-
-    // if we still don't have a buffer here, we probably ran out of memory
-    const sp<GraphicBuffer>& backBuffer(mBuffers[bufIdx]);
-    if (!err && backBuffer==0) {
-        err = NO_MEMORY;
-    }
-
+int Surface::dequeueBuffer(ANativeWindowBuffer** buffer) {
+    status_t err = mSurfaceTextureClient->dequeueBuffer(buffer);
     if (err == NO_ERROR) {
-        mDirtyRegion.set(backBuffer->width, backBuffer->height);
-        *buffer = backBuffer.get();
-    } else {
-        mSharedBufferClient->undoDequeue(bufIdx);
-    }
-
-    return err;
-}
-
-int Surface::cancelBuffer(ANativeWindowBuffer* buffer)
-{
-    status_t err = validate(true);
-    switch (err) {
-    case NO_ERROR:
-        // no error, common case
-        break;
-    case BAD_INDEX:
-        // legitimate errors here
-        return err;
-    default:
-        // other errors happen because the surface is now invalid,
-        // for instance because it has been destroyed. In this case,
-        // we just fail silently (canceling a buffer is not technically
-        // an error at this point)
-        return NO_ERROR;
-    }
-
-    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
-    err = mSharedBufferClient->cancel(bufIdx);
-
-    LOGE_IF(err, "error canceling buffer %d (%s)", bufIdx, strerror(-err));
-    return err;
-}
-
-
-int Surface::lockBuffer(ANativeWindowBuffer* buffer)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
-    GraphicLog& logger(GraphicLog::getInstance());
-    logger.log(GraphicLog::SF_APP_LOCK_BEFORE, mIdentity, bufIdx);
-
-    err = mSharedBufferClient->lock(bufIdx);
-
-    logger.log(GraphicLog::SF_APP_LOCK_AFTER, mIdentity, bufIdx);
-
-    LOGE_IF(err, "error locking buffer %d (%s)", bufIdx, strerror(-err));
-    return err;
-}
-
-int Surface::queueBuffer(ANativeWindowBuffer* buffer)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    if (mSwapRectangle.isValid()) {
-        mDirtyRegion.set(mSwapRectangle);
-    }
-    
-    int32_t bufIdx = getBufferIndex(GraphicBuffer::getSelf(buffer));
-
-    GraphicLog::getInstance().log(GraphicLog::SF_APP_QUEUE, mIdentity, bufIdx);
-
-    mSharedBufferClient->setTransform(bufIdx, mNextBufferTransform);
-    mSharedBufferClient->setCrop(bufIdx, mNextBufferCrop);
-    mSharedBufferClient->setDirtyRegion(bufIdx, mDirtyRegion);
-    err = mSharedBufferClient->queue(bufIdx);
-    LOGE_IF(err, "error queuing buffer %d (%s)", bufIdx, strerror(-err));
-
-    if (err == NO_ERROR) {
-        // TODO: can we avoid this IPC if we know there is one pending?
-        mClient.signalServer();
+        mDirtyRegion.set(buffer[0]->width, buffer[0]->height);
     }
     return err;
 }
 
-int Surface::query(int what, int* value) const
-{
+int Surface::cancelBuffer(ANativeWindowBuffer* buffer) {
+    return mSurfaceTextureClient->cancelBuffer(buffer);
+}
+
+int Surface::lockBuffer(ANativeWindowBuffer* buffer) {
+    return mSurfaceTextureClient->lockBuffer(buffer);
+}
+
+int Surface::queueBuffer(ANativeWindowBuffer* buffer) {
+    return mSurfaceTextureClient->queueBuffer(buffer);
+}
+
+int Surface::query(int what, int* value) const {
     switch (what) {
-    case NATIVE_WINDOW_WIDTH:
-        *value = int(mWidth);
+    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
+        // TODO: this is not needed anymore
+        *value = 1;
         return NO_ERROR;
-    case NATIVE_WINDOW_HEIGHT:
-        *value = int(mHeight);
-        return NO_ERROR;
-    case NATIVE_WINDOW_FORMAT:
-        *value = int(mFormat);
-        return NO_ERROR;
-    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
-        *value = MIN_UNDEQUEUED_BUFFERS;
-        return NO_ERROR;
-    case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        *value = sf->authenticateSurface(mSurface) ? 1 : 0;
-        return NO_ERROR;
-    }
     case NATIVE_WINDOW_CONCRETE_TYPE:
+        // TODO: this is not needed anymore
         *value = NATIVE_WINDOW_SURFACE;
         return NO_ERROR;
     }
-    return BAD_VALUE;
+    return mSurfaceTextureClient->query(what, value);
 }
 
-int Surface::perform(int operation, va_list args)
-{
-    status_t err = validate();
-    if (err != NO_ERROR)
-        return err;
-
-    int res = NO_ERROR;
-    switch (operation) {
-    case NATIVE_WINDOW_SET_USAGE:
-        dispatch_setUsage( args );
-        break;
-    case NATIVE_WINDOW_CONNECT:
-        res = dispatch_connect( args );
-        break;
-    case NATIVE_WINDOW_DISCONNECT:
-        res = dispatch_disconnect( args );
-        break;
-    case NATIVE_WINDOW_SET_CROP:
-        res = dispatch_crop( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFER_COUNT:
-        res = dispatch_set_buffer_count( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
-        res = dispatch_set_buffers_geometry( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFERS_TRANSFORM:
-        res = dispatch_set_buffers_transform( args );
-        break;
-    case NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP:
-        res = dispatch_set_buffers_timestamp( args );
-        break;
-    default:
-        res = NAME_NOT_FOUND;
-        break;
-    }
-    return res;
-}
-
-void Surface::dispatch_setUsage(va_list args) {
-    int usage = va_arg(args, int);
-    setUsage( usage );
-}
-int Surface::dispatch_connect(va_list args) {
-    int api = va_arg(args, int);
-    return connect( api );
-}
-int Surface::dispatch_disconnect(va_list args) {
-    int api = va_arg(args, int);
-    return disconnect( api );
-}
-int Surface::dispatch_crop(va_list args) {
-    android_native_rect_t const* rect = va_arg(args, android_native_rect_t*);
-    return crop( reinterpret_cast<Rect const*>(rect) );
-}
-int Surface::dispatch_set_buffer_count(va_list args) {
-    size_t bufferCount = va_arg(args, size_t);
-    return setBufferCount(bufferCount);
-}
-int Surface::dispatch_set_buffers_geometry(va_list args) {
-    int w = va_arg(args, int);
-    int h = va_arg(args, int);
-    int f = va_arg(args, int);
-    return setBuffersGeometry(w, h, f);
-}
-
-int Surface::dispatch_set_buffers_transform(va_list args) {
-    int transform = va_arg(args, int);
-    return setBuffersTransform(transform);
-}
-
-int Surface::dispatch_set_buffers_timestamp(va_list args) {
-    int64_t timestamp = va_arg(args, int64_t);
-    return setBuffersTimestamp(timestamp);
-}
-
-void Surface::setUsage(uint32_t reqUsage)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    mBufferInfo.set(reqUsage);
-}
-
-int Surface::connect(int api)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnected) {
-                err = -EINVAL;
-            } else {
-                mConnected = api;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-int Surface::disconnect(int api)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    int err = NO_ERROR;
-    switch (api) {
-        case NATIVE_WINDOW_API_EGL:
-            if (mConnected == api) {
-                mConnected = 0;
-            } else {
-                err = -EINVAL;
-            }
-            break;
-        default:
-            err = -EINVAL;
-            break;
-    }
-    return err;
-}
-
-int Surface::crop(Rect const* rect)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    // TODO: validate rect size
-
-    if (rect == NULL || rect->isEmpty()) {
-        mNextBufferCrop = Rect(0,0);
-    } else {
-        mNextBufferCrop = *rect;
-    }
-
-    return NO_ERROR;
-}
-
-int Surface::setBufferCount(int bufferCount)
-{
-    sp<ISurface> s(mSurface);
-    if (s == 0) return NO_INIT;
-
-    class SetBufferCountIPC : public SharedBufferClient::SetBufferCountCallback {
-        sp<ISurface> surface;
-        virtual status_t operator()(int bufferCount) const {
-            return surface->setBufferCount(bufferCount);
-        }
-    public:
-        SetBufferCountIPC(const sp<ISurface>& surface) : surface(surface) { }
-    } ipc(s);
-
-    status_t err = mSharedBufferClient->setBufferCount(bufferCount, ipc);
-    LOGE_IF(err, "ISurface::setBufferCount(%d) returned %s",
-            bufferCount, strerror(-err));
-
-    if (err == NO_ERROR) {
-        // Clear out any references to the old buffers.
-        mBuffers.clear();
-    }
-
-    return err;
-}
-
-int Surface::setBuffersGeometry(int w, int h, int format)
-{
-    if (w<0 || h<0 || format<0)
-        return BAD_VALUE;
-
-    if ((w && !h) || (!w && h))
-        return BAD_VALUE;
-
-    Mutex::Autolock _l(mSurfaceLock);
-    if (mConnected == NATIVE_WINDOW_API_EGL) {
-        return INVALID_OPERATION;
-    }
-
-    mBufferInfo.set(w, h, format);
-    if (format != 0) {
-        // we update the format of the surface as reported by query().
-        // this is to allow applications to change the format of a surface's
-        // buffer, and have it reflected in EGL; which is needed for
-        // EGLConfig validation.
-        mFormat = format;
-    }
-
-    mNextBufferCrop = Rect(0,0);
-
-    return NO_ERROR;
-}
-
-int Surface::setBuffersTransform(int transform)
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    mNextBufferTransform = transform;
-    return NO_ERROR;
-}
-
-int Surface::setBuffersTimestamp(int64_t timestamp)
-{
-    // Surface doesn't really have anything meaningful to do with timestamps
-    // so they'll just be dropped here.
-    return NO_ERROR;
+int Surface::perform(int operation, va_list args) {
+    return mSurfaceTextureClient->perform(operation, args);
 }
 
 // ----------------------------------------------------------------------------
 
-int Surface::getConnectedApi() const
-{
-    Mutex::Autolock _l(mSurfaceLock);
-    return mConnected;
+int Surface::getConnectedApi() const {
+    return mSurfaceTextureClient->getConnectedApi();
 }
 
 // ----------------------------------------------------------------------------
@@ -967,16 +560,17 @@
     }
 
     // we're intending to do software rendering from this point
-    setUsage(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
+    mSurfaceTextureClient->setUsage(
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
 
     ANativeWindowBuffer* out;
-    status_t err = dequeueBuffer(&out);
+    status_t err = mSurfaceTextureClient->dequeueBuffer(&out);
     LOGE_IF(err, "dequeueBuffer failed (%s)", strerror(-err));
     if (err == NO_ERROR) {
         sp<GraphicBuffer> backBuffer(GraphicBuffer::getSelf(out));
-        err = lockBuffer(backBuffer.get());
-        LOGE_IF(err, "lockBuffer (idx=%d) failed (%s)",
-                getBufferIndex(backBuffer), strerror(-err));
+        err = mSurfaceTextureClient->lockBuffer(backBuffer.get());
+        LOGE_IF(err, "lockBuffer (handle=%p) failed (%s)",
+                backBuffer->handle, strerror(-err));
         if (err == NO_ERROR) {
             const Rect bounds(backBuffer->width, backBuffer->height);
             const Region boundsRegion(bounds);
@@ -1043,110 +637,14 @@
     status_t err = mLockedBuffer->unlock();
     LOGE_IF(err, "failed unlocking buffer (%p)", mLockedBuffer->handle);
     
-    err = queueBuffer(mLockedBuffer.get());
-    LOGE_IF(err, "queueBuffer (idx=%d) failed (%s)",
-            getBufferIndex(mLockedBuffer), strerror(-err));
+    err = mSurfaceTextureClient->queueBuffer(mLockedBuffer.get());
+    LOGE_IF(err, "queueBuffer (handle=%p) failed (%s)",
+            mLockedBuffer->handle, strerror(-err));
 
     mPostedBuffer = mLockedBuffer;
     mLockedBuffer = 0;
     return err;
 }
 
-void Surface::setSwapRectangle(const Rect& r) {
-    Mutex::Autolock _l(mSurfaceLock);
-    mSwapRectangle = r;
-}
-
-int Surface::getBufferIndex(const sp<GraphicBuffer>& buffer) const
-{
-    int idx = buffer->getIndex();
-    if (idx < 0) {
-        // The buffer doesn't have an index set.  See if the handle the same as
-        // one of the buffers for which we do know the index.  This can happen
-        // e.g. if GraphicBuffer is used to wrap an ANativeWindowBuffer that
-        // was dequeued from an ANativeWindow.
-        for (size_t i = 0; i < mBuffers.size(); i++) {
-            if (mBuffers[i] != 0 && buffer->handle == mBuffers[i]->handle) {
-                idx = mBuffers[i]->getIndex();
-                break;
-            }
-        }
-    }
-    return idx;
-}
-
-status_t Surface::getBufferLocked(int index,
-        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
-    sp<ISurface> s(mSurface);
-    if (s == 0) return NO_INIT;
-
-    status_t err = NO_MEMORY;
-
-    // free the current buffer
-    sp<GraphicBuffer>& currentBuffer(mBuffers.editItemAt(index));
-    if (currentBuffer != 0) {
-        currentBuffer.clear();
-    }
-
-    sp<GraphicBuffer> buffer = s->requestBuffer(index, w, h, format, usage);
-    LOGE_IF(buffer==0,
-            "ISurface::getBuffer(%d, %08x) returned NULL",
-            index, usage);
-    if (buffer != 0) { // this should always happen by construction
-        LOGE_IF(buffer->handle == NULL, 
-                "Surface (identity=%d) requestBuffer(%d, %u, %u, %u, %08x) "
-                "returned a buffer with a null handle",
-                mIdentity, index, w, h, format, usage);
-        err = mSharedBufferClient->getStatus();
-        LOGE_IF(err,  "Surface (identity=%d) state = %d", mIdentity, err);
-        if (!err && buffer->handle != NULL) {
-            currentBuffer = buffer;
-            currentBuffer->setIndex(index);
-        } else {
-            err = err<0 ? err : status_t(NO_MEMORY);
-        }
-    }
-    return err; 
-}
-
-// ----------------------------------------------------------------------------
-Surface::BufferInfo::BufferInfo()
-    : mWidth(0), mHeight(0), mFormat(0),
-      mUsage(GRALLOC_USAGE_HW_RENDER), mDirty(0)
-{
-}
-
-void Surface::BufferInfo::set(uint32_t w, uint32_t h, uint32_t format) {
-    if ((mWidth != w) || (mHeight != h) || (mFormat != format)) {
-        mWidth = w;
-        mHeight = h;
-        mFormat = format;
-        mDirty |= GEOMETRY;
-    }
-}
-
-void Surface::BufferInfo::set(uint32_t usage) {
-    mUsage = usage;
-}
-
-void Surface::BufferInfo::get(uint32_t *pWidth, uint32_t *pHeight,
-        uint32_t *pFormat, uint32_t *pUsage) const {
-    *pWidth  = mWidth;
-    *pHeight = mHeight;
-    *pFormat = mFormat;
-    *pUsage  = mUsage;
-}
-
-bool Surface::BufferInfo::validateBuffer(const sp<GraphicBuffer>& buffer) const {
-    // make sure we AT LEAST have the usage flags we want
-    if (mDirty || buffer==0 ||
-            ((buffer->usage & mUsage) != mUsage)) {
-        mDirty = 0;
-        return false;
-    }
-    return true;
-}
-
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a1ff2c1..8cead80 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -20,19 +20,20 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
-#include <utils/threads.h>
-#include <utils/SortedVector.h>
 #include <utils/Log.h>
 #include <utils/Singleton.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
 
-#include <binder/IServiceManager.h>
 #include <binder/IMemory.h>
+#include <binder/IServiceManager.h>
 
 #include <ui/DisplayInfo.h>
 
+#include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/ISurfaceComposerClient.h>
-#include <surfaceflinger/ISurface.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
 
 #include <private/surfaceflinger/LayerState.h>
@@ -73,75 +74,52 @@
 
 // ---------------------------------------------------------------------------
 
+// NOTE: this is NOT a member function (it's a friend defined with its
+// declaration).
+static inline
+int compare_type( const ComposerState& lhs, const ComposerState& rhs) {
+    if (lhs.client < rhs.client)  return -1;
+    if (lhs.client > rhs.client)  return 1;
+    if (lhs.state.surface < rhs.state.surface)  return -1;
+    if (lhs.state.surface > rhs.state.surface)  return 1;
+    return 0;
+}
+
 class Composer : public Singleton<Composer>
 {
-    Mutex mLock;
-    SortedVector< wp<SurfaceComposerClient> > mActiveConnections;
-    SortedVector<sp<SurfaceComposerClient> > mOpenTransactions;
-
-    Composer() : Singleton<Composer>() {
-    }
-
-    void addClientImpl(const sp<SurfaceComposerClient>& client) {
-        Mutex::Autolock _l(mLock);
-        mActiveConnections.add(client);
-    }
-
-    void removeClientImpl(const sp<SurfaceComposerClient>& client) {
-        Mutex::Autolock _l(mLock);
-        mActiveConnections.remove(client);
-    }
-
-    void openGlobalTransactionImpl()
-    {
-        Mutex::Autolock _l(mLock);
-        if (mOpenTransactions.size()) {
-            LOGE("openGlobalTransaction() called more than once. skipping.");
-            return;
-        }
-        const size_t N = mActiveConnections.size();
-        for (size_t i=0; i<N; i++) {
-            sp<SurfaceComposerClient> client(mActiveConnections[i].promote());
-            if (client != 0 && mOpenTransactions.indexOf(client) < 0) {
-                if (client->openTransaction() == NO_ERROR) {
-                    mOpenTransactions.add(client);
-                } else {
-                    LOGE("openTransaction on client %p failed", client.get());
-                    // let it go, it'll fail later when the user
-                    // tries to do something with the transaction
-                }
-            }
-        }
-    }
-
-    void closeGlobalTransactionImpl()
-    {
-        mLock.lock();
-            SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions);
-            mOpenTransactions.clear();
-        mLock.unlock();
-
-        sp<ISurfaceComposer> sm(getComposerService());
-        sm->openGlobalTransaction();
-            const size_t N = clients.size();
-            for (size_t i=0; i<N; i++) {
-                clients[i]->closeTransaction();
-            }
-        sm->closeGlobalTransaction();
-    }
-
     friend class Singleton<Composer>;
 
+    mutable Mutex               mLock;
+    SortedVector<ComposerState> mStates;
+
+    Composer() : Singleton<Composer>() { }
+
+    void closeGlobalTransactionImpl();
+
+    layer_state_t* getLayerStateLocked(
+            const sp<SurfaceComposerClient>& client, SurfaceID id);
+
 public:
-    static void addClient(const sp<SurfaceComposerClient>& client) {
-        Composer::getInstance().addClientImpl(client);
-    }
-    static void removeClient(const sp<SurfaceComposerClient>& client) {
-        Composer::getInstance().removeClientImpl(client);
-    }
-    static void openGlobalTransaction() {
-        Composer::getInstance().openGlobalTransactionImpl();
-    }
+
+    status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
+            int32_t x, int32_t y);
+    status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id,
+            uint32_t w, uint32_t h);
+    status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id,
+            int32_t z);
+    status_t setFlags(const sp<SurfaceComposerClient>& client, SurfaceID id,
+            uint32_t flags, uint32_t mask);
+    status_t setTransparentRegionHint(
+            const sp<SurfaceComposerClient>& client, SurfaceID id,
+            const Region& transparentRegion);
+    status_t setAlpha(const sp<SurfaceComposerClient>& client, SurfaceID id,
+            float alpha);
+    status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id,
+            float dsdx, float dtdx, float dsdy, float dtdy);
+    status_t setFreezeTint(
+            const sp<SurfaceComposerClient>& client, SurfaceID id,
+            uint32_t tint);
+
     static void closeGlobalTransaction() {
         Composer::getInstance().closeGlobalTransactionImpl();
     }
@@ -151,127 +129,185 @@
 
 // ---------------------------------------------------------------------------
 
-static inline int compare_type( const layer_state_t& lhs,
-                                const layer_state_t& rhs) {
-    if (lhs.surface < rhs.surface)  return -1;
-    if (lhs.surface > rhs.surface)  return 1;
-    return 0;
+void Composer::closeGlobalTransactionImpl() {
+    sp<ISurfaceComposer> sm(getComposerService());
+
+    Vector<ComposerState> transaction;
+
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        transaction = mStates;
+        mStates.clear();
+    }
+
+   sm->setTransactionState(transaction);
 }
 
+layer_state_t* Composer::getLayerStateLocked(
+        const sp<SurfaceComposerClient>& client, SurfaceID id) {
+
+    ComposerState s;
+    s.client = client->mClient;
+    s.state.surface = id;
+
+    ssize_t index = mStates.indexOf(s);
+    if (index < 0) {
+        // we don't have it, add an initialized layer_state to our list
+        index = mStates.add(s);
+    }
+
+    ComposerState* const out = mStates.editArray();
+    return &(out[index].state);
+}
+
+status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
+        SurfaceID id, int32_t x, int32_t y) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::ePositionChanged;
+    s->x = x;
+    s->y = y;
+    return NO_ERROR;
+}
+
+status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
+        SurfaceID id, uint32_t w, uint32_t h) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::eSizeChanged;
+    s->w = w;
+    s->h = h;
+    return NO_ERROR;
+}
+
+status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
+        SurfaceID id, int32_t z) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::eLayerChanged;
+    s->z = z;
+    return NO_ERROR;
+}
+
+status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
+        SurfaceID id, uint32_t flags,
+        uint32_t mask) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::eVisibilityChanged;
+    s->flags &= ~mask;
+    s->flags |= (flags & mask);
+    s->mask |= mask;
+    return NO_ERROR;
+}
+
+status_t Composer::setTransparentRegionHint(
+        const sp<SurfaceComposerClient>& client, SurfaceID id,
+        const Region& transparentRegion) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::eTransparentRegionChanged;
+    s->transparentRegion = transparentRegion;
+    return NO_ERROR;
+}
+
+status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
+        SurfaceID id, float alpha) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::eAlphaChanged;
+    s->alpha = alpha;
+    return NO_ERROR;
+}
+
+status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
+        SurfaceID id, float dsdx, float dtdx,
+        float dsdy, float dtdy) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::eMatrixChanged;
+    layer_state_t::matrix22_t matrix;
+    matrix.dsdx = dsdx;
+    matrix.dtdx = dtdx;
+    matrix.dsdy = dsdy;
+    matrix.dtdy = dtdy;
+    s->matrix = matrix;
+    return NO_ERROR;
+}
+
+status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client,
+        SurfaceID id, uint32_t tint) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= ISurfaceComposer::eFreezeTintChanged;
+    s->tint = tint;
+    return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
 SurfaceComposerClient::SurfaceComposerClient()
-    : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT)
+    : mStatus(NO_INIT), mComposer(Composer::getInstance())
 {
 }
 
-void SurfaceComposerClient::onFirstRef()
-{
+void SurfaceComposerClient::onFirstRef() {
     sp<ISurfaceComposer> sm(getComposerService());
     if (sm != 0) {
         sp<ISurfaceComposerClient> conn = sm->createConnection();
         if (conn != 0) {
             mClient = conn;
-            Composer::addClient(this);
-            mPrebuiltLayerState = new layer_state_t;
             mStatus = NO_ERROR;
         }
     }
 }
 
-SurfaceComposerClient::~SurfaceComposerClient()
-{
-    delete mPrebuiltLayerState;
+SurfaceComposerClient::~SurfaceComposerClient() {
     dispose();
 }
 
-status_t SurfaceComposerClient::initCheck() const
-{
+status_t SurfaceComposerClient::initCheck() const {
     return mStatus;
 }
 
-sp<IBinder> SurfaceComposerClient::connection() const
-{
+sp<IBinder> SurfaceComposerClient::connection() const {
     return (mClient != 0) ? mClient->asBinder() : 0;
 }
 
 status_t SurfaceComposerClient::linkToComposerDeath(
         const sp<IBinder::DeathRecipient>& recipient,
-        void* cookie, uint32_t flags)
-{
+        void* cookie, uint32_t flags) {
     sp<ISurfaceComposer> sm(getComposerService());
     return sm->asBinder()->linkToDeath(recipient, cookie, flags);
 }
 
-void SurfaceComposerClient::dispose()
-{
+void SurfaceComposerClient::dispose() {
     // this can be called more than once.
     sp<ISurfaceComposerClient> client;
     Mutex::Autolock _lm(mLock);
     if (mClient != 0) {
-        Composer::removeClient(this);
         client = mClient; // hold ref while lock is held
         mClient.clear();
     }
     mStatus = NO_INIT;
 }
 
-status_t SurfaceComposerClient::getDisplayInfo(
-        DisplayID dpy, DisplayInfo* info)
-{
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
-        return BAD_VALUE;
-
-    volatile surface_flinger_cblk_t const * cblk = get_cblk();
-    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
-
-    info->w              = dcblk->w;
-    info->h              = dcblk->h;
-    info->orientation    = dcblk->orientation;
-    info->xdpi           = dcblk->xdpi;
-    info->ydpi           = dcblk->ydpi;
-    info->fps            = dcblk->fps;
-    info->density        = dcblk->density;
-    return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
-}
-
-ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
-{
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
-        return BAD_VALUE;
-    volatile surface_flinger_cblk_t const * cblk = get_cblk();
-    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
-    return dcblk->w;
-}
-
-ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
-{
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
-        return BAD_VALUE;
-    volatile surface_flinger_cblk_t const * cblk = get_cblk();
-    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
-    return dcblk->h;
-}
-
-ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
-{
-    if (uint32_t(dpy)>=SharedBufferStack::NUM_DISPLAY_MAX)
-        return BAD_VALUE;
-    volatile surface_flinger_cblk_t const * cblk = get_cblk();
-    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
-    return dcblk->orientation;
-}
-
-ssize_t SurfaceComposerClient::getNumberOfDisplays()
-{
-    volatile surface_flinger_cblk_t const * cblk = get_cblk();
-    uint32_t connected = cblk->connected;
-    int n = 0;
-    while (connected) {
-        if (connected&1) n++;
-        connected >>= 1;
-    }
-    return n;
-}
-
 sp<SurfaceControl> SurfaceComposerClient::createSurface(
         DisplayID display,
         uint32_t w,
@@ -309,34 +345,150 @@
     return result;
 }
 
-status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
-{
+status_t SurfaceComposerClient::destroySurface(SurfaceID sid) {
     if (mStatus != NO_ERROR)
         return mStatus;
-
-    // it's okay to destroy a surface while a transaction is open,
-    // (transactions really are a client-side concept)
-    // however, this indicates probably a misuse of the API or a bug
-    // in the client code.
-    LOGW_IF(mTransactionOpen,
-         "Destroying surface while a transaction is open. "
-         "Client %p: destroying surface %d, mTransactionOpen=%d",
-         this, sid, mTransactionOpen);
-
     status_t err = mClient->destroySurface(sid);
     return err;
 }
 
-void SurfaceComposerClient::openGlobalTransaction()
-{
-    Composer::openGlobalTransaction();
+inline Composer& SurfaceComposerClient::getComposer() {
+    return mComposer;
 }
 
-void SurfaceComposerClient::closeGlobalTransaction()
-{
+// ----------------------------------------------------------------------------
+
+void SurfaceComposerClient::openGlobalTransaction() {
+    // Currently a no-op
+}
+
+void SurfaceComposerClient::closeGlobalTransaction() {
     Composer::closeGlobalTransaction();
 }
 
+// ----------------------------------------------------------------------------
+
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) {
+    return getComposer().setFreezeTint(this, id, tint);
+}
+
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) {
+    return getComposer().setPosition(this, id, x, y);
+}
+
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) {
+    return getComposer().setSize(this, id, w, h);
+}
+
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) {
+    return getComposer().setLayer(this, id, z);
+}
+
+status_t SurfaceComposerClient::hide(SurfaceID id) {
+    return getComposer().setFlags(this, id,
+            ISurfaceComposer::eLayerHidden,
+            ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t) {
+    return getComposer().setFlags(this, id,
+            0,
+            ISurfaceComposer::eLayerHidden);
+}
+
+status_t SurfaceComposerClient::freeze(SurfaceID id) {
+    return getComposer().setFlags(this, id,
+            ISurfaceComposer::eLayerFrozen,
+            ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::unfreeze(SurfaceID id) {
+    return getComposer().setFlags(this, id,
+            0,
+            ISurfaceComposer::eLayerFrozen);
+}
+
+status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags,
+        uint32_t mask) {
+    return getComposer().setFlags(this, id, flags, mask);
+}
+
+status_t SurfaceComposerClient::setTransparentRegionHint(SurfaceID id,
+        const Region& transparentRegion) {
+    return getComposer().setTransparentRegionHint(this, id, transparentRegion);
+}
+
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) {
+    return getComposer().setAlpha(this, id, alpha);
+}
+
+status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx,
+        float dsdy, float dtdy) {
+    return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
+}
+
+// ----------------------------------------------------------------------------
+
+status_t SurfaceComposerClient::getDisplayInfo(
+        DisplayID dpy, DisplayInfo* info)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+
+    info->w              = dcblk->w;
+    info->h              = dcblk->h;
+    info->orientation    = dcblk->orientation;
+    info->xdpi           = dcblk->xdpi;
+    info->ydpi           = dcblk->ydpi;
+    info->fps            = dcblk->fps;
+    info->density        = dcblk->density;
+    return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
+}
+
+ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+    return dcblk->w;
+}
+
+ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+    return dcblk->h;
+}
+
+ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
+{
+    if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+        return BAD_VALUE;
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+    return dcblk->orientation;
+}
+
+ssize_t SurfaceComposerClient::getNumberOfDisplays()
+{
+    volatile surface_flinger_cblk_t const * cblk = get_cblk();
+    uint32_t connected = cblk->connected;
+    int n = 0;
+    while (connected) {
+        if (connected&1) n++;
+        connected >>= 1;
+    }
+    return n;
+}
+
+// ----------------------------------------------------------------------------
+
 status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
 {
     sp<ISurfaceComposer> sm(getComposerService());
@@ -349,199 +501,13 @@
     return sm->unfreezeDisplay(dpy, flags);
 }
 
-int SurfaceComposerClient::setOrientation(DisplayID dpy, 
+int SurfaceComposerClient::setOrientation(DisplayID dpy,
         int orientation, uint32_t flags)
 {
     sp<ISurfaceComposer> sm(getComposerService());
     return sm->setOrientation(dpy, orientation, flags);
 }
 
-status_t SurfaceComposerClient::openTransaction()
-{
-    if (mStatus != NO_ERROR)
-        return mStatus;
-    Mutex::Autolock _l(mLock);
-    mTransactionOpen++;
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::closeTransaction()
-{
-    if (mStatus != NO_ERROR)
-        return mStatus;
-
-    Mutex::Autolock _l(mLock);
-    if (mTransactionOpen <= 0) {
-        LOGE(   "closeTransaction (client %p, mTransactionOpen=%d) "
-                "called more times than openTransaction()",
-                this, mTransactionOpen);
-        return INVALID_OPERATION;
-    }
-
-    if (mTransactionOpen >= 2) {
-        mTransactionOpen--;
-        return NO_ERROR;
-    }
-
-    mTransactionOpen = 0;
-    const ssize_t count = mStates.size();
-    if (count) {
-        mClient->setState(count, mStates.array());
-        mStates.clear();
-    }
-    return NO_ERROR;
-}
-
-layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index)
-{
-    // API usage error, do nothing.
-    if (mTransactionOpen<=0) {
-        LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
-                this, int(index), mTransactionOpen);
-        return 0;
-    }
-
-    // use mPrebuiltLayerState just to find out if we already have it
-    layer_state_t& dummy(*mPrebuiltLayerState);
-    dummy.surface = index;
-    ssize_t i = mStates.indexOf(dummy);
-    if (i < 0) {
-        // we don't have it, add an initialized layer_state to our list
-        i = mStates.add(dummy);
-    }
-    return mStates.editArray() + i;
-}
-
-layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id)
-{
-    layer_state_t* s;
-    mLock.lock();
-    s = get_state_l(id);
-    if (!s) mLock.unlock();
-    return s;
-}
-
-void SurfaceComposerClient::unlockLayerState()
-{
-    mLock.unlock();
-}
-
-status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::ePositionChanged;
-    s->x = x;
-    s->y = y;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::eSizeChanged;
-    s->w = w;
-    s->h = h;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::eLayerChanged;
-    s->z = z;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::hide(SurfaceID id)
-{
-    return setFlags(id, ISurfaceComposer::eLayerHidden,
-            ISurfaceComposer::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
-{
-    return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
-}
-
-status_t SurfaceComposerClient::freeze(SurfaceID id)
-{
-    return setFlags(id, ISurfaceComposer::eLayerFrozen,
-            ISurfaceComposer::eLayerFrozen);
-}
-
-status_t SurfaceComposerClient::unfreeze(SurfaceID id)
-{
-    return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
-}
-
-status_t SurfaceComposerClient::setFlags(SurfaceID id,
-        uint32_t flags, uint32_t mask)
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::eVisibilityChanged;
-    s->flags &= ~mask;
-    s->flags |= (flags & mask);
-    s->mask |= mask;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setTransparentRegionHint(
-        SurfaceID id, const Region& transparentRegion)
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::eTransparentRegionChanged;
-    s->transparentRegion = transparentRegion;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::eAlphaChanged;
-    s->alpha = alpha;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setMatrix(
-        SurfaceID id,
-        float dsdx, float dtdx,
-        float dsdy, float dtdy )
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::eMatrixChanged;
-    layer_state_t::matrix22_t matrix;
-    matrix.dsdx = dsdx;
-    matrix.dtdx = dtdx;
-    matrix.dsdy = dsdy;
-    matrix.dtdy = dtdy;
-    s->matrix = matrix;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
-status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
-{
-    layer_state_t* s = lockLayerState(id);
-    if (!s) return BAD_INDEX;
-    s->what |= ISurfaceComposer::eFreezeTintChanged;
-    s->tint = tint;
-    unlockLayerState();
-    return NO_ERROR;
-}
-
 // ----------------------------------------------------------------------------
 
 ScreenshotClient::ScreenshotClient()
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index ee97dcf..0925001 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -78,7 +78,7 @@
 
 static void mtxMul(float out[16], const float a[16], const float b[16]);
 
-SurfaceTexture::SurfaceTexture(GLuint tex) :
+SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode) :
     mDefaultWidth(1),
     mDefaultHeight(1),
     mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -91,11 +91,13 @@
     mCurrentTimestamp(0),
     mNextTransform(0),
     mTexName(tex),
-    mSynchronousMode(false) {
+    mSynchronousMode(false),
+    mAllowSynchronousMode(allowSynchronousMode) {
     LOGV("SurfaceTexture::SurfaceTexture");
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
     mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
     mNextCrop.makeInvalid();
+    memcpy(mCurrentTransformMatrix, mtxIdentity, sizeof(mCurrentTransformMatrix));
 }
 
 SurfaceTexture::~SurfaceTexture() {
@@ -270,7 +272,7 @@
             if (state == BufferSlot::DEQUEUED) {
                 dequeuedCount++;
             }
-            if (state == BufferSlot::FREE || i == mCurrentTexture) {
+            if (state == BufferSlot::FREE /*|| i == mCurrentTexture*/) {
                 foundSync = i;
                 if (i != mCurrentTexture) {
                     found = i;
@@ -370,6 +372,9 @@
     Mutex::Autolock lock(mMutex);
 
     status_t err = OK;
+    if (!mAllowSynchronousMode && enabled)
+        return err;
+
     if (!enabled) {
         // going to asynchronous mode, drain the queue
         while (mSynchronousMode != enabled && !mQueue.isEmpty()) {
@@ -412,17 +417,22 @@
             return -EINVAL;
         }
 
-        if (mQueue.empty()) {
-            listener = mFrameAvailableListener;
-        }
-
         if (mSynchronousMode) {
-            // in synchronous mode we queue all buffers in a FIFO
+            // In synchronous mode we queue all buffers in a FIFO.
             mQueue.push_back(buf);
+
+            // Synchronous mode always signals that an additional frame should
+            // be consumed.
+            listener = mFrameAvailableListener;
         } else {
-            // in asynchronous mode we only keep the most recent buffer
+            // In asynchronous mode we only keep the most recent buffer.
             if (mQueue.empty()) {
                 mQueue.push_back(buf);
+
+                // Asynchronous mode only signals that a frame should be
+                // consumed if no previous frame was pending. If a frame were
+                // pending then the consumer would have already been notified.
+                listener = mFrameAvailableListener;
             } else {
                 Fifo::iterator front(mQueue.begin());
                 // buffer currently queued is freed
@@ -478,24 +488,14 @@
 
 status_t SurfaceTexture::updateTexImage() {
     LOGV("SurfaceTexture::updateTexImage");
-
     Mutex::Autolock lock(mMutex);
 
-    int buf = mCurrentTexture;
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
     if (!mQueue.empty()) {
-        // in asynchronous mode the list is guaranteed to be one buffer deep,
-        // while in synchronous mode we use the oldest buffer
         Fifo::iterator front(mQueue.begin());
-        buf = *front;
-        mQueue.erase(front);
-        if (mQueue.isEmpty()) {
-            mDequeueCondition.signal();
-        }
-    }
+        int buf = *front;
 
-    // Initially both mCurrentTexture and buf are INVALID_BUFFER_SLOT,
-    // so this check will fail until a buffer gets queued.
-    if (mCurrentTexture != buf) {
         // Update the GL texture object.
         EGLImageKHR image = mSlots[buf].mEglImage;
         if (image == EGL_NO_IMAGE_KHR) {
@@ -533,7 +533,7 @@
         }
 
         if (mCurrentTexture != INVALID_BUFFER_SLOT) {
-            // the current buffer becomes FREE if it was still in the queued
+            // The current buffer becomes FREE if it was still in the queued
             // state. If it has already been given to the client
             // (synchronous mode), then it stays in DEQUEUED state.
             if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
@@ -547,17 +547,18 @@
         mCurrentCrop = mSlots[buf].mCrop;
         mCurrentTransform = mSlots[buf].mTransform;
         mCurrentTimestamp = mSlots[buf].mTimestamp;
+        computeCurrentTransformMatrix();
+
+        // Now that we've passed the point at which failures can happen,
+        // it's safe to remove the buffer from the front of the queue.
+        mQueue.erase(front);
         mDequeueCondition.signal();
     } else {
         // We always bind the texture even if we don't update its contents.
         glBindTexture(mCurrentTextureTarget, mTexName);
     }
-    return OK;
-}
 
-size_t SurfaceTexture::getQueuedCount() const {
-    Mutex::Autolock lock(mMutex);
-    return mQueue.size();
+    return OK;
 }
 
 bool SurfaceTexture::isExternalFormat(uint32_t format)
@@ -596,8 +597,12 @@
 }
 
 void SurfaceTexture::getTransformMatrix(float mtx[16]) {
-    LOGV("SurfaceTexture::getTransformMatrix");
     Mutex::Autolock lock(mMutex);
+    memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+}
+
+void SurfaceTexture::computeCurrentTransformMatrix() {
+    LOGV("SurfaceTexture::computeCurrentTransformMatrix");
 
     float xform[16];
     for (int i = 0; i < 16; i++) {
@@ -684,7 +689,7 @@
     // coordinate of 0, so SurfaceTexture must behave the same way.  We don't
     // want to expose this to applications, however, so we must add an
     // additional vertical flip to the transform after all the other transforms.
-    mtxMul(mtx, mtxFlipV, mtxBeforeFlipV);
+    mtxMul(mCurrentTransformMatrix, mtxFlipV, mtxBeforeFlipV);
 }
 
 nsecs_t SurfaceTexture::getTimestamp() {
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index c20fcf2..b9b2310 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -143,12 +143,40 @@
 int SurfaceTextureClient::cancelBuffer(android_native_buffer_t* buffer) {
     LOGV("SurfaceTextureClient::cancelBuffer");
     Mutex::Autolock lock(mMutex);
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
+    }
+    mSurfaceTexture->cancelBuffer(i);
+    return OK;
+}
+
+int SurfaceTextureClient::getSlotFromBufferLocked(
+        android_native_buffer_t* buffer) const {
+    bool dumpedState = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i]->handle == buffer->handle) {
-            mSurfaceTexture->cancelBuffer(i);
-            return OK;
+        // XXX: Dump the slots whenever we hit a NULL entry while searching for
+        // a buffer.
+        if (mSlots[i] == NULL) {
+            if (!dumpedState) {
+                LOGD("getSlotFromBufferLocked: encountered NULL buffer in slot %d "
+                        "looking for buffer %p", i, buffer->handle);
+                for (int j = 0; j < NUM_BUFFER_SLOTS; j++) {
+                    if (mSlots[j] == NULL) {
+                        LOGD("getSlotFromBufferLocked:   %02d: NULL", j);
+                    } else {
+                        LOGD("getSlotFromBufferLocked:   %02d: %p", j, mSlots[j]->handle);
+                    }
+                }
+                dumpedState = true;
+            }
+        }
+
+        if (mSlots[i] != NULL && mSlots[i]->handle == buffer->handle) {
+            return i;
         }
     }
+    LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
     return BAD_VALUE;
 }
 
@@ -169,18 +197,23 @@
     } else {
         timestamp = mTimestamp;
     }
-    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i]->handle == buffer->handle) {
-            return mSurfaceTexture->queueBuffer(i, timestamp);
-        }
+    int i = getSlotFromBufferLocked(buffer);
+    if (i < 0) {
+        return i;
     }
-    LOGE("queueBuffer: unknown buffer queued");
-    return BAD_VALUE;
+    mSurfaceTexture->queueBuffer(i, timestamp);
+    return OK;
 }
 
 int SurfaceTextureClient::query(int what, int* value) const {
     LOGV("SurfaceTextureClient::query");
     switch (what) {
+    case NATIVE_WINDOW_FORMAT:
+        if (mReqFormat) {
+            *value = mReqFormat;
+            return NO_ERROR;
+        }
+        break;
     case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER:
         // TODO: this is not needed anymore
         *value = 0;
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 2f704c8..519b40e 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -32,6 +32,7 @@
     virtual void SetUp() {
         mST = new SurfaceTexture(123);
         mSTC = new SurfaceTextureClient(mST);
+        mANW = mSTC;
 
         // We need a valid GL context so we can test updateTexImage()
         // This initializes EGL and create a dummy GL context with a
@@ -69,6 +70,8 @@
     virtual void TearDown() {
         mST.clear();
         mSTC.clear();
+        mANW.clear();
+
         eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
         eglDestroyContext(mEglDisplay, mEglContext);
         eglDestroySurface(mEglDisplay, mEglSurface);
@@ -86,6 +89,8 @@
 
     sp<SurfaceTexture> mST;
     sp<SurfaceTextureClient> mSTC;
+    sp<ANativeWindow> mANW;
+
     EGLDisplay mEglDisplay;
     EGLSurface mEglSurface;
     EGLContext mEglContext;
@@ -97,31 +102,26 @@
 }
 
 TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
-    sp<ANativeWindow> anw(mSTC);
     int result = -123;
-    int err = anw->query(anw.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
+    int err = mANW->query(mANW.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
             &result);
     EXPECT_EQ(NO_ERROR, err);
     EXPECT_EQ(0, result);
 }
 
 TEST_F(SurfaceTextureClientTest, ConcreteTypeIsSurfaceTextureClient) {
-    sp<ANativeWindow> anw(mSTC);
     int result = -123;
-    int err = anw->query(anw.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result);
+    int err = mANW->query(mANW.get(), NATIVE_WINDOW_CONCRETE_TYPE, &result);
     EXPECT_EQ(NO_ERROR, err);
     EXPECT_EQ(NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT, result);
 }
 
 TEST_F(SurfaceTextureClientTest, ANativeWindowLockFails) {
-    sp<ANativeWindow> anw(mSTC);
     ANativeWindow_Buffer buf;
-    ASSERT_EQ(BAD_VALUE, ANativeWindow_lock(anw.get(), &buf, NULL));
+    ASSERT_EQ(BAD_VALUE, ANativeWindow_lock(mANW.get(), &buf, NULL));
 }
 
 TEST_F(SurfaceTextureClientTest, EglCreateWindowSurfaceSucceeds) {
-    sp<ANativeWindow> anw(mSTC);
-
     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
     ASSERT_NE(EGL_NO_DISPLAY, dpy);
@@ -147,7 +147,7 @@
             &numConfigs));
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
-    EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, anw.get(),
+    EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, mANW.get(),
             NULL);
     EXPECT_NE(EGL_NO_SURFACE, eglSurface);
     EXPECT_EQ(EGL_SUCCESS, eglGetError());
@@ -156,269 +156,246 @@
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometryInvalidSizesFail) {
-    sp<ANativeWindow> anw(mSTC);
-
-    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1,  0,  0));
-    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  0, -1,  0));
-    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  0,  0, -1));
-    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(), -1, -1,  0));
-    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  0,  8,  0));
-    EXPECT_GT(OK, native_window_set_buffers_geometry(anw.get(),  8,  0,  0));
+    EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1,  0,  0));
+    EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(),  0, -1,  0));
+    EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(),  0,  0, -1));
+    EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(), -1, -1,  0));
+    EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(),  0,  8,  0));
+    EXPECT_GT(OK, native_window_set_buffers_geometry(mANW.get(),  8,  0,  0));
 }
 
 TEST_F(SurfaceTextureClientTest, DefaultGeometryValues) {
-    sp<ANativeWindow> anw(mSTC);
     ANativeWindowBuffer* buf;
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(1, buf->width);
     EXPECT_EQ(1, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometryCanBeSet) {
-    sp<ANativeWindow> anw(mSTC);
     ANativeWindowBuffer* buf;
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, PIXEL_FORMAT_RGB_565));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, PIXEL_FORMAT_RGB_565));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(16, buf->width);
     EXPECT_EQ(8, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometryDefaultSizeSetFormat) {
-    sp<ANativeWindow> anw(mSTC);
     ANativeWindowBuffer* buf;
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(1, buf->width);
     EXPECT_EQ(1, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySetSizeDefaultFormat) {
-    sp<ANativeWindow> anw(mSTC);
     ANativeWindowBuffer* buf;
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(16, buf->width);
     EXPECT_EQ(8, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeUnset) {
-    sp<ANativeWindow> anw(mSTC);
     ANativeWindowBuffer* buf;
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(16, buf->width);
     EXPECT_EQ(8, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, 0));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, 0));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(1, buf->width);
     EXPECT_EQ(1, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
 }
 
 TEST_F(SurfaceTextureClientTest, BufferGeometrySizeCanBeChangedWithoutFormat) {
-    sp<ANativeWindow> anw(mSTC);
     ANativeWindowBuffer* buf;
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, PIXEL_FORMAT_RGB_565));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 0, 0, PIXEL_FORMAT_RGB_565));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(1, buf->width);
     EXPECT_EQ(1, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 16, 8, 0));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 16, 8, 0));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(16, buf->width);
     EXPECT_EQ(8, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGB_565, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSize) {
-    sp<ANativeWindow> anw(mSTC);
     sp<SurfaceTexture> st(mST);
     ANativeWindowBuffer* buf;
     EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf));
     EXPECT_EQ(16, buf->width);
     EXPECT_EQ(8, buf->height);
     EXPECT_EQ(PIXEL_FORMAT_RGBA_8888, buf->format);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf));
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeAfterDequeue) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     ANativeWindowBuffer* buf[2];
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
     EXPECT_NE(buf[0], buf[1]);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
-    EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+    EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
     EXPECT_NE(buf[0], buf[1]);
     EXPECT_EQ(16, buf[0]->width);
     EXPECT_EQ(16, buf[1]->width);
     EXPECT_EQ(8, buf[0]->height);
     EXPECT_EQ(8, buf[1]->height);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSetDefaultSizeVsGeometry) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     ANativeWindowBuffer* buf[2];
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
-    EXPECT_EQ(OK, st->setDefaultBufferSize(16, 8));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
+    EXPECT_EQ(OK, mST->setDefaultBufferSize(16, 8));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
     EXPECT_NE(buf[0], buf[1]);
     EXPECT_EQ(16, buf[0]->width);
     EXPECT_EQ(16, buf[1]->width);
     EXPECT_EQ(8, buf[0]->height);
     EXPECT_EQ(8, buf[1]->height);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
-    EXPECT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 12, 24, 0));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
+    EXPECT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 12, 24, 0));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
     EXPECT_NE(buf[0], buf[1]);
     EXPECT_EQ(12, buf[0]->width);
     EXPECT_EQ(12, buf[1]->width);
     EXPECT_EQ(24, buf[0]->height);
     EXPECT_EQ(24, buf[1]->height);
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[1]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[1]));
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureTooManyUpdateTexImage) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     android_native_buffer_t* buf[3];
-    ASSERT_EQ(OK, st->setSynchronousMode(false));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
+    ASSERT_EQ(OK, mST->setSynchronousMode(false));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
 
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(OK, st->updateTexImage());
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
 
-    ASSERT_EQ(OK, st->setSynchronousMode(true));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3));
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
 
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
 
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(OK, st->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(OK, mST->updateTexImage());
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeSlowRetire) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     android_native_buffer_t* buf[3];
-    ASSERT_EQ(OK, st->setSynchronousMode(true));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
     EXPECT_NE(buf[0], buf[1]);
     EXPECT_NE(buf[1], buf[2]);
     EXPECT_NE(buf[2], buf[0]);
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[0]);
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]);
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[2]);
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]);
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeFastRetire) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     android_native_buffer_t* buf[3];
-    ASSERT_EQ(OK, st->setSynchronousMode(true));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 4));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
     EXPECT_NE(buf[0], buf[1]);
     EXPECT_NE(buf[1], buf[2]);
     EXPECT_NE(buf[2], buf[0]);
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[0]);
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]);
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[2]);
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]);
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeDQQR) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     android_native_buffer_t* buf[3];
-    ASSERT_EQ(OK, st->setSynchronousMode(true));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3));
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
 
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[0]);
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[0]);
 
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
     EXPECT_NE(buf[0], buf[1]);
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]);
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
 
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
     EXPECT_NE(buf[1], buf[2]);
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[2]);
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[2]);
 }
 
 // XXX: We currently have no hardware that properly handles dequeuing the
 // buffer that is currently bound to the texture.
 TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeDequeueCurrent) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     android_native_buffer_t* buf[3];
     android_native_buffer_t* firstBuf;
-    ASSERT_EQ(OK, st->setSynchronousMode(true));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &firstBuf));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), firstBuf));
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), firstBuf);
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &firstBuf));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), firstBuf));
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), firstBuf);
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
     EXPECT_NE(buf[0], buf[1]);
     EXPECT_NE(buf[1], buf[2]);
     EXPECT_NE(buf[2], buf[0]);
@@ -426,41 +403,36 @@
 }
 
 TEST_F(SurfaceTextureClientTest, SurfaceTextureSyncModeMinUndequeued) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
     android_native_buffer_t* buf[3];
-    ASSERT_EQ(OK, st->setSynchronousMode(true));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3));
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
 
-    // We should be able to dequeue all the buffers before we've queued any.
-    EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
-    EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
+    // We should be able to dequeue all the buffers before we've queued mANWy.
+    EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+    EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
 
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[2]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
 
-    EXPECT_EQ(OK, st->updateTexImage());
-    EXPECT_EQ(st->getCurrentBuffer().get(), buf[1]);
+    EXPECT_EQ(OK, mST->updateTexImage());
+    EXPECT_EQ(mST->getCurrentBuffer().get(), buf[1]);
 
-    EXPECT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
+    EXPECT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
 
     // Once we've queued a buffer, however we should not be able to dequeue more
     // than (buffer-count - MIN_UNDEQUEUED_BUFFERS), which is 2 in this case.
-    EXPECT_EQ(-EBUSY, anw->dequeueBuffer(anw.get(), &buf[1]));
+    EXPECT_EQ(-EBUSY, mANW->dequeueBuffer(mANW.get(), &buf[1]));
 
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->cancelBuffer(anw.get(), buf[2]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mANW->cancelBuffer(mANW.get(), buf[2]));
 }
 
 // XXX: This is not expected to pass until the synchronization hacks are removed
 // from the SurfaceTexture class.
 TEST_F(SurfaceTextureClientTest, DISABLED_SurfaceTextureSyncModeWaitRetire) {
-    sp<ANativeWindow> anw(mSTC);
-    sp<SurfaceTexture> st(mST);
-
     class MyThread : public Thread {
-        sp<SurfaceTexture> st;
+        sp<SurfaceTexture> mST;
         EGLContext ctx;
         EGLSurface sur;
         EGLDisplay dpy;
@@ -470,14 +442,14 @@
             eglMakeCurrent(dpy, sur, sur, ctx);
             usleep(20000);
             Mutex::Autolock _l(mLock);
-            st->updateTexImage();
+            mST->updateTexImage();
             mBufferRetired = true;
             eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
             return false;
         }
     public:
-        MyThread(const sp<SurfaceTexture>& st)
-            : st(st), mBufferRetired(false) {
+        MyThread(const sp<SurfaceTexture>& mST)
+            : mST(mST), mBufferRetired(false) {
             ctx = eglGetCurrentContext();
             sur = eglGetCurrentSurface(EGL_DRAW);
             dpy = eglGetCurrentDisplay();
@@ -493,25 +465,152 @@
     };
 
     android_native_buffer_t* buf[3];
-    ASSERT_EQ(OK, st->setSynchronousMode(true));
-    ASSERT_EQ(OK, native_window_set_buffer_count(anw.get(), 3));
+    ASSERT_EQ(OK, mST->setSynchronousMode(true));
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 3));
     // dequeue/queue/update so we have a current buffer
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    st->updateTexImage();
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    mST->updateTexImage();
 
-    MyThread* thread = new MyThread(st);
+    MyThread* thread = new MyThread(mST);
     sp<Thread> threadBase(thread);
 
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[0]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[0]));
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[1]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[1]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
     thread->run();
-    ASSERT_EQ(OK, anw->dequeueBuffer(anw.get(), &buf[2]));
-    ASSERT_EQ(OK, anw->queueBuffer(anw.get(), buf[2]));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[1]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[1]));
+    //ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[2]));
+    //ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[2]));
     thread->bufferDequeued();
     thread->requestExitAndWait();
 }
 
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixReturnsVerticalFlip) {
+    android_native_buffer_t* buf[3];
+    float mtx[16] = {};
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mST->updateTexImage());
+    mST->getTransformMatrix(mtx);
+
+    EXPECT_EQ(1.f, mtx[0]);
+    EXPECT_EQ(0.f, mtx[1]);
+    EXPECT_EQ(0.f, mtx[2]);
+    EXPECT_EQ(0.f, mtx[3]);
+
+    EXPECT_EQ(0.f, mtx[4]);
+    EXPECT_EQ(-1.f, mtx[5]);
+    EXPECT_EQ(0.f, mtx[6]);
+    EXPECT_EQ(0.f, mtx[7]);
+
+    EXPECT_EQ(0.f, mtx[8]);
+    EXPECT_EQ(0.f, mtx[9]);
+    EXPECT_EQ(1.f, mtx[10]);
+    EXPECT_EQ(0.f, mtx[11]);
+
+    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(1.f, mtx[13]);
+    EXPECT_EQ(0.f, mtx[14]);
+    EXPECT_EQ(1.f, mtx[15]);
 }
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffers) {
+    android_native_buffer_t* buf[3];
+    float mtx[16] = {};
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mST->updateTexImage());
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
+    mST->getTransformMatrix(mtx);
+
+    EXPECT_EQ(1.f, mtx[0]);
+    EXPECT_EQ(0.f, mtx[1]);
+    EXPECT_EQ(0.f, mtx[2]);
+    EXPECT_EQ(0.f, mtx[3]);
+
+    EXPECT_EQ(0.f, mtx[4]);
+    EXPECT_EQ(-1.f, mtx[5]);
+    EXPECT_EQ(0.f, mtx[6]);
+    EXPECT_EQ(0.f, mtx[7]);
+
+    EXPECT_EQ(0.f, mtx[8]);
+    EXPECT_EQ(0.f, mtx[9]);
+    EXPECT_EQ(1.f, mtx[10]);
+    EXPECT_EQ(0.f, mtx[11]);
+
+    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(1.f, mtx[13]);
+    EXPECT_EQ(0.f, mtx[14]);
+    EXPECT_EQ(1.f, mtx[15]);
+}
+
+TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
+    android_native_buffer_t* buf[3];
+    float mtx[16] = {};
+    android_native_rect_t crop;
+    crop.left = 0;
+    crop.top = 0;
+    crop.right = 5;
+    crop.bottom = 5;
+
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 4));
+    ASSERT_EQ(OK, native_window_set_buffers_geometry(mANW.get(), 8, 8, 0));
+    ASSERT_EQ(OK, mANW->dequeueBuffer(mANW.get(), &buf[0]));
+    ASSERT_EQ(OK, native_window_set_crop(mANW.get(), &crop));
+    ASSERT_EQ(OK, mANW->queueBuffer(mANW.get(), buf[0]));
+    ASSERT_EQ(OK, mST->updateTexImage());
+    ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
+    mST->getTransformMatrix(mtx);
+
+    // This accounts for the 1 texel shrink for each edge that's included in the
+    // transform matrix to avoid texturing outside the crop region.
+    EXPECT_EQ(.5f, mtx[0]);
+    EXPECT_EQ(0.f, mtx[1]);
+    EXPECT_EQ(0.f, mtx[2]);
+    EXPECT_EQ(0.f, mtx[3]);
+
+    EXPECT_EQ(0.f, mtx[4]);
+    EXPECT_EQ(-.5f, mtx[5]);
+    EXPECT_EQ(0.f, mtx[6]);
+    EXPECT_EQ(0.f, mtx[7]);
+
+    EXPECT_EQ(0.f, mtx[8]);
+    EXPECT_EQ(0.f, mtx[9]);
+    EXPECT_EQ(1.f, mtx[10]);
+    EXPECT_EQ(0.f, mtx[11]);
+
+    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(.5f, mtx[13]);
+    EXPECT_EQ(0.f, mtx[14]);
+    EXPECT_EQ(1.f, mtx[15]);
+}
+
+// This test verifies that the buffer format can be queried immediately after
+// it is set.
+TEST_F(SurfaceTextureClientTest, QueryFormatAfterSettingWorks) {
+    sp<ANativeWindow> anw(mSTC);
+    int fmts[] = {
+        // RGBA_8888 should not come first, as it's the default
+        HAL_PIXEL_FORMAT_RGBX_8888,
+        HAL_PIXEL_FORMAT_RGBA_8888,
+        HAL_PIXEL_FORMAT_RGB_888,
+        HAL_PIXEL_FORMAT_RGB_565,
+        HAL_PIXEL_FORMAT_BGRA_8888,
+        HAL_PIXEL_FORMAT_RGBA_5551,
+        HAL_PIXEL_FORMAT_RGBA_4444,
+        HAL_PIXEL_FORMAT_YV12,
+    };
+
+    const int numFmts = (sizeof(fmts) / sizeof(fmts[0]));
+    for (int i = 0; i < numFmts; i++) {
+      int fmt = -1;
+      ASSERT_EQ(OK, native_window_set_buffers_geometry(anw.get(), 0, 0, fmts[i]));
+      ASSERT_EQ(OK, anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt));
+      EXPECT_EQ(fmts[i], fmt);
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 8747ba5..c06400e 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+
 #include <gtest/gtest.h>
 #include <gui/SurfaceTexture.h>
 #include <gui/SurfaceTextureClient.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/String8.h>
+#include <utils/threads.h>
 
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/Surface.h>
@@ -43,8 +46,6 @@
     }
 
     virtual void SetUp() {
-        EGLBoolean returnValue;
-
         mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
@@ -56,9 +57,8 @@
         RecordProperty("EglVersionMajor", majorVersion);
         RecordProperty("EglVersionMajor", minorVersion);
 
-        EGLConfig myConfig = {0};
         EGLint numConfigs = 0;
-        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
+        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &mGlConfig,
                 1, &numConfigs));
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
@@ -84,13 +84,13 @@
             ASSERT_TRUE(mSurfaceControl != NULL);
             ASSERT_TRUE(mSurfaceControl->isValid());
 
-            ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
-            ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
+            SurfaceComposerClient::openGlobalTransaction();
+            ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
             ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-            ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+            SurfaceComposerClient::closeGlobalTransaction();
 
             sp<ANativeWindow> window = mSurfaceControl->getSurface();
-            mEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
+            mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
                     window.get(), NULL);
         } else {
             EGLint pbufferAttribs[] = {
@@ -98,13 +98,13 @@
                 EGL_HEIGHT, getSurfaceHeight(),
                 EGL_NONE };
 
-            mEglSurface = eglCreatePbufferSurface(mEglDisplay, myConfig,
+            mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
                     pbufferAttribs);
         }
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
 
-        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
+        mEglContext = eglCreateContext(mEglDisplay, mGlConfig, EGL_NO_CONTEXT,
                 getContextAttribs());
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
@@ -173,11 +173,11 @@
     }
 
     virtual EGLint getSurfaceWidth() {
-        return 64;
+        return 512;
     }
 
     virtual EGLint getSurfaceHeight() {
-        return 64;
+        return 512;
     }
 
     void loadShader(GLenum shaderType, const char* pSource, GLuint* outShader) {
@@ -270,8 +270,12 @@
         *outPgm = program;
     }
 
+    static int abs(int value) {
+        return value > 0 ? value : -value;
+    }
+
     ::testing::AssertionResult checkPixel(int x, int y, int r,
-            int g, int b, int a) {
+            int g, int b, int a, int tolerance=2) {
         GLubyte pixel[4];
         String8 msg;
         glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
@@ -285,22 +289,22 @@
             return ::testing::AssertionFailure(
                     ::testing::Message(msg.string()));
         }
-        if (r >= 0 && GLubyte(r) != pixel[0]) {
+        if (r >= 0 && abs(r - int(pixel[0])) > tolerance) {
             msg += String8::format("r(%d isn't %d)", pixel[0], r);
         }
-        if (g >= 0 && GLubyte(g) != pixel[1]) {
+        if (g >= 0 && abs(g - int(pixel[1])) > tolerance) {
             if (!msg.isEmpty()) {
                 msg += " ";
             }
             msg += String8::format("g(%d isn't %d)", pixel[1], g);
         }
-        if (b >= 0 && GLubyte(b) != pixel[2]) {
+        if (b >= 0 && abs(b - int(pixel[2])) > tolerance) {
             if (!msg.isEmpty()) {
                 msg += " ";
             }
             msg += String8::format("b(%d isn't %d)", pixel[2], b);
         }
-        if (a >= 0 && GLubyte(a) != pixel[3]) {
+        if (a >= 0 && abs(a - int(pixel[3])) > tolerance) {
             if (!msg.isEmpty()) {
                 msg += " ";
             }
@@ -322,6 +326,7 @@
     EGLDisplay mEglDisplay;
     EGLSurface mEglSurface;
     EGLContext mEglContext;
+    EGLConfig  mGlConfig;
 };
 
 // XXX: Code above this point should live elsewhere
@@ -394,6 +399,18 @@
         glBindTexture(GL_TEXTURE_EXTERNAL_OES, TEX_ID);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
 
+        // XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as
+        // they're setting the defautls for that target, but when hacking things
+        // to use GL_TEXTURE_2D they are needed to achieve the same behavior.
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
         GLfloat texMatrix[16];
         mST->getTransformMatrix(texMatrix);
         glUniformMatrix4fv(mTexMatrixHandle, 1, GL_FALSE, texMatrix);
@@ -402,6 +419,31 @@
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
     }
 
+    class FrameWaiter : public SurfaceTexture::FrameAvailableListener {
+    public:
+        FrameWaiter():
+                mPendingFrames(0) {
+        }
+
+        void waitForFrame() {
+            Mutex::Autolock lock(mMutex);
+            while (mPendingFrames == 0) {
+                mCondition.wait(mMutex);
+            }
+            mPendingFrames--;
+        }
+
+        virtual void onFrameAvailable() {
+            Mutex::Autolock lock(mMutex);
+            mPendingFrames++;
+            mCondition.signal();
+        }
+
+        int mPendingFrames;
+        Mutex mMutex;
+        Condition mCondition;
+    };
+
     sp<SurfaceTexture> mST;
     sp<SurfaceTextureClient> mSTC;
     sp<ANativeWindow> mANW;
@@ -467,12 +509,26 @@
     }
 }
 
+void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
+    const size_t PIXEL_SIZE = 4;
+    for (int x = 0; x < w; x++) {
+        for (int y = 0; y < h; y++) {
+            off_t offset = (y * stride + x) * PIXEL_SIZE;
+            for (int c = 0; c < 4; c++) {
+                int parityX = (x / (1 << (c+2))) & 1;
+                int parityY = (y / (1 << (c+2))) & 1;
+                buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
+            }
+        }
+    }
+}
+
 TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
-    const int yuvTexWidth = 64;
-    const int yuvTexHeight = 66;
+    const int texWidth = 64;
+    const int texHeight = 66;
 
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
-            yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
+            texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
     ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
             GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
 
@@ -486,7 +542,7 @@
     // Fill the buffer with the a checkerboard pattern
     uint8_t* img = NULL;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
-    fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
+    fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
     buf->unlock();
     ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
 
@@ -495,32 +551,29 @@
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    glViewport(0, 0, texWidth, texHeight);
     drawTexture();
 
     EXPECT_TRUE(checkPixel( 0,  0, 255, 127, 255, 255));
     EXPECT_TRUE(checkPixel(63,  0,   0, 133,   0, 255));
-    EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
-    EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(63, 65,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel( 0, 65, 255, 127, 255, 255));
 
-    EXPECT_TRUE(checkPixel(22, 44, 247,  70, 255, 255));
-    EXPECT_TRUE(checkPixel(45, 52, 209,  32, 235, 255));
-    EXPECT_TRUE(checkPixel(52, 51, 100, 255,  73, 255));
+    EXPECT_TRUE(checkPixel(22, 44, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(45, 52, 255, 127, 255, 255));
+    EXPECT_TRUE(checkPixel(52, 51,  98, 255,  73, 255));
     EXPECT_TRUE(checkPixel( 7, 31, 155,   0, 118, 255));
-    EXPECT_TRUE(checkPixel(31,  9, 148,  71, 110, 255));
+    EXPECT_TRUE(checkPixel(31,  9, 107,  24,  87, 255));
     EXPECT_TRUE(checkPixel(29, 35, 255, 127, 255, 255));
     EXPECT_TRUE(checkPixel(36, 22, 155,  29,   0, 255));
 }
 
-// XXX: This test is disabled because it it currently broken on all devices to
-// which I have access.  Some of the checkPixel calls are not correct because
-// I just copied them from the npot test above and haven't bothered to figure
-// out the correct values.
-TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledYV12BufferPow2) {
-    const int yuvTexWidth = 64;
-    const int yuvTexHeight = 64;
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferPow2) {
+    const int texWidth = 64;
+    const int texHeight = 64;
 
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
-            yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
+            texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
     ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
             GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
 
@@ -534,7 +587,7 @@
     // Fill the buffer with the a checkerboard pattern
     uint8_t* img = NULL;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
-    fillYV12Buffer(img, yuvTexWidth, yuvTexHeight, buf->getStride());
+    fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
     buf->unlock();
     ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
 
@@ -543,28 +596,29 @@
     glClearColor(0.2, 0.2, 0.2, 0.2);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    glViewport(0, 0, texWidth, texHeight);
     drawTexture();
 
-    EXPECT_TRUE(checkPixel( 0,  0, 255, 127, 255, 255));
-    EXPECT_TRUE(checkPixel(63,  0,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel( 0,  0,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel(63,  0, 255, 127, 255, 255));
     EXPECT_TRUE(checkPixel(63, 63,   0, 133,   0, 255));
     EXPECT_TRUE(checkPixel( 0, 63, 255, 127, 255, 255));
 
-    EXPECT_TRUE(checkPixel(22, 19, 247,  70, 255, 255));
-    EXPECT_TRUE(checkPixel(45, 11, 209,  32, 235, 255));
-    EXPECT_TRUE(checkPixel(52, 12, 100, 255,  73, 255));
-    EXPECT_TRUE(checkPixel( 7, 32, 155,   0, 118, 255));
-    EXPECT_TRUE(checkPixel(31, 54, 148,  71, 110, 255));
-    EXPECT_TRUE(checkPixel(29, 28, 255, 127, 255, 255));
-    EXPECT_TRUE(checkPixel(36, 41, 155,  29,   0, 255));
+    EXPECT_TRUE(checkPixel(22, 19, 100, 255,  74, 255));
+    EXPECT_TRUE(checkPixel(45, 11, 100, 255,  74, 255));
+    EXPECT_TRUE(checkPixel(52, 12, 155,   0, 181, 255));
+    EXPECT_TRUE(checkPixel( 7, 32, 150, 237, 170, 255));
+    EXPECT_TRUE(checkPixel(31, 54,   0,  71, 117, 255));
+    EXPECT_TRUE(checkPixel(29, 28,   0, 133,   0, 255));
+    EXPECT_TRUE(checkPixel(36, 41, 100, 232, 255, 255));
 }
 
 TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferWithCrop) {
-    const int yuvTexWidth = 64;
-    const int yuvTexHeight = 66;
+    const int texWidth = 64;
+    const int texHeight = 66;
 
     ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
-            yuvTexWidth, yuvTexHeight, HAL_PIXEL_FORMAT_YV12));
+            texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
     ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
             GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
 
@@ -572,8 +626,8 @@
         {4, 6, 22, 36},
         {0, 6, 22, 36},
         {4, 0, 22, 36},
-        {4, 6, yuvTexWidth, 36},
-        {4, 6, 22, yuvTexHeight},
+        {4, 6, texWidth, 36},
+        {4, 6, 22, texHeight},
     };
 
     for (int i = 0; i < 5; i++) {
@@ -592,7 +646,7 @@
 
         uint8_t* img = NULL;
         buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
-        fillYV12BufferRect(img, yuvTexWidth, yuvTexHeight, buf->getStride(), crop);
+        fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
         buf->unlock();
         ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
 
@@ -601,6 +655,7 @@
         glClearColor(0.2, 0.2, 0.2, 0.2);
         glClear(GL_COLOR_BUFFER_BIT);
 
+        glViewport(0, 0, 64, 64);
         drawTexture();
 
         EXPECT_TRUE(checkPixel( 0,  0,  82, 255,  35, 255));
@@ -618,4 +673,607 @@
     }
 }
 
+// This test is intended to catch synchronization bugs between the CPU-written
+// and GPU-read buffers.
+TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BuffersRepeatedly) {
+    enum { texWidth = 16 };
+    enum { texHeight = 16 };
+    enum { numFrames = 1024 };
+
+    ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
+    ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            texWidth, texHeight, HAL_PIXEL_FORMAT_YV12));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    struct TestPixel {
+        int x;
+        int y;
+    };
+    const TestPixel testPixels[] = {
+        {  4, 11 },
+        { 12, 14 },
+        {  7,  2 },
+    };
+    enum {numTestPixels = sizeof(testPixels) / sizeof(testPixels[0])};
+
+    class ProducerThread : public Thread {
+    public:
+        ProducerThread(const sp<ANativeWindow>& anw, const TestPixel* testPixels):
+                mANW(anw),
+                mTestPixels(testPixels) {
+        }
+
+        virtual ~ProducerThread() {
+        }
+
+        virtual bool threadLoop() {
+            for (int i = 0; i < numFrames; i++) {
+                ANativeWindowBuffer* anb;
+                if (mANW->dequeueBuffer(mANW.get(), &anb) != NO_ERROR) {
+                    return false;
+                }
+                if (anb == NULL) {
+                    return false;
+                }
+
+                sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+                if (mANW->lockBuffer(mANW.get(), buf->getNativeBuffer())
+                        != NO_ERROR) {
+                    return false;
+                }
+
+                const int yuvTexOffsetY = 0;
+                int stride = buf->getStride();
+                int yuvTexStrideY = stride;
+                int yuvTexOffsetV = yuvTexStrideY * texHeight;
+                int yuvTexStrideV = (yuvTexStrideY/2 + 0xf) & ~0xf;
+                int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
+                int yuvTexStrideU = yuvTexStrideV;
+
+                uint8_t* img = NULL;
+                buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+
+                // Gray out all the test pixels first, so we're more likely to
+                // see a failure if GL is still texturing from the buffer we
+                // just dequeued.
+                for (int j = 0; j < numTestPixels; j++) {
+                    int x = mTestPixels[j].x;
+                    int y = mTestPixels[j].y;
+                    uint8_t value = 128;
+                    img[y*stride + x] = value;
+                }
+
+                // Fill the buffer with gray.
+                for (int y = 0; y < texHeight; y++) {
+                    for (int x = 0; x < texWidth; x++) {
+                        img[yuvTexOffsetY + y*yuvTexStrideY + x] = 128;
+                        img[yuvTexOffsetU + (y/2)*yuvTexStrideU + x/2] = 128;
+                        img[yuvTexOffsetV + (y/2)*yuvTexStrideV + x/2] = 128;
+                    }
+                }
+
+                // Set the test pixels to either white or black.
+                for (int j = 0; j < numTestPixels; j++) {
+                    int x = mTestPixels[j].x;
+                    int y = mTestPixels[j].y;
+                    uint8_t value = 0;
+                    if (j == (i % numTestPixels)) {
+                        value = 255;
+                    }
+                    img[y*stride + x] = value;
+                }
+
+                buf->unlock();
+                if (mANW->queueBuffer(mANW.get(), buf->getNativeBuffer())
+                        != NO_ERROR) {
+                    return false;
+                }
+            }
+            return false;
+        }
+
+        sp<ANativeWindow> mANW;
+        const TestPixel* mTestPixels;
+    };
+
+    sp<FrameWaiter> fw(new FrameWaiter);
+    mST->setFrameAvailableListener(fw);
+
+    sp<Thread> pt(new ProducerThread(mANW, testPixels));
+    pt->run();
+
+    glViewport(0, 0, texWidth, texHeight);
+
+    glClearColor(0.2, 0.2, 0.2, 0.2);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    // We wait for the first two frames up front so that the producer will be
+    // likely to dequeue the buffer that's currently being textured from.
+    fw->waitForFrame();
+    fw->waitForFrame();
+
+    for (int i = 0; i < numFrames; i++) {
+        SCOPED_TRACE(String8::format("frame %d", i).string());
+
+        // We must wait for each frame to come in because if we ever do an
+        // updateTexImage call that doesn't consume a newly available buffer
+        // then the producer and consumer will get out of sync, which will cause
+        // a deadlock.
+        if (i > 1) {
+            fw->waitForFrame();
+        }
+        mST->updateTexImage();
+        drawTexture();
+
+        for (int j = 0; j < numTestPixels; j++) {
+            int x = testPixels[j].x;
+            int y = testPixels[j].y;
+            uint8_t value = 0;
+            if (j == (i % numTestPixels)) {
+                // We must y-invert the texture coords
+                EXPECT_TRUE(checkPixel(x, texHeight-y-1, 255, 255, 255, 255));
+            } else {
+                // We must y-invert the texture coords
+                EXPECT_TRUE(checkPixel(x, texHeight-y-1, 0, 0, 0, 255));
+            }
+        }
+    }
+
+    pt->requestExitAndWait();
 }
+
+// XXX: This test is disabled because there are currently no drivers that can
+// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
+TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferNpot) {
+    const int texWidth = 64;
+    const int texHeight = 66;
+
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    android_native_buffer_t* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
+
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    // Fill the buffer with the a checkerboard pattern
+    uint8_t* img = NULL;
+    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
+    buf->unlock();
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    mST->updateTexImage();
+
+    glClearColor(0.2, 0.2, 0.2, 0.2);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glViewport(0, 0, texWidth, texHeight);
+    drawTexture();
+
+    EXPECT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
+    EXPECT_TRUE(checkPixel(63,  0, 231, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(63, 65, 231, 231, 231, 231));
+    EXPECT_TRUE(checkPixel( 0, 65,  35,  35,  35,  35));
+
+    EXPECT_TRUE(checkPixel(15, 10,  35, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(19, 40,  35, 231,  35,  35));
+    EXPECT_TRUE(checkPixel(38, 30, 231,  35,  35,  35));
+    EXPECT_TRUE(checkPixel(42, 54,  35,  35,  35, 231));
+    EXPECT_TRUE(checkPixel(37, 33, 228,  38,  38,  38));
+    EXPECT_TRUE(checkPixel(31,  8, 231,  35,  35, 231));
+    EXPECT_TRUE(checkPixel(36, 47, 228,  35, 231, 231));
+    EXPECT_TRUE(checkPixel(24, 63,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(48,  3, 228, 228,  38,  35));
+    EXPECT_TRUE(checkPixel(54, 50,  35, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(24, 25,  41,  41, 231, 231));
+    EXPECT_TRUE(checkPixel(10,  9,  38,  38, 231, 231));
+    EXPECT_TRUE(checkPixel(29,  4,  35,  35,  35, 231));
+    EXPECT_TRUE(checkPixel(56, 31,  38, 228, 231,  35));
+    EXPECT_TRUE(checkPixel(58, 55,  35,  35, 231, 231));
+}
+
+// XXX: This test is disabled because there are currently no drivers that can
+// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
+TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromCpuFilledRGBABufferPow2) {
+    const int texWidth = 64;
+    const int texHeight = 64;
+
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
+
+    android_native_buffer_t* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
+
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    // Fill the buffer with the a checkerboard pattern
+    uint8_t* img = NULL;
+    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    fillRGBA8Buffer(img, texWidth, texHeight, buf->getStride());
+    buf->unlock();
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    mST->updateTexImage();
+
+    glClearColor(0.2, 0.2, 0.2, 0.2);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glViewport(0, 0, texWidth, texHeight);
+    drawTexture();
+
+    EXPECT_TRUE(checkPixel( 0,  0, 231, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(63,  0,  35,  35,  35,  35));
+    EXPECT_TRUE(checkPixel(63, 63, 231, 231, 231, 231));
+    EXPECT_TRUE(checkPixel( 0, 63,  35,  35,  35,  35));
+
+    EXPECT_TRUE(checkPixel(12, 46, 231, 231, 231,  35));
+    EXPECT_TRUE(checkPixel(16,  1, 231, 231,  35, 231));
+    EXPECT_TRUE(checkPixel(21, 12, 231,  35,  35, 231));
+    EXPECT_TRUE(checkPixel(26, 51, 231,  35, 231,  35));
+    EXPECT_TRUE(checkPixel( 5, 32,  35, 231, 231,  35));
+    EXPECT_TRUE(checkPixel(13,  8,  35, 231, 231, 231));
+    EXPECT_TRUE(checkPixel(46,  3,  35,  35, 231,  35));
+    EXPECT_TRUE(checkPixel(30, 33,  35,  35,  35,  35));
+    EXPECT_TRUE(checkPixel( 6, 52, 231, 231,  35,  35));
+    EXPECT_TRUE(checkPixel(55, 33,  35, 231,  35, 231));
+    EXPECT_TRUE(checkPixel(16, 29,  35,  35, 231, 231));
+    EXPECT_TRUE(checkPixel( 1, 30,  35,  35,  35, 231));
+    EXPECT_TRUE(checkPixel(41, 37,  35,  35, 231, 231));
+    EXPECT_TRUE(checkPixel(46, 29, 231, 231,  35,  35));
+    EXPECT_TRUE(checkPixel(15, 25,  35, 231,  35, 231));
+    EXPECT_TRUE(checkPixel( 3, 52,  35, 231,  35,  35));
+}
+
+// XXX: This test is disabled because there are currently no drivers that can
+// handle RGBA textures with the GL_TEXTURE_EXTERNAL_OES target.
+TEST_F(SurfaceTextureGLTest, DISABLED_TexturingFromGLFilledRGBABufferPow2) {
+    const int texWidth = 64;
+    const int texHeight = 64;
+
+    mST->setDefaultBufferSize(texWidth, texHeight);
+
+    // Do the producer side of things
+    EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
+            mANW.get(), NULL);
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
+
+    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
+            mEglContext));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    glClearColor(0.6, 0.6, 0.6, 0.6);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glEnable(GL_SCISSOR_TEST);
+    glScissor(4, 4, 4, 4);
+    glClearColor(1.0, 0.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glScissor(24, 48, 4, 4);
+    glClearColor(0.0, 1.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glScissor(37, 17, 4, 4);
+    glClearColor(0.0, 0.0, 1.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    eglSwapBuffers(mEglDisplay, stcEglSurface);
+
+    // Do the consumer side of things
+    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+            mEglContext));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    glDisable(GL_SCISSOR_TEST);
+
+    mST->updateTexImage();
+
+    glClearColor(0.2, 0.2, 0.2, 0.2);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glViewport(0, 0, texWidth, texHeight);
+    drawTexture();
+
+    EXPECT_TRUE(checkPixel( 0,  0, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(63,  0, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
+
+    EXPECT_TRUE(checkPixel( 4,  7, 255,   0,   0, 255));
+    EXPECT_TRUE(checkPixel(25, 51,   0, 255,   0, 255));
+    EXPECT_TRUE(checkPixel(40, 19,   0,   0, 255, 255));
+    EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(13,  8, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(46,  3, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
+}
+
+/*
+ * This test is for testing GL -> GL texture streaming via SurfaceTexture.  It
+ * contains functionality to create a producer thread that will perform GL
+ * rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
+ * Additionally it supports interlocking the producer and consumer threads so
+ * that a specific sequence of calls can be deterministically created by the
+ * test.
+ *
+ * The intended usage is as follows:
+ *
+ * TEST_F(...) {
+ *     class PT : public ProducerThread {
+ *         virtual void render() {
+ *             ...
+ *             swapBuffers();
+ *         }
+ *     };
+ *
+ *     runProducerThread(new PT());
+ *
+ *     // The order of these calls will vary from test to test and may include
+ *     // multiple frames and additional operations (e.g. GL rendering from the
+ *     // texture).
+ *     fc->waitForFrame();
+ *     mST->updateTexImage();
+ *     fc->finishFrame();
+ * }
+ *
+ */
+class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
+protected:
+
+    // ProducerThread is an abstract base class to simplify the creation of
+    // OpenGL ES frame producer threads.
+    class ProducerThread : public Thread {
+    public:
+        virtual ~ProducerThread() {
+        }
+
+        void setEglObjects(EGLDisplay producerEglDisplay,
+                EGLSurface producerEglSurface,
+                EGLContext producerEglContext) {
+            mProducerEglDisplay = producerEglDisplay;
+            mProducerEglSurface = producerEglSurface;
+            mProducerEglContext = producerEglContext;
+        }
+
+        virtual bool threadLoop() {
+            eglMakeCurrent(mProducerEglDisplay, mProducerEglSurface,
+                    mProducerEglSurface, mProducerEglContext);
+            render();
+            eglMakeCurrent(mProducerEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                    EGL_NO_CONTEXT);
+            return false;
+        }
+
+    protected:
+        virtual void render() = 0;
+
+        void swapBuffers() {
+            eglSwapBuffers(mProducerEglDisplay, mProducerEglSurface);
+        }
+
+        EGLDisplay mProducerEglDisplay;
+        EGLSurface mProducerEglSurface;
+        EGLContext mProducerEglContext;
+    };
+
+    // FrameCondition is a utility class for interlocking between the producer
+    // and consumer threads.  The FrameCondition object should be created and
+    // destroyed in the consumer thread only.  The consumer thread should set
+    // the FrameCondition as the FrameAvailableListener of the SurfaceTexture,
+    // and should call both waitForFrame and finishFrame once for each expected
+    // frame.
+    //
+    // This interlocking relies on the fact that onFrameAvailable gets called
+    // synchronously from SurfaceTexture::queueBuffer.
+    class FrameCondition : public SurfaceTexture::FrameAvailableListener {
+    public:
+        // waitForFrame waits for the next frame to arrive.  This should be
+        // called from the consumer thread once for every frame expected by the
+        // test.
+        void waitForFrame() {
+            LOGV("+waitForFrame");
+            Mutex::Autolock lock(mMutex);
+            status_t result = mFrameAvailableCondition.wait(mMutex);
+            LOGV("-waitForFrame");
+        }
+
+        // Allow the producer to return from its swapBuffers call and continue
+        // on to produce the next frame.  This should be called by the consumer
+        // thread once for every frame expected by the test.
+        void finishFrame() {
+            LOGV("+finishFrame");
+            Mutex::Autolock lock(mMutex);
+            mFrameFinishCondition.signal();
+            LOGV("-finishFrame");
+        }
+
+        // This should be called by SurfaceTexture on the producer thread.
+        virtual void onFrameAvailable() {
+            LOGV("+onFrameAvailable");
+            Mutex::Autolock lock(mMutex);
+            mFrameAvailableCondition.signal();
+            mFrameFinishCondition.wait(mMutex);
+            LOGV("-onFrameAvailable");
+        }
+
+    protected:
+        Mutex mMutex;
+        Condition mFrameAvailableCondition;
+        Condition mFrameFinishCondition;
+    };
+
+    SurfaceTextureGLToGLTest():
+            mProducerEglSurface(EGL_NO_SURFACE),
+            mProducerEglContext(EGL_NO_CONTEXT) {
+    }
+
+    virtual void SetUp() {
+        SurfaceTextureGLTest::SetUp();
+
+        EGLConfig myConfig = {0};
+        EGLint numConfigs = 0;
+        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
+                1, &numConfigs));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
+                mANW.get(), NULL);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
+
+        mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
+                EGL_NO_CONTEXT, getContextAttribs());
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
+
+        mFC = new FrameCondition();
+        mST->setFrameAvailableListener(mFC);
+    }
+
+    virtual void TearDown() {
+        if (mProducerThread != NULL) {
+            mProducerThread->requestExitAndWait();
+        }
+        if (mProducerEglContext != EGL_NO_CONTEXT) {
+            eglDestroyContext(mEglDisplay, mProducerEglContext);
+        }
+        if (mProducerEglSurface != EGL_NO_SURFACE) {
+            eglDestroySurface(mEglDisplay, mProducerEglSurface);
+        }
+        mProducerThread.clear();
+        mFC.clear();
+    }
+
+    void runProducerThread(const sp<ProducerThread> producerThread) {
+        ASSERT_TRUE(mProducerThread == NULL);
+        mProducerThread = producerThread;
+        producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
+                mProducerEglContext);
+        producerThread->run();
+    }
+
+    EGLSurface mProducerEglSurface;
+    EGLContext mProducerEglContext;
+    sp<ProducerThread> mProducerThread;
+    sp<FrameCondition> mFC;
+};
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageBeforeFrameFinishedWorks) {
+    class PT : public ProducerThread {
+        virtual void render() {
+            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
+            swapBuffers();
+        }
+    };
+
+    runProducerThread(new PT());
+
+    mFC->waitForFrame();
+    mST->updateTexImage();
+    mFC->finishFrame();
+
+    // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_UpdateTexImageAfterFrameFinishedWorks) {
+    class PT : public ProducerThread {
+        virtual void render() {
+            glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+            glClear(GL_COLOR_BUFFER_BIT);
+            swapBuffers();
+        }
+    };
+
+    runProducerThread(new PT());
+
+    mFC->waitForFrame();
+    mFC->finishFrame();
+    mST->updateTexImage();
+
+    // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageBeforeFrameFinishedWorks) {
+    enum { NUM_ITERATIONS = 1024 };
+
+    class PT : public ProducerThread {
+        virtual void render() {
+            for (int i = 0; i < NUM_ITERATIONS; i++) {
+                glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+                glClear(GL_COLOR_BUFFER_BIT);
+                LOGV("+swapBuffers");
+                swapBuffers();
+                LOGV("-swapBuffers");
+            }
+        }
+    };
+
+    runProducerThread(new PT());
+
+    for (int i = 0; i < NUM_ITERATIONS; i++) {
+        mFC->waitForFrame();
+        LOGV("+updateTexImage");
+        mST->updateTexImage();
+        LOGV("-updateTexImage");
+        mFC->finishFrame();
+
+        // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+    }
+}
+
+// XXX: This test is disabled because it causes hangs on some devices.
+TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedUpdateTexImageAfterFrameFinishedWorks) {
+    enum { NUM_ITERATIONS = 1024 };
+
+    class PT : public ProducerThread {
+        virtual void render() {
+            for (int i = 0; i < NUM_ITERATIONS; i++) {
+                glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+                glClear(GL_COLOR_BUFFER_BIT);
+                LOGV("+swapBuffers");
+                swapBuffers();
+                LOGV("-swapBuffers");
+            }
+        }
+    };
+
+    runProducerThread(new PT());
+
+    for (int i = 0; i < NUM_ITERATIONS; i++) {
+        mFC->waitForFrame();
+        mFC->finishFrame();
+        LOGV("+updateTexImage");
+        mST->updateTexImage();
+        LOGV("-updateTexImage");
+
+        // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
+    }
+}
+
+} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 35c8640..450cdf1 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -36,10 +36,10 @@
         ASSERT_TRUE(mSurfaceControl != NULL);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
-        ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+        SurfaceComposerClient::openGlobalTransaction();
         ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
         ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
-        ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+        SurfaceComposerClient::closeGlobalTransaction();
 
         mSurface = mSurfaceControl->getSurface();
         ASSERT_TRUE(mSurface != NULL);
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index f9990bb..427bbba 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -43,7 +43,6 @@
 LOCAL_SRC_FILES:= \
 	$(commonSources) \
 	EGLUtils.cpp \
-	EventRecurrence.cpp \
 	FramebufferNativeWindow.cpp \
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
diff --git a/libs/ui/EventRecurrence.cpp b/libs/ui/EventRecurrence.cpp
deleted file mode 100644
index b436b50..0000000
--- a/libs/ui/EventRecurrence.cpp
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- *  Copyright 2006 The Android Open Source Project
- */
-
-#include <pim/EventRecurrence.h>
-#include <utils/String8.h>
-#include <stdio.h>
-#include <limits.h>
-
-namespace android {
-
-#define FAIL_HERE() do { \
-            printf("Parsing failed at line %d\n", __LINE__); \
-            return UNKNOWN_ERROR; \
-        } while(0)
-
-EventRecurrence::EventRecurrence()
-    :freq((freq_t)0),
-     until(),
-     count(0),
-     interval(0),
-     bysecond(0),
-     bysecondCount(0),
-     byminute(0),
-     byminuteCount(0),
-     byhour(0),
-     byhourCount(0),
-     byday(0),
-     bydayNum(0),
-     bydayCount(0),
-     bymonthday(0),
-     bymonthdayCount(0),
-     byyearday(0),
-     byyeardayCount(0),
-     byweekno(0),
-     byweeknoCount(0),
-     bymonth(0),
-     bymonthCount(0),
-     bysetpos(0),
-     bysetposCount(0),
-     wkst(0)
-{
-}
-
-EventRecurrence::~EventRecurrence()
-{
-    delete[] bysecond;
-    delete[] byminute;
-    delete[] byhour;
-    delete[] byday;
-    delete[] bydayNum;
-    delete[] byyearday;
-    delete[] bymonthday;
-    delete[] byweekno;
-    delete[] bymonth;
-    delete[] bysetpos;
-}
-
-enum LHS {
-    NONE_LHS = 0,
-    FREQ,
-    UNTIL,
-    COUNT,
-    INTERVAL,
-    BYSECOND,
-    BYMINUTE,
-    BYHOUR,
-    BYDAY,
-    BYMONTHDAY,
-    BYYEARDAY,
-    BYWEEKNO,
-    BYMONTH,
-    BYSETPOS,
-    WKST
-};
-
-struct LHSProc
-{
-    const char16_t* text;
-    size_t textSize;
-    uint32_t value;
-};
-
-const char16_t FREQ_text[] = { 'F', 'R', 'E', 'Q' };
-const char16_t UNTIL_text[] = { 'U', 'N', 'T', 'I', 'L' };
-const char16_t COUNT_text[] = { 'C', 'O', 'U', 'N', 'T' };
-const char16_t INTERVAL_text[] = { 'I', 'N', 'T', 'E', 'R', 'V', 'A', 'L'};
-const char16_t BYSECOND_text[] = { 'B', 'Y', 'S', 'E', 'C', 'O', 'N', 'D' };
-const char16_t BYMINUTE_text[] = { 'B', 'Y', 'M', 'I', 'N', 'U', 'T', 'E' };
-const char16_t BYHOUR_text[] = { 'B', 'Y', 'H', 'O', 'U', 'R' };
-const char16_t BYDAY_text[] = { 'B', 'Y', 'D', 'A', 'Y' };
-const char16_t BYMONTHDAY_text[] = { 'B','Y','M','O','N','T','H','D','A','Y' };
-const char16_t BYYEARDAY_text[] = { 'B','Y','Y','E','A','R','D','A','Y' };
-const char16_t BYWEEKNO_text[] = { 'B', 'Y', 'W', 'E', 'E', 'K', 'N', 'O' };
-const char16_t BYMONTH_text[] = { 'B', 'Y', 'M', 'O', 'N', 'T', 'H' };
-const char16_t BYSETPOS_text[] = { 'B', 'Y', 'S', 'E', 'T', 'P', 'O', 'S' };
-const char16_t WKST_text[] = { 'W', 'K', 'S', 'T' };
-
-#define SIZ(x) (sizeof(x)/sizeof(x[0]))
-
-const LHSProc LHSPROC[] = {
-    { FREQ_text, SIZ(FREQ_text), FREQ },
-    { UNTIL_text, SIZ(UNTIL_text), UNTIL },
-    { COUNT_text, SIZ(COUNT_text), COUNT },
-    { INTERVAL_text, SIZ(INTERVAL_text), INTERVAL },
-    { BYSECOND_text, SIZ(BYSECOND_text), BYSECOND },
-    { BYMINUTE_text, SIZ(BYMINUTE_text), BYMINUTE },
-    { BYHOUR_text, SIZ(BYHOUR_text), BYHOUR },
-    { BYDAY_text, SIZ(BYDAY_text), BYDAY },
-    { BYMONTHDAY_text, SIZ(BYMONTHDAY_text), BYMONTHDAY },
-    { BYYEARDAY_text, SIZ(BYYEARDAY_text), BYYEARDAY },
-    { BYWEEKNO_text, SIZ(BYWEEKNO_text), BYWEEKNO },
-    { BYMONTH_text, SIZ(BYMONTH_text), BYMONTH },
-    { BYSETPOS_text, SIZ(BYSETPOS_text), BYSETPOS },
-    { WKST_text, SIZ(WKST_text), WKST },
-    { NULL, 0, NONE_LHS },
-};
-
-const char16_t SECONDLY_text[] = { 'S','E','C','O','N','D','L','Y' };
-const char16_t MINUTELY_text[] = { 'M','I','N','U','T','E','L','Y' };
-const char16_t HOURLY_text[] = { 'H','O','U','R','L','Y' };
-const char16_t DAILY_text[] = { 'D','A','I','L','Y' };
-const char16_t WEEKLY_text[] = { 'W','E','E','K','L','Y' };
-const char16_t MONTHLY_text[] = { 'M','O','N','T','H','L','Y' };
-const char16_t YEARLY_text[] = { 'Y','E','A','R','L','Y' };
-
-typedef LHSProc FreqProc;
-
-const FreqProc FREQPROC[] = {
-    { SECONDLY_text, SIZ(SECONDLY_text), EventRecurrence::SECONDLY },
-    { MINUTELY_text, SIZ(MINUTELY_text), EventRecurrence::MINUTELY },
-    { HOURLY_text, SIZ(HOURLY_text), EventRecurrence::HOURLY },
-    { DAILY_text, SIZ(DAILY_text), EventRecurrence::DAILY },
-    { WEEKLY_text, SIZ(WEEKLY_text), EventRecurrence::WEEKLY },
-    { MONTHLY_text, SIZ(MONTHLY_text), EventRecurrence::MONTHLY },
-    { YEARLY_text, SIZ(YEARLY_text), EventRecurrence::YEARLY },
-    { NULL, 0, NONE_LHS },
-};
-
-const char16_t SU_text[] = { 'S','U' };
-const char16_t MO_text[] = { 'M','O' };
-const char16_t TU_text[] = { 'T','U' };
-const char16_t WE_text[] = { 'W','E' };
-const char16_t TH_text[] = { 'T','H' };
-const char16_t FR_text[] = { 'F','R' };
-const char16_t SA_text[] = { 'S','A' };
-
-const FreqProc WEEKDAYPROC[] = {
-    { SU_text, SIZ(SU_text), EventRecurrence::SU },
-    { MO_text, SIZ(MO_text), EventRecurrence::MO },
-    { TU_text, SIZ(TU_text), EventRecurrence::TU },
-    { WE_text, SIZ(WE_text), EventRecurrence::WE },
-    { TH_text, SIZ(TH_text), EventRecurrence::TH },
-    { FR_text, SIZ(FR_text), EventRecurrence::FR },
-    { SA_text, SIZ(SA_text), EventRecurrence::SA },
-    { NULL, 0, NONE_LHS },
-};
-
-// returns the index into LHSPROC for the match or -1 if not found
-inline static int
-match_proc(const LHSProc* p, const char16_t* str, size_t len)
-{
-    int i = 0;
-    while (p->text != NULL) {
-        if (p->textSize == len) {
-            if (0 == memcmp(p->text, str, len*sizeof(char16_t))) {
-                return i;
-            }
-        }
-        p++;
-        i++;
-    }
-    return -1;
-}
-
-// rangeMin and rangeMax are inclusive
-static status_t
-parse_int(const char16_t* str, size_t len, int* out,
-            int rangeMin, int rangeMax, bool zeroOK)
-{
-    char16_t c;
-    size_t i=0;
-
-    if (len == 0) {
-        FAIL_HERE();
-    }
-    bool negative = false;
-    c = str[0];
-    if (c == '-' ) {
-        negative = true;
-        i++;
-    }
-    else if (c == '+') {
-        i++;
-    }
-    int n = 0;
-    for (; i<len; i++) {
-        c = str[i];
-        if (c < '0' || c > '9') {
-            FAIL_HERE();
-        }
-        int prev = n;
-        n *= 10;
-        // the spec doesn't address how big these numbers can be,
-        // so we're not going to worry about not being able to represent
-        // INT_MIN, and if we're going to wrap, we'll just clamp to
-        // INT_MAX instead
-        if (n < prev) {
-            n = INT_MAX;
-        } else {
-            n += c - '0';
-        }
-    }
-    if (negative) {
-        n = -n;
-    }
-    if (n < rangeMin || n > rangeMax) {
-        FAIL_HERE();
-    }
-    if (!zeroOK && n == 0) {
-        FAIL_HERE();
-    }
-    *out = n;
-    return NO_ERROR;
-}
-
-static status_t
-parse_int_list(const char16_t* str, size_t len, int* countOut, int** listOut,
-          int rangeMin, int rangeMax, bool zeroOK,
-          status_t (*func)(const char16_t*,size_t,int*,int,int,bool)=parse_int)
-{
-    status_t err;
-
-    if (len == 0) {
-        *countOut = 0;
-        *listOut = NULL;
-        return NO_ERROR;
-    }
-
-    // make one pass through looking for commas so we know how big to make our
-    // out array.
-    int count = 1;
-    for (size_t i=0; i<len; i++) {
-        if (str[i] == ',') {
-            count++;
-        }
-    }
-
-    int* list = new int[count];
-    const char16_t* p = str;
-    int commaIndex = 0;
-    size_t i;
-
-    for (i=0; i<len; i++) {
-        if (str[i] == ',') {
-            err = func(p, (str+i-p), list+commaIndex, rangeMin,
-                    rangeMax, zeroOK);
-            if (err != NO_ERROR) {
-                goto bail;
-            }
-            commaIndex++;
-            p = str+i+1;
-        }
-    }
-
-    err = func(p, (str+i-p), list+commaIndex, rangeMin, rangeMax, zeroOK);
-    if (err != NO_ERROR) {
-        goto bail;
-    }
-    commaIndex++;
-
-    *countOut = count;
-    *listOut = list;
-
-    return NO_ERROR;
-
-bail:
-    delete[] list;
-    FAIL_HERE();
-}
-
-// the numbers here are small, so we pack them both into one value, and then
-// split it out later.  it lets us reuse all the comma separated list code.
-static status_t
-parse_byday(const char16_t* s, size_t len, int* out,
-            int rangeMin, int rangeMax, bool zeroOK)
-{
-    status_t err;
-    int n = 0;
-    const char16_t* p = s;
-    size_t plen = len;
-
-    if (len > 0) {
-        char16_t c = s[0];
-        if (c == '-' || c == '+' || (c >= '0' && c <= '9')) {
-            if (len > 1) {
-                size_t nlen = 0;
-                c = s[nlen];
-                while (nlen < len
-                        && (c == '-' || c == '+' || (c >= '0' && c <= '9'))) {
-                    c = s[nlen];
-                    nlen++;
-                }
-                if (nlen > 0) {
-                    nlen--;
-                    err = parse_int(s, nlen, &n, rangeMin, rangeMax, zeroOK);
-                    if (err != NO_ERROR) {
-                        FAIL_HERE();
-                    }
-                    p += nlen;
-                    plen -= nlen;
-                }
-            }
-        }
-
-        int index = match_proc(WEEKDAYPROC, p, plen);
-        if (index >= 0) {
-            *out = (0xffff0000 & WEEKDAYPROC[index].value)
-                    | (0x0000ffff & n);
-            return NO_ERROR;
-        }
-    }
-    return UNKNOWN_ERROR;
-}
-
-static void
-postprocess_byday(int count, int* byday, int** bydayNum)
-{
-    int* bdn = new int[count];
-    *bydayNum = bdn;
-    for (int i=0; i<count; i++) {
-        uint32_t v = byday[i];
-        int16_t num = v & 0x0000ffff;
-        byday[i] = v & 0xffff0000;  
-        // will sign extend:
-        bdn[i] = num;
-    }
-}
-
-#define PARSE_INT_LIST_CHECKED(name, rangeMin, rangeMax, zeroOK) \
-    if (name##Count != 0 || NO_ERROR != parse_int_list(s, slen, \
-                         &name##Count, &name, rangeMin, rangeMax, zeroOK)) { \
-        FAIL_HERE(); \
-    }
-status_t
-EventRecurrence::parse(const String16& str)
-{
-    char16_t const* work = str.string();
-    size_t len = str.size();
-
-    int lhsIndex = NONE_LHS;
-    int index;
-    
-    size_t start = 0;
-    for (size_t i=0; i<len; i++) {
-        char16_t c = work[i];
-        if (c != ';' && i == len-1) {
-            c = ';';
-            i++;
-        }
-        if (c == ';' || c == '=') {
-            if (i != start) {
-                const char16_t* s = work+start;
-                const size_t slen = i-start;
-
-                String8 thestring(String16(s, slen));
-
-                switch (c)
-                {
-                    case '=':
-                        if (lhsIndex == NONE_LHS) {
-                            lhsIndex = match_proc(LHSPROC, s, slen);
-                            if (lhsIndex >= 0) {
-                                break;
-                            }
-                        }
-                        FAIL_HERE();
-                    case ';':
-                    {
-                        switch (LHSPROC[lhsIndex].value)
-                        {
-                            case FREQ:
-                                if (this->freq != 0) {
-                                    FAIL_HERE();
-                                }
-                                index = match_proc(FREQPROC, s, slen);
-                                if (index >= 0) {
-                                    this->freq = (freq_t)FREQPROC[index].value;
-                                }
-                                break;
-                            case UNTIL:
-                                // XXX should check that this is a valid time
-                                until.setTo(String16(s, slen));
-                                break;
-                            case COUNT:
-                                if (count != 0
-                                     || NO_ERROR != parse_int(s, slen,
-                                             &count, INT_MIN, INT_MAX, true)) {
-                                    FAIL_HERE();
-                                }
-                                break;
-                            case INTERVAL:
-                                if (interval != 0
-                                     || NO_ERROR != parse_int(s, slen,
-                                         &interval, INT_MIN, INT_MAX, false)) {
-                                    FAIL_HERE();
-                                }
-                                break;
-                            case BYSECOND:
-                                PARSE_INT_LIST_CHECKED(bysecond, 0, 59, true)
-                                break;
-                            case BYMINUTE:
-                                PARSE_INT_LIST_CHECKED(byminute, 0, 59, true)
-                                break;
-                            case BYHOUR:
-                                PARSE_INT_LIST_CHECKED(byhour, 0, 23, true)
-                                break;
-                            case BYDAY:
-                                if (bydayCount != 0 || NO_ERROR != 
-                                        parse_int_list(s, slen, &bydayCount,
-                                              &byday, -53, 53, false,
-                                              parse_byday)) {
-                                    FAIL_HERE();
-                                }
-                                postprocess_byday(bydayCount, byday, &bydayNum);
-                                break;
-                            case BYMONTHDAY:
-                                PARSE_INT_LIST_CHECKED(bymonthday, -31, 31,
-                                                        false)
-                                break;
-                            case BYYEARDAY:
-                                PARSE_INT_LIST_CHECKED(byyearday, -366, 366,
-                                                        false)
-                                break;
-                            case BYWEEKNO:
-                                PARSE_INT_LIST_CHECKED(byweekno, -53, 53,
-                                                        false)
-                                break;
-                            case BYMONTH:
-                                PARSE_INT_LIST_CHECKED(bymonth, 1, 12, false)
-                                break;
-                            case BYSETPOS:
-                                PARSE_INT_LIST_CHECKED(bysetpos,
-                                                        INT_MIN, INT_MAX, true)
-                                break;
-                            case WKST:
-                                if (this->wkst != 0) {
-                                    FAIL_HERE();
-                                }
-                                index = match_proc(WEEKDAYPROC, s, slen);
-                                if (index >= 0) {
-                                    this->wkst = (int)WEEKDAYPROC[index].value;
-                                }
-                                break;
-                            default:
-                                FAIL_HERE();
-                        }
-                        lhsIndex = NONE_LHS;
-                        break;
-                    }
-                }
-
-                start = i+1;
-            }
-        }
-    }
-
-    // enforce that there was a FREQ
-    if (freq == 0) {
-        FAIL_HERE();
-    }
-
-    // default wkst to MO if it wasn't specified
-    if (wkst == 0) {
-        wkst = MO;
-    }
-
-    return NO_ERROR;
-}
-
-
-}; // namespace android
-
-
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 1ba38a7..0af7f80 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -13,6 +13,10 @@
 // Log debug messages about velocity tracking.
 #define DEBUG_VELOCITY 0
 
+// Log debug messages about acceleration.
+#define DEBUG_ACCELERATION 0
+
+
 #include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
@@ -20,6 +24,7 @@
 #include <ui/Input.h>
 
 #include <math.h>
+#include <limits.h>
 
 #ifdef HAVE_ANDROID_OS
 #include <binder/Parcel.h>
@@ -693,6 +698,10 @@
 
 // --- VelocityTracker ---
 
+const uint32_t VelocityTracker::HISTORY_SIZE;
+const nsecs_t VelocityTracker::MAX_AGE;
+const nsecs_t VelocityTracker::MIN_DURATION;
+
 VelocityTracker::VelocityTracker() {
     clear();
 }
@@ -881,14 +890,6 @@
 
         // Make sure we used at least one sample.
         if (samplesUsed != 0) {
-            // Scale the velocity linearly if the window of samples is small.
-            nsecs_t totalDuration = newestMovement.eventTime - oldestMovement.eventTime;
-            if (totalDuration < MIN_WINDOW) {
-                float scale = float(totalDuration) / float(MIN_WINDOW);
-                accumVx *= scale;
-                accumVy *= scale;
-            }
-
             *outVx = accumVx;
             *outVy = accumVy;
             return true;
@@ -902,6 +903,85 @@
 }
 
 
+// --- VelocityControl ---
+
+const nsecs_t VelocityControl::STOP_TIME;
+
+VelocityControl::VelocityControl() {
+    reset();
+}
+
+void VelocityControl::setParameters(const VelocityControlParameters& parameters) {
+    mParameters = parameters;
+    reset();
+}
+
+void VelocityControl::reset() {
+    mLastMovementTime = LLONG_MIN;
+    mRawPosition.x = 0;
+    mRawPosition.y = 0;
+    mVelocityTracker.clear();
+}
+
+void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) {
+    if ((deltaX && *deltaX) || (deltaY && *deltaY)) {
+        if (eventTime >= mLastMovementTime + STOP_TIME) {
+#if DEBUG_ACCELERATION
+            LOGD("VelocityControl: stopped, last movement was %0.3fms ago",
+                    (eventTime - mLastMovementTime) * 0.000001f);
+#endif
+            reset();
+        }
+
+        mLastMovementTime = eventTime;
+        if (deltaX) {
+            mRawPosition.x += *deltaX;
+        }
+        if (deltaY) {
+            mRawPosition.y += *deltaY;
+        }
+        mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
+
+        float vx, vy;
+        float scale = mParameters.scale;
+        if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
+            float speed = hypotf(vx, vy) * scale;
+            if (speed >= mParameters.highThreshold) {
+                // Apply full acceleration above the high speed threshold.
+                scale *= mParameters.acceleration;
+            } else if (speed > mParameters.lowThreshold) {
+                // Linearly interpolate the acceleration to apply between the low and high
+                // speed thresholds.
+                scale *= 1 + (speed - mParameters.lowThreshold)
+                        / (mParameters.highThreshold - mParameters.lowThreshold)
+                        * (mParameters.acceleration - 1);
+            }
+
+#if DEBUG_ACCELERATION
+            LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
+                    "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
+                    mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+                    mParameters.acceleration,
+                    vx, vy, speed, scale / mParameters.scale);
+#endif
+        } else {
+#if DEBUG_ACCELERATION
+            LOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity",
+                    mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+                    mParameters.acceleration);
+#endif
+        }
+
+        if (deltaX) {
+            *deltaX *= scale;
+        }
+        if (deltaY) {
+            *deltaY *= scale;
+        }
+    }
+}
+
+
 // --- InputDeviceInfo ---
 
 InputDeviceInfo::InputDeviceInfo() {
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index ffdfe66..c46d6f4 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -443,7 +443,8 @@
 
     if (! mPinned || ! mMotionEventSampleDataTail) {
         LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
-                "AMOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string());
+                "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.",
+                mChannel->getName().string());
         return INVALID_OPERATION;
     }
 
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index e8d40ba..774e8c9 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -21,11 +21,13 @@
 	Asset.cpp \
 	AssetDir.cpp \
 	AssetManager.cpp \
+	BlobCache.cpp \
 	BufferedTextOutput.cpp \
 	CallStack.cpp \
 	Debug.cpp \
 	FileMap.cpp \
 	Flattenable.cpp \
+	LinearTransform.cpp \
 	ObbFile.cpp \
 	Pool.cpp \
 	PropertyMap.cpp \
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index f963058..8791263 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -285,7 +285,8 @@
             break;
         }
         default:
-            LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
+            LOGD("Chunk header at %d has invalid type: 0x%08x",
+                    (int)(m_pos - sizeof(m_header)), (int)m_header.type);
             m_status = EINVAL;
     }
     
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index e15875f..87549fe 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -503,6 +503,16 @@
         needExtended = true;
     }
 
+    // Non-7bit-clean path also means needing pax extended format
+    if (!needExtended) {
+        for (size_t i = 0; i < filepath.length(); i++) {
+            if ((filepath[i] & 0x80) != 0) {
+                needExtended = true;
+                break;
+            }
+        }
+    }
+
     int err = 0;
     struct stat64 s;
     if (lstat64(filepath.string(), &s) != 0) {
@@ -515,6 +525,7 @@
     String8 prefix;
 
     const int isdir = S_ISDIR(s.st_mode);
+    if (isdir) s.st_size = 0;   // directories get no actual data in the tar stream
 
     // !!! TODO: use mmap when possible to avoid churning the buffer cache
     // !!! TODO: this will break with symlinks; need to use readlink(2)
diff --git a/libs/utils/BlobCache.cpp b/libs/utils/BlobCache.cpp
new file mode 100644
index 0000000..590576a
--- /dev/null
+++ b/libs/utils/BlobCache.cpp
@@ -0,0 +1,244 @@
+/*
+ ** Copyright 2011, 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 "BlobCache"
+//#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/BlobCache.h>
+#include <utils/Log.h>
+
+namespace android {
+
+BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
+        mMaxKeySize(maxKeySize),
+        mMaxValueSize(maxValueSize),
+        mMaxTotalSize(maxTotalSize),
+        mTotalSize(0) {
+    nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+#ifdef _WIN32
+    srand(now);
+#else
+    mRandState[0] = (now >> 0) & 0xFFFF;
+    mRandState[1] = (now >> 16) & 0xFFFF;
+    mRandState[2] = (now >> 32) & 0xFFFF;
+#endif
+    LOGV("initializing random seed using %lld", now);
+}
+
+void BlobCache::set(const void* key, size_t keySize, const void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        LOGV("set: not caching because the key is too large: %d (limit: %d)",
+                keySize, mMaxKeySize);
+        return;
+    }
+    if (mMaxValueSize < valueSize) {
+        LOGV("set: not caching because the value is too large: %d (limit: %d)",
+                valueSize, mMaxValueSize);
+        return;
+    }
+    if (mMaxTotalSize < keySize + valueSize) {
+        LOGV("set: not caching because the combined key/value size is too "
+                "large: %d (limit: %d)", keySize + valueSize, mMaxTotalSize);
+        return;
+    }
+    if (keySize == 0) {
+        LOGW("set: not caching because keySize is 0");
+        return;
+    }
+    if (valueSize <= 0) {
+        LOGW("set: not caching because valueSize is 0");
+        return;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    sp<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+
+    while (true) {
+
+        ssize_t index = mCacheEntries.indexOf(dummyEntry);
+        if (index < 0) {
+            // Create a new cache entry.
+            sp<Blob> keyBlob(new Blob(key, keySize, true));
+            sp<Blob> valueBlob(new Blob(value, valueSize, true));
+            size_t newTotalSize = mTotalSize + keySize + valueSize;
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    LOGV("set: not caching new key/value pair because the "
+                            "total cache size limit would be exceeded: %d "
+                            "(limit: %d)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            mCacheEntries.add(CacheEntry(keyBlob, valueBlob));
+            mTotalSize = newTotalSize;
+            LOGV("set: created new cache entry with %d byte key and %d byte value",
+                    keySize, valueSize);
+        } else {
+            // Update the existing cache entry.
+            sp<Blob> valueBlob(new Blob(value, valueSize, true));
+            sp<Blob> oldValueBlob(mCacheEntries[index].getValue());
+            size_t newTotalSize = mTotalSize + valueSize - oldValueBlob->getSize();
+            if (mMaxTotalSize < newTotalSize) {
+                if (isCleanable()) {
+                    // Clean the cache and try again.
+                    clean();
+                    continue;
+                } else {
+                    LOGV("set: not caching new value because the total cache "
+                            "size limit would be exceeded: %d (limit: %d)",
+                            keySize + valueSize, mMaxTotalSize);
+                    break;
+                }
+            }
+            mCacheEntries.editItemAt(index).setValue(valueBlob);
+            mTotalSize = newTotalSize;
+            LOGV("set: updated existing cache entry with %d byte key and %d byte "
+                    "value", keySize, valueSize);
+        }
+        break;
+    }
+}
+
+size_t BlobCache::get(const void* key, size_t keySize, void* value,
+        size_t valueSize) {
+    if (mMaxKeySize < keySize) {
+        LOGV("get: not searching because the key is too large: %d (limit %d)",
+                keySize, mMaxKeySize);
+        return 0;
+    }
+    Mutex::Autolock lock(mMutex);
+    sp<Blob> dummyKey(new Blob(key, keySize, false));
+    CacheEntry dummyEntry(dummyKey, NULL);
+    ssize_t index = mCacheEntries.indexOf(dummyEntry);
+    if (index < 0) {
+        LOGV("get: no cache entry found for key of size %d", keySize);
+        return 0;
+    }
+
+    // The key was found. Return the value if the caller's buffer is large
+    // enough.
+    sp<Blob> valueBlob(mCacheEntries[index].getValue());
+    size_t valueBlobSize = valueBlob->getSize();
+    if (valueBlobSize <= valueSize) {
+        LOGV("get: copying %d bytes to caller's buffer", valueBlobSize);
+        memcpy(value, valueBlob->getData(), valueBlobSize);
+    } else {
+        LOGV("get: caller's buffer is too small for value: %d (needs %d)",
+                valueSize, valueBlobSize);
+    }
+    return valueBlobSize;
+}
+
+long int BlobCache::blob_random() {
+#ifdef _WIN32
+    return rand();
+#else
+    return nrand48(mRandState);
+#endif
+}
+
+void BlobCache::clean() {
+    // Remove a random cache entry until the total cache size gets below half
+    // the maximum total cache size.
+    while (mTotalSize > mMaxTotalSize / 2) {
+        size_t i = size_t(blob_random() % (mCacheEntries.size()));
+        const CacheEntry& entry(mCacheEntries[i]);
+        mTotalSize -= entry.getKey()->getSize() + entry.getValue()->getSize();
+        mCacheEntries.removeAt(i);
+    }
+}
+
+bool BlobCache::isCleanable() const {
+    return mTotalSize > mMaxTotalSize / 2;
+}
+
+BlobCache::Blob::Blob(const void* data, size_t size, bool copyData):
+        mData(copyData ? malloc(size) : data),
+        mSize(size),
+        mOwnsData(copyData) {
+    if (copyData) {
+        memcpy(const_cast<void*>(mData), data, size);
+    }
+}
+
+BlobCache::Blob::~Blob() {
+    if (mOwnsData) {
+        free(const_cast<void*>(mData));
+    }
+}
+
+bool BlobCache::Blob::operator<(const Blob& rhs) const {
+    if (mSize == rhs.mSize) {
+        return memcmp(mData, rhs.mData, mSize) < 0;
+    } else {
+        return mSize < rhs.mSize;
+    }
+}
+
+const void* BlobCache::Blob::getData() const {
+    return mData;
+}
+
+size_t BlobCache::Blob::getSize() const {
+    return mSize;
+}
+
+BlobCache::CacheEntry::CacheEntry() {
+}
+
+BlobCache::CacheEntry::CacheEntry(const sp<Blob>& key, const sp<Blob>& value):
+        mKey(key),
+        mValue(value) {
+}
+
+BlobCache::CacheEntry::CacheEntry(const CacheEntry& ce):
+        mKey(ce.mKey),
+        mValue(ce.mValue) {
+}
+
+bool BlobCache::CacheEntry::operator<(const CacheEntry& rhs) const {
+    return *mKey < *rhs.mKey;
+}
+
+const BlobCache::CacheEntry& BlobCache::CacheEntry::operator=(const CacheEntry& rhs) {
+    mKey = rhs.mKey;
+    mValue = rhs.mValue;
+    return *this;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getKey() const {
+    return mKey;
+}
+
+sp<BlobCache::Blob> BlobCache::CacheEntry::getValue() const {
+    return mValue;
+}
+
+void BlobCache::CacheEntry::setValue(const sp<Blob>& value) {
+    mValue = value;
+}
+
+} // namespace android
diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp
new file mode 100644
index 0000000..d752415
--- /dev/null
+++ b/libs/utils/LinearTransform.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2011 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 __STDC_LIMIT_MACROS
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <utils/LinearTransform.h>
+
+namespace android {
+
+template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; }
+
+// Static math methods involving linear transformations
+static bool scale_u64_to_u64(
+        uint64_t val,
+        uint32_t N,
+        uint32_t D,
+        uint64_t* res,
+        bool round_up_not_down) {
+    uint64_t tmp1, tmp2;
+    uint32_t r;
+
+    assert(res);
+    assert(D);
+
+    // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
+    // integer X.
+    // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
+    // integer X.
+    // Let X[A, B] with A <= B denote bits A through B of the integer X.
+    // Let (A | B) denote the concatination of two 32 bit ints, A and B.
+    // IOW X = (A | B) => U32(X) == A && L32(X) == B
+    //
+    // compute M = val * N (a 96 bit int)
+    // ---------------------------------
+    // tmp2 = U32(val) * N (a 64 bit int)
+    // tmp1 = L32(val) * N (a 64 bit int)
+    // which means
+    // M = val * N = (tmp2 << 32) + tmp1
+    tmp2 = (val >> 32) * N;
+    tmp1 = (val & UINT32_MAX) * N;
+
+    // compute M[32, 95]
+    // tmp2 = tmp2 + U32(tmp1)
+    //      = (U32(val) * N) + U32(L32(val) * N)
+    //      = M[32, 95]
+    tmp2 += tmp1 >> 32;
+
+    // if M[64, 95] >= D, then M/D has bits > 63 set and we have
+    // an overflow.
+    if ((tmp2 >> 32) >= D) {
+        *res = UINT64_MAX;
+        return false;
+    }
+
+    // Divide.  Going in we know
+    // tmp2 = M[32, 95]
+    // U32(tmp2) < D
+    r = tmp2 % D;
+    tmp2 /= D;
+
+    // At this point
+    // tmp1      = L32(val) * N
+    // tmp2      = M[32, 95] / D
+    //           = (M / D)[32, 95]
+    // r         = M[32, 95] % D
+    // U32(tmp2) = 0
+    //
+    // compute tmp1 = (r | M[0, 31])
+    tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
+
+    // Divide again.  Keep the remainder around in order to round properly.
+    r = tmp1 % D;
+    tmp1 /= D;
+
+    // At this point
+    // tmp2      = (M / D)[32, 95]
+    // tmp1      = (M / D)[ 0, 31]
+    // r         =  M % D
+    // U32(tmp1) = 0
+    // U32(tmp2) = 0
+
+    // Pack the result and deal with the round-up case (As well as the
+    // remote possiblility over overflow in such a case).
+    *res = (tmp2 << 32) | tmp1;
+    if (r && round_up_not_down) {
+        ++(*res);
+        if (!(*res)) {
+            *res = UINT64_MAX;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static bool linear_transform_s64_to_s64(
+        int64_t  val,
+        int64_t  basis1,
+        int32_t  N,
+        uint32_t D,
+        int64_t  basis2,
+        int64_t* out) {
+    uint64_t scaled, res;
+    uint64_t abs_val;
+    bool is_neg;
+
+    if (!out)
+        return false;
+
+    // Compute abs(val - basis_64). Keep track of whether or not this delta
+    // will be negative after the scale opertaion.
+    if (val < basis1) {
+        is_neg = true;
+        abs_val = basis1 - val;
+    } else {
+        is_neg = false;
+        abs_val = val - basis1;
+    }
+
+    if (N < 0)
+        is_neg = !is_neg;
+
+    if (!scale_u64_to_u64(abs_val,
+                          ABS(N),
+                          D,
+                          &scaled,
+                          is_neg))
+        return false; // overflow/undeflow
+
+    // if scaled is >= 0x8000<etc>, then we are going to overflow or
+    // underflow unless ABS(basis2) is large enough to pull us back into the
+    // non-overflow/underflow region.
+    if (scaled & INT64_MIN) {
+        if (is_neg && (basis2 < 0))
+            return false; // certain underflow
+
+        if (!is_neg && (basis2 >= 0))
+            return false; // certain overflow
+
+        if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
+            return false; // not enough
+
+        // Looks like we are OK
+        *out = (is_neg ? (-scaled) : scaled) + basis2;
+    } else {
+        // Scaled fits within signed bounds, so we just need to check for
+        // over/underflow for two signed integers.  Basically, if both scaled
+        // and basis2 have the same sign bit, and the result has a different
+        // sign bit, then we have under/overflow.  An easy way to compute this
+        // is
+        // (scaled_signbit XNOR basis_signbit) &&
+        // (scaled_signbit XOR res_signbit)
+        // ==
+        // (scaled_signbit XOR basis_signbit XOR 1) &&
+        // (scaled_signbit XOR res_signbit)
+
+        if (is_neg)
+            scaled = -scaled;
+        res = scaled + basis2;
+
+        if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
+            return false;
+
+        *out = res;
+    }
+
+    return true;
+}
+
+bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
+    if (0 == a_to_b_denom)
+        return false;
+
+    return linear_transform_s64_to_s64(a_in,
+                                       a_zero,
+                                       a_to_b_numer,
+                                       a_to_b_denom,
+                                       b_zero,
+                                       b_out);
+}
+
+bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
+    if (0 == a_to_b_numer)
+        return false;
+
+    return linear_transform_s64_to_s64(b_in,
+                                       b_zero,
+                                       a_to_b_denom,
+                                       a_to_b_numer,
+                                       a_zero,
+                                       a_out);
+}
+
+template <class T> void LinearTransform::reduce(T* N, T* D) {
+    T a, b;
+    if (!N || !D || !(*D)) {
+        assert(false);
+        return;
+    }
+
+    a = *N;
+    b = *D;
+
+    if (a == 0) {
+        *D = 1;
+        return;
+    }
+
+    // This implements Euclid's method to find GCD.
+    if (a < b) {
+        T tmp = a;
+        a = b;
+        b = tmp;
+    }
+
+    while (1) {
+        // a is now the greater of the two.
+        const T remainder = a % b;
+        if (remainder == 0) {
+            *N /= b;
+            *D /= b;
+            return;
+        }
+        // by swapping remainder and b, we are guaranteeing that a is
+        // still the greater of the two upon entrance to the loop.
+        a = b;
+        b = remainder;
+    }
+};
+
+template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
+template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
+
+void LinearTransform::reduce(int32_t* N, uint32_t* D) {
+    if (N && D && *D) {
+        if (*N < 0) {
+            *N = -(*N);
+            reduce(reinterpret_cast<uint32_t*>(N), D);
+            *N = -(*N);
+        } else {
+            reduce(reinterpret_cast<uint32_t*>(N), D);
+        }
+    }
+}
+
+}  // namespace android
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index dd0052a..8db2009 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -49,6 +49,11 @@
 
 // ---------------------------------------------------------------------------
 
+RefBase::Destroyer::~Destroyer() {
+}
+
+// ---------------------------------------------------------------------------
+
 class RefBase::weakref_impl : public RefBase::weakref_type
 {
 public:
@@ -56,7 +61,7 @@
     volatile int32_t    mWeak;
     RefBase* const      mBase;
     volatile int32_t    mFlags;
-
+    Destroyer*          mDestroyer;
 
 #if !DEBUG_REFS
 
@@ -65,6 +70,7 @@
         , mWeak(0)
         , mBase(base)
         , mFlags(0)
+        , mDestroyer(0)
     {
     }
 
@@ -345,10 +351,6 @@
     const_cast<RefBase*>(this)->onFirstRef();
 }
 
-void RefBase::destroy() const {
-    delete this;
-}
-
 void RefBase::decStrong(const void* id) const
 {
     weakref_impl* const refs = mRefs;
@@ -361,7 +363,11 @@
     if (c == 1) {
         const_cast<RefBase*>(this)->onLastStrongRef(id);
         if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
-            destroy();
+            if (refs->mDestroyer) {
+                refs->mDestroyer->destroy(this);
+            } else {
+                delete this;
+            }
         }
     }
     refs->decWeak(id);
@@ -394,7 +400,9 @@
     return mRefs->mStrong;
 }
 
-
+void RefBase::setDestroyer(RefBase::Destroyer* destroyer) {
+    mRefs->mDestroyer = destroyer;
+}
 
 RefBase* RefBase::weakref_type::refBase() const
 {
@@ -418,18 +426,28 @@
     if (c != 1) return;
     
     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) {
-        if (impl->mStrong == INITIAL_STRONG_VALUE)
-            if (impl->mBase)
-                impl->mBase->destroy();
-        else {
+        if (impl->mStrong == INITIAL_STRONG_VALUE) {
+            if (impl->mBase) {
+                if (impl->mDestroyer) {
+                    impl->mDestroyer->destroy(impl->mBase);
+                } else {
+                    delete impl->mBase;
+                }
+            }
+        } else {
             // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
             delete impl;
         }
     } else {
         impl->mBase->onLastWeakRef(id);
         if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) {
-            if (impl->mBase)
-                impl->mBase->destroy();
+            if (impl->mBase) {
+                if (impl->mDestroyer) {
+                    impl->mDestroyer->destroy(impl->mBase);
+                } else {
+                    delete impl->mBase;
+                }
+            }
         }
     }
 }
@@ -551,8 +569,10 @@
 
 RefBase::~RefBase()
 {
-    if (mRefs->mWeak == 0) {
-        delete mRefs;
+    if ((mRefs->mFlags & OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_WEAK) {
+        if (mRefs->mWeak == 0) {
+            delete mRefs;
+        }
     }
 }
 
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 4a6a3db..cb6c246 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -2663,6 +2663,9 @@
                     goto nope;
                 }
             }
+            if (outTypeSpecFlags) {
+                *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
+            }
             return m->id;
 nope:
             ;
@@ -2677,6 +2680,9 @@
                          index);
                     return 0;
                 }
+                if (outTypeSpecFlags) {
+                    *outTypeSpecFlags = ResTable_typeSpec::SPEC_PUBLIC;
+                }
                 return  Res_MAKEARRAY(index);
             }
         }
@@ -2687,6 +2693,8 @@
         return 0;
     }
 
+    bool fakePublic = false;
+
     // Figure out the package and type we are looking in...
 
     const char16_t* packageEnd = NULL;
@@ -2698,7 +2706,13 @@
         else if (*p == '/') typeEnd = p;
         p++;
     }
-    if (*name == '@') name++;
+    if (*name == '@') {
+        name++;
+        if (*name == '*') {
+            fakePublic = true;
+            name++;
+        }
+    }
     if (name >= nameEnd) {
         return 0;
     }
@@ -2803,6 +2817,9 @@
                 if (dtohl(entry->key.index) == (size_t)ei) {
                     if (outTypeSpecFlags) {
                         *outTypeSpecFlags = typeConfigs->typeSpecFlags[i];
+                        if (fakePublic) {
+                            *outTypeSpecFlags |= ResTable_typeSpec::SPEC_PUBLIC;
+                        }
                     }
                     return Res_MAKEID(group->id-1, ti, i);
                 }
@@ -2819,7 +2836,8 @@
                                  String16* outName,
                                  const String16* defType,
                                  const String16* defPackage,
-                                 const char** outErrorMsg)
+                                 const char** outErrorMsg,
+                                 bool* outPublicOnly)
 {
     const char16_t* packageEnd = NULL;
     const char16_t* typeEnd = NULL;
@@ -2836,6 +2854,16 @@
     p = refStr;
     if (*p == '@') p++;
 
+    if (outPublicOnly != NULL) {
+        *outPublicOnly = true;
+    }
+    if (*p == '*') {
+        p++;
+        if (outPublicOnly != NULL) {
+            *outPublicOnly = false;
+        }
+    }
+
     if (packageEnd) {
         *outPackage = String16(p, packageEnd-p);
         p = packageEnd+1;
diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/utils/StreamingZipInflater.cpp
index 5a162cc..00498bd 100644
--- a/libs/utils/StreamingZipInflater.cpp
+++ b/libs/utils/StreamingZipInflater.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_NDEBUG 1
+//#define LOG_NDEBUG 0
 #define LOG_TAG "szipinf"
 #include <utils/Log.h>
 
@@ -77,7 +77,7 @@
 }
 
 void StreamingZipInflater::initInflateState() {
-    LOGD("Initializing inflate state");
+    LOGV("Initializing inflate state");
 
     memset(&mInflateState, 0, sizeof(mInflateState));
     mInflateState.zalloc = Z_NULL;
@@ -152,13 +152,13 @@
             mInflateState.avail_out = mOutBufSize;
 
             /*
-            LOGD("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p",
+            LOGV("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p",
                     mInflateState.avail_in, mInflateState.avail_out,
                     mInflateState.next_in, mInflateState.next_out);
             */
             int result = Z_OK;
             if (mStreamNeedsInit) {
-                LOGD("Initializing zlib to inflate");
+                LOGV("Initializing zlib to inflate");
                 result = inflateInit2(&mInflateState, -MAX_WBITS);
                 mStreamNeedsInit = false;
             }
@@ -192,7 +192,7 @@
         size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
         if (toRead > 0) {
             ssize_t didRead = ::read(mFd, mInBuf, toRead);
-            //LOGD("Reading input chunk, size %08x didread %08x", toRead, didRead);
+            //LOGV("Reading input chunk, size %08x didread %08x", toRead, didRead);
             if (didRead < 0) {
                 // TODO: error
                 LOGE("Error reading asset data");
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 8b5da0e..15bb1d2 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -168,6 +168,9 @@
         return 0;
     }
 
+    // Note that *threadID is directly available to the parent only, as it is
+    // assigned after the child starts.  Use memory barrier / lock if the child
+    // or other threads also need access.
     if (threadId != NULL) {
         *threadId = (android_thread_id_t)thread; // XXX: this is not portable
     }
@@ -332,10 +335,17 @@
 
     pthread_once(&gDoSchedulingGroupOnce, checkDoSchedulingGroup);
     if (gDoSchedulingGroup) {
+        // set_sched_policy does not support tid == 0
+        int policy_tid;
+        if (tid == 0) {
+            policy_tid = androidGetTid();
+        } else {
+            policy_tid = tid;
+        }
         if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-            rc = set_sched_policy(tid, SP_BACKGROUND);
+            rc = set_sched_policy(policy_tid, SP_BACKGROUND);
         } else if (getpriority(PRIO_PROCESS, tid) >= ANDROID_PRIORITY_BACKGROUND) {
-            rc = set_sched_policy(tid, SP_FOREGROUND);
+            rc = set_sched_policy(policy_tid, SP_FOREGROUND);
         }
     }
 
@@ -718,7 +728,6 @@
         res = androidCreateRawThreadEtc(_threadLoop,
                 this, name, priority, stack, &mThread);
     }
-    // The new thread wakes up at _threadLoop, but immediately blocks on mLock
     
     if (res == false) {
         mStatus = UNKNOWN_ERROR;   // something happened!
@@ -742,11 +751,6 @@
 {
     Thread* const self = static_cast<Thread*>(user);
 
-    // force a memory barrier before reading any fields, in particular mHoldSelf
-    {
-    Mutex::Autolock _l(self->mLock);
-    }
-
     sp<Thread> strong(self->mHoldSelf);
     wp<Thread> weak(strong);
     self->mHoldSelf.clear();
@@ -816,6 +820,7 @@
 
 status_t Thread::requestExitAndWait()
 {
+    Mutex::Autolock _l(mLock);
     if (mThread == getThreadId()) {
         LOGW(
         "Thread (this=%p): don't call waitForExit() from this "
@@ -825,9 +830,8 @@
         return WOULD_BLOCK;
     }
     
-    requestExit();
+    mExitPending = true;
 
-    Mutex::Autolock _l(mLock);
     while (mRunning == true) {
         mThreadExitedCondition.wait(mLock);
     }
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 72d4876..87ad98e 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -6,6 +6,7 @@
 
 # Build the unit tests.
 test_src_files := \
+	BlobCache_test.cpp \
 	ObbFile_test.cpp \
 	Looper_test.cpp \
 	String8_test.cpp \
diff --git a/libs/utils/tests/BlobCache_test.cpp b/libs/utils/tests/BlobCache_test.cpp
new file mode 100644
index 0000000..653ea5e
--- /dev/null
+++ b/libs/utils/tests/BlobCache_test.cpp
@@ -0,0 +1,257 @@
+/*
+ ** Copyright 2011, 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <utils/BlobCache.h>
+
+namespace android {
+
+class BlobCacheTest : public ::testing::Test {
+protected:
+    enum {
+        MAX_KEY_SIZE = 6,
+        MAX_VALUE_SIZE = 8,
+        MAX_TOTAL_SIZE = 13,
+    };
+
+    virtual void SetUp() {
+        mBC = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
+    }
+
+    virtual void TearDown() {
+        mBC.clear();
+    }
+
+    sp<BlobCache> mBC;
+};
+
+TEST_F(BlobCacheTest, CacheSingleValueSucceeds) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheTwoValuesSucceeds) {
+    char buf[2] = { 0xee, 0xee };
+    mBC->set("ab", 2, "cd", 2);
+    mBC->set("ef", 2, "gh", 2);
+    ASSERT_EQ(size_t(2), mBC->get("ab", 2, buf, 2));
+    ASSERT_EQ('c', buf[0]);
+    ASSERT_EQ('d', buf[1]);
+    ASSERT_EQ(size_t(2), mBC->get("ef", 2, buf, 2));
+    ASSERT_EQ('g', buf[0]);
+    ASSERT_EQ('h', buf[1]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesInsideBounds) {
+    char buf[6] = { 0xee, 0xee, 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf+1, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ('e', buf[1]);
+    ASSERT_EQ('f', buf[2]);
+    ASSERT_EQ('g', buf[3]);
+    ASSERT_EQ('h', buf[4]);
+    ASSERT_EQ(0xee, buf[5]);
+}
+
+TEST_F(BlobCacheTest, GetOnlyWritesIfBufferIsLargeEnough) {
+    char buf[3] = { 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 3));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+}
+
+TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
+    mBC->set("abcd", 4, "efgh", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, "ijkl", 4);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('i', buf[0]);
+    ASSERT_EQ('j', buf[1]);
+    ASSERT_EQ('k', buf[2]);
+    ASSERT_EQ('l', buf[3]);
+}
+
+TEST_F(BlobCacheTest, SecondSetKeepsFirstValueIfTooLarge) {
+    char buf[MAX_VALUE_SIZE+1] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyIsTooBig) {
+    char key[MAX_KEY_SIZE+1];
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE+1; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE+1, "bbbb", 4);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE+1, buf, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+    ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfValueIsTooBig) {
+    char buf[MAX_VALUE_SIZE+1];
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE+1);
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(0), mBC->get("abcd", 4, buf, MAX_VALUE_SIZE+1));
+    for (int i = 0; i < MAX_VALUE_SIZE+1; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ(0xee, buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, DoesntCacheIfKeyValuePairIsTooBig) {
+    // Check a testing assumptions
+    ASSERT_TRUE(MAX_TOTAL_SIZE < MAX_KEY_SIZE + MAX_VALUE_SIZE);
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE + 1 };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
+    char key[MAX_KEY_SIZE];
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    mBC->set(key, MAX_KEY_SIZE, "wxyz", 4);
+    ASSERT_EQ(size_t(4), mBC->get(key, MAX_KEY_SIZE, buf, 4));
+    ASSERT_EQ('w', buf[0]);
+    ASSERT_EQ('x', buf[1]);
+    ASSERT_EQ('y', buf[2]);
+    ASSERT_EQ('z', buf[3]);
+}
+
+TEST_F(BlobCacheTest, CacheMaxValueSizeSucceeds) {
+    char buf[MAX_VALUE_SIZE];
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 'b';
+    }
+    mBC->set("abcd", 4, buf, MAX_VALUE_SIZE);
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        buf[i] = 0xee;
+    }
+    ASSERT_EQ(size_t(MAX_VALUE_SIZE), mBC->get("abcd", 4, buf,
+            MAX_VALUE_SIZE));
+    for (int i = 0; i < MAX_VALUE_SIZE; i++) {
+        SCOPED_TRACE(i);
+        ASSERT_EQ('b', buf[i]);
+    }
+}
+
+TEST_F(BlobCacheTest, CacheMaxKeyValuePairSizeSucceeds) {
+    // Check a testing assumption
+    ASSERT_TRUE(MAX_KEY_SIZE < MAX_TOTAL_SIZE);
+
+    enum { bufSize = MAX_TOTAL_SIZE - MAX_KEY_SIZE };
+
+    char key[MAX_KEY_SIZE];
+    char buf[bufSize];
+    for (int i = 0; i < MAX_KEY_SIZE; i++) {
+        key[i] = 'a';
+    }
+    for (int i = 0; i < bufSize; i++) {
+        buf[i] = 'b';
+    }
+
+    mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
+    ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+}
+
+TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
+    char buf[1] = { 0xee };
+    mBC->set("x", 1, "y", 1);
+    ASSERT_EQ(size_t(1), mBC->get("x", 1, buf, 1));
+    ASSERT_EQ('y', buf[0]);
+}
+
+TEST_F(BlobCacheTest, CacheSizeDoesntExceedTotalLimit) {
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    int numCached = 0;
+    for (int i = 0; i < 256; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_GE(MAX_TOTAL_SIZE / 2, numCached);
+}
+
+TEST_F(BlobCacheTest, ExceedingTotalLimitHalvesCacheSize) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Insert one more entry, causing a cache overflow.
+    {
+        uint8_t k = maxEntries;
+        mBC->set(&k, 1, "x", 1);
+    }
+    // Count the number of entries in the cache.
+    int numCached = 0;
+    for (int i = 0; i < maxEntries+1; i++) {
+        uint8_t k = i;
+        if (mBC->get(&k, 1, NULL, 0) == 1) {
+            numCached++;
+        }
+    }
+    ASSERT_EQ(maxEntries/2 + 1, numCached);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 9daaad8..c618263 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -2,18 +2,18 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    clz.cpp.arm \
-    DisplayHardware/DisplayHardware.cpp \
+    Layer.cpp 								\
+    LayerBase.cpp 							\
+    LayerDim.cpp 							\
+    DisplayHardware/DisplayHardware.cpp 	\
     DisplayHardware/DisplayHardwareBase.cpp \
-    DisplayHardware/HWComposer.cpp \
-    GLExtensions.cpp \
-    Layer.cpp \
-    LayerBase.cpp \
-    LayerDim.cpp \
-    MessageQueue.cpp \
-    SurfaceFlinger.cpp \
-    TextureManager.cpp \
-    Transform.cpp
+    DisplayHardware/HWComposer.cpp 			\
+    GLExtensions.cpp 						\
+    MessageQueue.cpp 						\
+    SurfaceFlinger.cpp 						\
+    SurfaceTextureLayer.cpp 				\
+    Transform.cpp 							\
+    
 
 LOCAL_CFLAGS:= -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8df2b92..35e29a6 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -18,8 +18,9 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <cutils/properties.h>
+#include <cutils/compiler.h>
 #include <cutils/native_handle.h>
+#include <cutils/properties.h>
 
 #include <utils/Errors.h>
 #include <utils/Log.h>
@@ -31,12 +32,12 @@
 #include <surfaceflinger/Surface.h>
 
 #include "clz.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "DisplayHardware/HWComposer.h"
 #include "GLExtensions.h"
 #include "Layer.h"
 #include "SurfaceFlinger.h"
-#include "DisplayHardware/DisplayHardware.h"
-#include "DisplayHardware/HWComposer.h"
-
+#include "SurfaceTextureLayer.h"
 
 #define DEBUG_RESIZE    0
 
@@ -52,102 +53,82 @@
 Layer::Layer(SurfaceFlinger* flinger,
         DisplayID display, const sp<Client>& client)
     :   LayerBaseClient(flinger, display, client),
+        mTextureName(-1U),
+        mQueuedFrames(0),
+        mCurrentTransform(0),
+        mCurrentOpacity(true),
         mFormat(PIXEL_FORMAT_NONE),
         mGLExtensions(GLExtensions::getInstance()),
-        mNeedsBlending(true),
+        mOpaqueLayer(true),
         mNeedsDithering(false),
         mSecure(false),
         mProtectedByApp(false),
-        mTextureManager(),
-        mBufferManager(mTextureManager),
-        mWidth(0), mHeight(0),
-        mNeedsScaling(false), mFixedSize(false)
+        mFixedSize(false)
 {
+    mCurrentCrop.makeInvalid();
+    glGenTextures(1, &mTextureName);
+}
+
+void Layer::destroy(RefBase const* base) {
+    mFlinger->destroyLayer(static_cast<LayerBase const*>(base));
+}
+
+void Layer::onFirstRef()
+{
+    LayerBaseClient::onFirstRef();
+    setDestroyer(this);
+
+    struct FrameQueuedListener : public SurfaceTexture::FrameAvailableListener {
+        FrameQueuedListener(Layer* layer) : mLayer(layer) { }
+    private:
+        wp<Layer> mLayer;
+        virtual void onFrameAvailable() {
+            sp<Layer> that(mLayer.promote());
+            if (that != 0) {
+                that->onFrameQueued();
+            }
+        }
+    };
+    mSurfaceTexture = new SurfaceTextureLayer(mTextureName, this);
+    mSurfaceTexture->setFrameAvailableListener(new FrameQueuedListener(this));
+    mSurfaceTexture->setSynchronousMode(true);
+    mSurfaceTexture->setBufferCountServer(2);
 }
 
 Layer::~Layer()
 {
-    // FIXME: must be called from the main UI thread
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-    mBufferManager.destroy(dpy);
-
-    // we can use getUserClientUnsafe here because we know we're
-    // single-threaded at that point.
-    sp<UserClient> ourClient(mUserClientRef.getUserClientUnsafe());
-    if (ourClient != 0) {
-        ourClient->detachLayer(this);
-    }
+    glDeleteTextures(1, &mTextureName);
 }
 
-void Layer::destroy() const {
-    mFlinger->destroyLayer(this);
-}
-
-status_t Layer::setToken(const sp<UserClient>& userClient,
-        SharedClient* sharedClient, int32_t token)
-{
-    sp<SharedBufferServer> lcblk = new SharedBufferServer(
-            sharedClient, token, mBufferManager.getDefaultBufferCount(),
-            getIdentity());
-
-
-    sp<UserClient> ourClient(mUserClientRef.getClient());
-
-    /*
-     *  Here it is guaranteed that userClient != ourClient
-     *  (see UserClient::getTokenForSurface()).
-     *
-     *  We release the token used by this surface in ourClient below.
-     *  This should be safe to do so now, since this layer won't be attached
-     *  to this client, it should be okay to reuse that id.
-     *
-     *  If this causes problems, an other solution would be to keep a list
-     *  of all the {UserClient, token} ever used and release them when the
-     *  Layer is destroyed.
-     *
-     */
-
-    if (ourClient != 0) {
-        ourClient->detachLayer(this);
-    }
-
-    status_t err = mUserClientRef.setToken(userClient, lcblk, token);
-    LOGE_IF(err != NO_ERROR,
-            "ClientRef::setToken(%p, %p, %u) failed",
-            userClient.get(), lcblk.get(), token);
-
-    if (err == NO_ERROR) {
-        // we need to free the buffers associated with this surface
-    }
-
-    return err;
-}
-
-int32_t Layer::getToken() const
-{
-    return mUserClientRef.getToken();
-}
-
-sp<UserClient> Layer::getClient() const
-{
-    return mUserClientRef.getClient();
+void Layer::onFrameQueued() {
+    android_atomic_inc(&mQueuedFrames);
+    mFlinger->signalEvent();
 }
 
 // called with SurfaceFlinger::mStateLock as soon as the layer is entered
 // in the purgatory list
 void Layer::onRemoved()
 {
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (lcblk) {
-        // wake up the condition
-        lcblk->setStatus(NO_INIT);
-    }
 }
 
-sp<LayerBaseClient::Surface> Layer::createSurface() const
+sp<ISurface> Layer::createSurface()
 {
-    sp<Surface> sur(new SurfaceLayer(mFlinger, const_cast<Layer *>(this)));
+    class BSurface : public BnSurface, public LayerCleaner {
+        wp<const Layer> mOwner;
+        virtual sp<ISurfaceTexture> getSurfaceTexture() const {
+            sp<ISurfaceTexture> res;
+            sp<const Layer> that( mOwner.promote() );
+            if (that != NULL) {
+                res = that->mSurfaceTexture;
+            }
+            return res;
+        }
+    public:
+        BSurface(const sp<SurfaceFlinger>& flinger,
+                const sp<Layer>& layer)
+            : LayerCleaner(flinger, layer), mOwner(layer) { }
+    };
+    sp<ISurface> sur(new BSurface(mFlinger, this));
     return sur;
 }
 
@@ -175,17 +156,14 @@
     const uint32_t hwFlags = hw.getFlags();
     
     mFormat = format;
-    mWidth  = w;
-    mHeight = h;
-
-    mReqFormat = format;
-    mReqWidth = w;
-    mReqHeight = h;
 
     mSecure = (flags & ISurfaceComposer::eSecure) ? true : false;
     mProtectedByApp = (flags & ISurfaceComposer::eProtectedByApp) ? true : false;
-    mNeedsBlending = (info.h_alpha - info.l_alpha) > 0 &&
-            (flags & ISurfaceComposer::eOpaque) == 0;
+    mOpaqueLayer = (flags & ISurfaceComposer::eOpaque);
+    mCurrentOpacity = getOpacityForFormat(format);
+
+    mSurfaceTexture->setDefaultBufferSize(w, h);
+    mSurfaceTexture->setDefaultBufferFormat(format);
 
     // we use the red index
     int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED);
@@ -216,10 +194,12 @@
         return;
     }
 
-    Transform tr(Transform(mOrientation) * Transform(mBufferTransform));
+    // FIXME: shouldn't we take the state's transform into account here?
+
+    Transform tr(Transform(mOrientation) * Transform(mCurrentTransform));
     hwcl->transform = tr.getOrientation();
 
-    if (needsBlending()) {
+    if (!isOpaque()) {
         hwcl->blending = mPremultipliedAlpha ?
                 HWC_BLENDING_PREMULT : HWC_BLENDING_COVERAGE;
     }
@@ -236,7 +216,7 @@
 }
 
 void Layer::setPerFrameData(hwc_layer_t* hwcl) {
-    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
+    const sp<GraphicBuffer>& buffer(mActiveBuffer);
     if (buffer == NULL) {
         // this can happen if the client never drew into this layer yet,
         // or if we ran out of memory. In that case, don't let
@@ -247,11 +227,11 @@
     }
     hwcl->handle = buffer->handle;
 
-    if (!mBufferCrop.isEmpty()) {
-        hwcl->sourceCrop.left   = mBufferCrop.left;
-        hwcl->sourceCrop.top    = mBufferCrop.top;
-        hwcl->sourceCrop.right  = mBufferCrop.right;
-        hwcl->sourceCrop.bottom = mBufferCrop.bottom;
+    if (isCropped()) {
+        hwcl->sourceCrop.left   = mCurrentCrop.left;
+        hwcl->sourceCrop.top    = mCurrentCrop.top;
+        hwcl->sourceCrop.right  = mCurrentCrop.right;
+        hwcl->sourceCrop.bottom = mCurrentCrop.bottom;
     } else {
         hwcl->sourceCrop.left   = 0;
         hwcl->sourceCrop.top    = 0;
@@ -260,51 +240,12 @@
     }
 }
 
-void Layer::reloadTexture(const Region& dirty)
-{
-    sp<GraphicBuffer> buffer(mBufferManager.getActiveBuffer());
-    if (buffer == NULL) {
-        // this situation can happen if we ran out of memory for instance.
-        // not much we can do. continue to use whatever texture was bound
-        // to this context.
-        return;
-    }
-
-    if (mGLExtensions.haveDirectTexture()) {
-        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-        if (mBufferManager.initEglImage(dpy, buffer) != NO_ERROR) {
-            // not sure what we can do here...
-            goto slowpath;
-        }
-    } else {
-slowpath:
-        GGLSurface t;
-        if (buffer->usage & GRALLOC_USAGE_SW_READ_MASK) {
-            status_t res = buffer->lock(&t, GRALLOC_USAGE_SW_READ_OFTEN);
-            LOGE_IF(res, "error %d (%s) locking buffer %p",
-                    res, strerror(res), buffer.get());
-            if (res == NO_ERROR) {
-                mBufferManager.loadTexture(dirty, t);
-                buffer->unlock();
-            }
-        } else {
-            // we can't do anything
-        }
-    }
+static inline uint16_t pack565(int r, int g, int b) {
+    return (r<<11)|(g<<5)|b;
 }
-
-void Layer::drawForSreenShot() const
-{
-    const bool currentFiltering = mNeedsFiltering;
-    const_cast<Layer*>(this)->mNeedsFiltering = true;
-    LayerBase::drawForSreenShot();
-    const_cast<Layer*>(this)->mNeedsFiltering = currentFiltering;
-}
-
 void Layer::onDraw(const Region& clip) const
 {
-    Texture tex(mBufferManager.getActiveTexture());
-    if (tex.name == -1LU) {
+    if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -330,7 +271,25 @@
         }
         return;
     }
-    drawWithOpenGL(clip, tex);
+
+    GLenum target = mSurfaceTexture->getCurrentTextureTarget();
+    glBindTexture(target, mTextureName);
+    if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) {
+        // TODO: we could be more subtle with isFixedSize()
+        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    } else {
+        glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    }
+    glEnable(target);
+    glMatrixMode(GL_TEXTURE);
+    glLoadMatrixf(mTextureMatrix);
+    glMatrixMode(GL_MODELVIEW);
+
+    drawWithOpenGL(clip);
+
+    glDisable(target);
 }
 
 // As documented in libhardware header, formats in the range
@@ -340,186 +299,37 @@
 // hardware.h, instead of using hard-coded values here.
 #define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF)
 
-bool Layer::needsBlending(const sp<GraphicBuffer>& buffer) const
+bool Layer::getOpacityForFormat(uint32_t format)
 {
-    // If buffers where set with eOpaque flag, all buffers are known to
-    // be opaque without having to check their actual format
-    if (mNeedsBlending && buffer != NULL) {
-        PixelFormat format = buffer->getPixelFormat();
-
-        if (HARDWARE_IS_DEVICE_FORMAT(format)) {
-            return false;
-        }
-
-        PixelFormatInfo info;
-        status_t err = getPixelFormatInfo(format, &info);
-        if (!err && info.h_alpha <= info.l_alpha) {
-            return false;
-        }
+    if (HARDWARE_IS_DEVICE_FORMAT(format)) {
+        return true;
     }
-
-    // Return opacity as determined from flags and format options
-    // passed to setBuffers()
-    return mNeedsBlending;
+    PixelFormatInfo info;
+    status_t err = getPixelFormatInfo(PixelFormat(format), &info);
+    // in case of error (unknown format), we assume no blending
+    return (err || info.h_alpha <= info.l_alpha);
 }
 
-bool Layer::needsBlending() const
-{
-    if (mBufferManager.hasActiveBuffer()) {
-        return needsBlending(mBufferManager.getActiveBuffer());
-    }
 
-    return mNeedsBlending;
-}
-
-bool Layer::needsFiltering() const
+bool Layer::isOpaque() const
 {
-    if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
-        // if our buffer is not the same size than ourselves,
-        // we need filtering.
-        Mutex::Autolock _l(mLock);
-        if (mNeedsScaling)
-            return true;
-    }
-    return LayerBase::needsFiltering();
+    // if we don't have a buffer yet, we're translucent regardless of the
+    // layer's opaque flag.
+    if (mActiveBuffer == 0)
+        return false;
+
+    // if the layer has the opaque flag, then we're always opaque,
+    // otherwise we use the current buffer's format.
+    return mOpaqueLayer || mCurrentOpacity;
 }
 
 bool Layer::isProtected() const
 {
-    sp<GraphicBuffer> activeBuffer(mBufferManager.getActiveBuffer());
+    const sp<GraphicBuffer>& activeBuffer(mActiveBuffer);
     return (activeBuffer != 0) &&
             (activeBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
-status_t Layer::setBufferCount(int bufferCount)
-{
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (!lcblk) {
-        // oops, the client is already gone
-        return DEAD_OBJECT;
-    }
-
-    // NOTE: lcblk->resize() is protected by an internal lock
-    status_t err = lcblk->resize(bufferCount);
-    if (err == NO_ERROR) {
-        EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-        mBufferManager.resize(bufferCount, mFlinger, dpy);
-    }
-
-    return err;
-}
-
-sp<GraphicBuffer> Layer::requestBuffer(int index,
-        uint32_t reqWidth, uint32_t reqHeight, uint32_t reqFormat,
-        uint32_t usage)
-{
-    sp<GraphicBuffer> buffer;
-
-    if (int32_t(reqWidth | reqHeight | reqFormat) < 0)
-        return buffer;
-
-    if ((!reqWidth && reqHeight) || (reqWidth && !reqHeight))
-        return buffer;
-
-    // this ensures our client doesn't go away while we're accessing
-    // the shared area.
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (!lcblk) {
-        // oops, the client is already gone
-        return buffer;
-    }
-
-    /*
-     * This is called from the client's Surface::dequeue(). This can happen
-     * at any time, especially while we're in the middle of using the
-     * buffer 'index' as our front buffer.
-     */
-
-    status_t err = NO_ERROR;
-    uint32_t w, h, f;
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-
-        // zero means default
-        const bool fixedSize = reqWidth && reqHeight;
-        if (!reqFormat) reqFormat = mFormat;
-        if (!reqWidth)  reqWidth = mWidth;
-        if (!reqHeight) reqHeight = mHeight;
-
-        w = reqWidth;
-        h = reqHeight;
-        f = reqFormat;
-
-        if ((reqWidth != mReqWidth) || (reqHeight != mReqHeight) ||
-                (reqFormat != mReqFormat)) {
-            mReqWidth  = reqWidth;
-            mReqHeight = reqHeight;
-            mReqFormat = reqFormat;
-            mFixedSize = fixedSize;
-            mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
-
-            lcblk->reallocateAllExcept(index);
-        }
-    }
-
-    // here we have to reallocate a new buffer because the buffer could be
-    // used as the front buffer, or by a client in our process
-    // (eg: status bar), and we can't release the handle under its feet.
-    const uint32_t effectiveUsage = getEffectiveUsage(usage);
-    buffer = new GraphicBuffer(w, h, f, effectiveUsage);
-    err = buffer->initCheck();
-
-    if (err || buffer->handle == 0) {
-        GraphicBuffer::dumpAllocationsToSystemLog();
-        LOGE_IF(err || buffer->handle == 0,
-                "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d failed (%s)",
-                this, index, w, h, strerror(-err));
-    } else {
-        LOGD_IF(DEBUG_RESIZE,
-                "Layer::requestBuffer(this=%p), index=%d, w=%d, h=%d, handle=%p",
-                this, index, w, h, buffer->handle);
-    }
-
-    if (err == NO_ERROR && buffer->handle != 0) {
-        Mutex::Autolock _l(mLock);
-        mBufferManager.attachBuffer(index, buffer);
-    }
-    return buffer;
-}
-
-uint32_t Layer::getEffectiveUsage(uint32_t usage) const
-{
-    /*
-     *  buffers used for software rendering, but h/w composition
-     *  are allocated with SW_READ_OFTEN | SW_WRITE_OFTEN | HW_TEXTURE
-     *
-     *  buffers used for h/w rendering and h/w composition
-     *  are allocated with  HW_RENDER | HW_TEXTURE
-     *
-     *  buffers used with h/w rendering and either NPOT or no egl_image_ext
-     *  are allocated with SW_READ_RARELY | HW_RENDER
-     *
-     */
-
-    if (mSecure) {
-        // secure buffer, don't store it into the GPU
-        usage = GraphicBuffer::USAGE_SW_READ_OFTEN |
-                GraphicBuffer::USAGE_SW_WRITE_OFTEN;
-    } else {
-        // it's allowed to modify the usage flags here, but generally
-        // the requested flags should be honored.
-        // request EGLImage for all buffers
-        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-    }
-    if (mProtectedByApp) {
-        // need a hardware-protected path to external video sink
-        usage |= GraphicBuffer::USAGE_PROTECTED;
-    }
-    return usage;
-}
-
 uint32_t Layer::doTransaction(uint32_t flags)
 {
     const Layer::State& front(drawingState());
@@ -531,10 +341,12 @@
     if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
-                "resize (layer=%p), requested (%dx%d), drawing (%d,%d)",
+                "resize (layer=%p), requested (%dx%d), drawing (%d,%d), "
+                "fixedSize=%d",
                 this,
                 int(temp.requested_w), int(temp.requested_h),
-                int(front.requested_w), int(front.requested_h));
+                int(front.requested_w), int(front.requested_h),
+                isFixedSize());
 
         if (!isFixedSize()) {
             // we're being resized and there is a freeze display request,
@@ -557,17 +369,7 @@
 
             // record the new size, form this point on, when the client request
             // a buffer, it'll get the new size.
-            setBufferSize(temp.requested_w, temp.requested_h);
-
-            ClientRef::Access sharedClient(mUserClientRef);
-            SharedBufferServer* lcblk(sharedClient.get());
-            if (lcblk) {
-                // all buffers need reallocation
-                lcblk->reallocateAll();
-            }
-        } else {
-            // record the new size
-            setBufferSize(temp.requested_w, temp.requested_h);
+            mSurfaceTexture->setDefaultBufferSize(temp.requested_w, temp.requested_h);
         }
     }
 
@@ -582,79 +384,67 @@
     return LayerBase::doTransaction(flags);
 }
 
-void Layer::setBufferSize(uint32_t w, uint32_t h) {
-    Mutex::Autolock _l(mLock);
-    mWidth = w;
-    mHeight = h;
-    mNeedsScaling = mWidth != mReqWidth || mHeight != mReqHeight;
-}
-
 bool Layer::isFixedSize() const {
     Mutex::Autolock _l(mLock);
     return mFixedSize;
 }
 
+void Layer::setFixedSize(bool fixedSize)
+{
+    Mutex::Autolock _l(mLock);
+    mFixedSize = fixedSize;
+}
+
+bool Layer::isCropped() const {
+    return !mCurrentCrop.isEmpty();
+}
+
 // ----------------------------------------------------------------------------
 // pageflip handling...
 // ----------------------------------------------------------------------------
 
 void Layer::lockPageFlip(bool& recomputeVisibleRegions)
 {
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    if (!lcblk) {
-        // client died
-        recomputeVisibleRegions = true;
-        return;
-    }
+    if (mQueuedFrames > 0) {
+        // signal another event if we have more frames pending
+        if (android_atomic_dec(&mQueuedFrames) > 1) {
+            mFlinger->signalEvent();
+        }
 
-    ssize_t buf = lcblk->retireAndLock();
-    if (buf == NOT_ENOUGH_DATA) {
-        // NOTE: This is not an error, it simply means there is nothing to
-        // retire. The buffer is locked because we will use it
-        // for composition later in the loop
-        return;
-    }
+        if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
+            // something happened!
+            recomputeVisibleRegions = true;
+            return;
+        }
 
-    if (buf < NO_ERROR) {
-        LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
-        mPostedDirtyRegion.clear();
-        return;
-    }
+        mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+        mSurfaceTexture->getTransformMatrix(mTextureMatrix);
 
-    // we retired a buffer, which becomes the new front buffer
+        const Rect crop(mSurfaceTexture->getCurrentCrop());
+        const uint32_t transform(mSurfaceTexture->getCurrentTransform());
+        if ((crop != mCurrentCrop) || (transform != mCurrentTransform)) {
+            mCurrentCrop = crop;
+            mCurrentTransform = transform;
+            mFlinger->invalidateHwcGeometry();
+        }
 
-    const bool noActiveBuffer = !mBufferManager.hasActiveBuffer();
-    const bool activeBlending =
-            noActiveBuffer ? true : needsBlending(mBufferManager.getActiveBuffer());
-
-    if (mBufferManager.setActiveBufferIndex(buf) < NO_ERROR) {
-        LOGE("retireAndLock() buffer index (%d) out of range", int(buf));
-        mPostedDirtyRegion.clear();
-        return;
-    }
-
-    if (noActiveBuffer) {
-        // we didn't have an active buffer, we need to recompute
-        // our visible region
-        recomputeVisibleRegions = true;
-    }
-
-    sp<GraphicBuffer> newFrontBuffer(getBuffer(buf));
-    if (newFrontBuffer != NULL) {
-        if (!noActiveBuffer && activeBlending != needsBlending(newFrontBuffer)) {
-            // new buffer has different opacity than previous active buffer, need
-            // to recompute visible regions accordingly
+        const bool opacity(getOpacityForFormat(mActiveBuffer->format));
+        if (opacity != mCurrentOpacity) {
+            mCurrentOpacity = opacity;
             recomputeVisibleRegions = true;
         }
 
-        // get the dirty region
-        // compute the posted region
-        const Region dirty(lcblk->getDirtyRegion(buf));
-        mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
+        const GLenum target(mSurfaceTexture->getCurrentTextureTarget());
+        glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
         // update the layer size and release freeze-lock
         const Layer::State& front(drawingState());
+
+        // FIXME: mPostedDirtyRegion = dirty & bounds
+        mPostedDirtyRegion.set(front.w, front.h);
+
+        sp<GraphicBuffer> newFrontBuffer(mActiveBuffer);
         if ((newFrontBuffer->getWidth()  == front.requested_w &&
             newFrontBuffer->getHeight() == front.requested_h) ||
             isFixedSize())
@@ -685,35 +475,7 @@
             // we now have the correct size, unfreeze the screen
             mFreezeLock.clear();
         }
-
-        // get the crop region
-        setBufferCrop( lcblk->getCrop(buf) );
-
-        // get the transformation
-        setBufferTransform( lcblk->getTransform(buf) );
-
-    } else {
-        // this should not happen unless we ran out of memory while
-        // allocating the buffer. we're hoping that things will get back
-        // to normal the next time the app tries to draw into this buffer.
-        // meanwhile, pretend the screen didn't update.
-        mPostedDirtyRegion.clear();
     }
-
-    if (lcblk->getQueuedCount()) {
-        // signal an event if we have more buffers waiting
-        mFlinger->signalEvent();
-    }
-
-    /* a buffer was posted, so we need to call reloadTexture(), which
-     * will update our internal data structures (eg: EGLImageKHR or
-     * texture names). we need to do this even if mPostedDirtyRegion is
-     * empty -- it's orthogonal to the fact that a new buffer was posted,
-     * for instance, a degenerate case could be that the user did an empty
-     * update but repainted the buffer with appropriate content (after a
-     * resize for instance).
-     */
-    reloadTexture( mPostedDirtyRegion );
 }
 
 void Layer::unlockPageFlip(
@@ -746,329 +508,36 @@
 {
     LayerBaseClient::dump(result, buffer, SIZE);
 
-    ClientRef::Access sharedClient(mUserClientRef);
-    SharedBufferServer* lcblk(sharedClient.get());
-    uint32_t totalTime = 0;
-    if (lcblk) {
-        SharedBufferStack::Statistics stats = lcblk->getStats();
-        totalTime= stats.totalTime;
-        result.append( lcblk->dump("      ") );
-    }
-
-    sp<const GraphicBuffer> buf0(getBuffer(0));
-    sp<const GraphicBuffer> buf1(getBuffer(1));
-    uint32_t w0=0, h0=0, s0=0;
-    uint32_t w1=0, h1=0, s1=0;
+    sp<const GraphicBuffer> buf0(mActiveBuffer);
+    uint32_t w0=0, h0=0, s0=0, f0=0;
     if (buf0 != 0) {
         w0 = buf0->getWidth();
         h0 = buf0->getHeight();
         s0 = buf0->getStride();
-    }
-    if (buf1 != 0) {
-        w1 = buf1->getWidth();
-        h1 = buf1->getHeight();
-        s1 = buf1->getStride();
+        f0 = buf0->format;
     }
     snprintf(buffer, SIZE,
             "      "
-            "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
-            " freezeLock=%p, dq-q-time=%u us\n",
-            mFormat, w0, h0, s0, w1, h1, s1,
-            getFreezeLock().get(), totalTime);
+            "format=%2d, activeBuffer=[%3ux%3u:%3u,%3u],"
+            " freezeLock=%p, queued-frames=%d\n",
+            mFormat, w0, h0, s0,f0,
+            getFreezeLock().get(), mQueuedFrames);
 
     result.append(buffer);
-}
 
-// ---------------------------------------------------------------------------
-
-Layer::ClientRef::ClientRef()
-    : mControlBlock(0), mToken(-1) {
-}
-
-Layer::ClientRef::~ClientRef() {
-}
-
-int32_t Layer::ClientRef::getToken() const {
-    Mutex::Autolock _l(mLock);
-    return mToken;
-}
-
-sp<UserClient> Layer::ClientRef::getClient() const {
-    Mutex::Autolock _l(mLock);
-    return mUserClient.promote();
-}
-
-status_t Layer::ClientRef::setToken(const sp<UserClient>& uc,
-        const sp<SharedBufferServer>& sharedClient, int32_t token) {
-    Mutex::Autolock _l(mLock);
-
-    { // scope for strong mUserClient reference
-        sp<UserClient> userClient(mUserClient.promote());
-        if (userClient != 0 && mControlBlock != 0) {
-            mControlBlock->setStatus(NO_INIT);
-        }
+    if (mSurfaceTexture != 0) {
+        mSurfaceTexture->dump(result, "            ", buffer, SIZE);
     }
-
-    mUserClient = uc;
-    mToken = token;
-    mControlBlock = sharedClient;
-    return NO_ERROR;
 }
 
-sp<UserClient> Layer::ClientRef::getUserClientUnsafe() const {
-    return mUserClient.promote();
-}
-
-// this class gives us access to SharedBufferServer safely
-// it makes sure the UserClient (and its associated shared memory)
-// won't go away while we're accessing it.
-Layer::ClientRef::Access::Access(const ClientRef& ref)
-    : mControlBlock(0)
+uint32_t Layer::getEffectiveUsage(uint32_t usage) const
 {
-    Mutex::Autolock _l(ref.mLock);
-    mUserClientStrongRef = ref.mUserClient.promote();
-    if (mUserClientStrongRef != 0)
-        mControlBlock = ref.mControlBlock;
-}
-
-Layer::ClientRef::Access::~Access()
-{
-}
-
-// ---------------------------------------------------------------------------
-
-Layer::BufferManager::BufferManager(TextureManager& tm)
-    : mNumBuffers(NUM_BUFFERS), mTextureManager(tm),
-      mActiveBufferIndex(-1), mFailover(false)
-{
-}
-
-Layer::BufferManager::~BufferManager()
-{
-}
-
-status_t Layer::BufferManager::resize(size_t size,
-        const sp<SurfaceFlinger>& flinger, EGLDisplay dpy)
-{
-    Mutex::Autolock _l(mLock);
-
-    if (size < mNumBuffers) {
-        // If there is an active texture, move it into slot 0 if needed
-        if (mActiveBufferIndex > 0) {
-            BufferData activeBufferData = mBufferData[mActiveBufferIndex];
-            mBufferData[mActiveBufferIndex] = mBufferData[0];
-            mBufferData[0] = activeBufferData;
-            mActiveBufferIndex = 0;
-        }
-
-        // Free the buffers that are no longer needed.
-        for (size_t i = size; i < mNumBuffers; i++) {
-            mBufferData[i].buffer = 0;
-
-            // Create a message to destroy the textures on SurfaceFlinger's GL
-            // thread.
-            class MessageDestroyTexture : public MessageBase {
-                Image mTexture;
-                EGLDisplay mDpy;
-             public:
-                MessageDestroyTexture(const Image& texture, EGLDisplay dpy)
-                    : mTexture(texture), mDpy(dpy) { }
-                virtual bool handler() {
-                    status_t err = Layer::BufferManager::destroyTexture(
-                            &mTexture, mDpy);
-                    LOGE_IF(err<0, "error destroying texture: %d (%s)",
-                            mTexture.name, strerror(-err));
-                    return true; // XXX: err == 0;  ????
-                }
-            };
-
-            MessageDestroyTexture *msg = new MessageDestroyTexture(
-                    mBufferData[i].texture, dpy);
-
-            // Don't allow this texture to be cleaned up by
-            // BufferManager::destroy.
-            mBufferData[i].texture.name = -1U;
-            mBufferData[i].texture.image = EGL_NO_IMAGE_KHR;
-
-            // Post the message to the SurfaceFlinger object.
-            flinger->postMessageAsync(msg);
-        }
+    // TODO: should we do something special if mSecure is set?
+    if (mProtectedByApp) {
+        // need a hardware-protected path to external video sink
+        usage |= GraphicBuffer::USAGE_PROTECTED;
     }
-
-    mNumBuffers = size;
-    return NO_ERROR;
-}
-
-// only for debugging
-sp<GraphicBuffer> Layer::BufferManager::getBuffer(size_t index) const {
-    return mBufferData[index].buffer;
-}
-
-status_t Layer::BufferManager::setActiveBufferIndex(size_t index) {
-    BufferData const * const buffers = mBufferData;
-    Mutex::Autolock _l(mLock);
-    mActiveBuffer = buffers[index].buffer;
-    mActiveBufferIndex = index;
-    return NO_ERROR;
-}
-
-size_t Layer::BufferManager::getActiveBufferIndex() const {
-    return mActiveBufferIndex;
-}
-
-Texture Layer::BufferManager::getActiveTexture() const {
-    Texture res;
-    if (mFailover || mActiveBufferIndex<0) {
-        res = mFailoverTexture;
-    } else {
-        static_cast<Image&>(res) = mBufferData[mActiveBufferIndex].texture;
-    }
-    return res;
-}
-
-sp<GraphicBuffer> Layer::BufferManager::getActiveBuffer() const {
-    return mActiveBuffer;
-}
-
-bool Layer::BufferManager::hasActiveBuffer() const {
-    return mActiveBufferIndex >= 0;
-}
-
-sp<GraphicBuffer> Layer::BufferManager::detachBuffer(size_t index)
-{
-    BufferData* const buffers = mBufferData;
-    sp<GraphicBuffer> buffer;
-    Mutex::Autolock _l(mLock);
-    buffer = buffers[index].buffer;
-    buffers[index].buffer = 0;
-    return buffer;
-}
-
-status_t Layer::BufferManager::attachBuffer(size_t index,
-        const sp<GraphicBuffer>& buffer)
-{
-    BufferData* const buffers = mBufferData;
-    Mutex::Autolock _l(mLock);
-    buffers[index].buffer = buffer;
-    buffers[index].texture.dirty = true;
-    return NO_ERROR;
-}
-
-status_t Layer::BufferManager::destroy(EGLDisplay dpy)
-{
-    BufferData* const buffers = mBufferData;
-    size_t num;
-    { // scope for the lock
-        Mutex::Autolock _l(mLock);
-        num = mNumBuffers;
-        for (size_t i=0 ; i<num ; i++) {
-            buffers[i].buffer = 0;
-        }
-    }
-    for (size_t i=0 ; i<num ; i++) {
-        destroyTexture(&buffers[i].texture, dpy);
-    }
-    destroyTexture(&mFailoverTexture, dpy);
-    return NO_ERROR;
-}
-
-status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
-        const sp<GraphicBuffer>& buffer)
-{
-    status_t err = NO_INIT;
-    ssize_t index = mActiveBufferIndex;
-    if (index >= 0) {
-        if (!mFailover) {
-            {
-               // Without that lock, there is a chance of race condition
-               // where while composing a specific index, requestBuf
-               // with the same index can be executed and touch the same data
-               // that is being used in initEglImage.
-               // (e.g. dirty flag in texture)
-               Mutex::Autolock _l(mLock);
-               Image& texture(mBufferData[index].texture);
-               err = mTextureManager.initEglImage(&texture, dpy, buffer);
-            }
-            // if EGLImage fails, we switch to regular texture mode, and we
-            // free all resources associated with using EGLImages.
-            if (err == NO_ERROR) {
-                mFailover = false;
-                destroyTexture(&mFailoverTexture, dpy);
-            } else {
-                mFailover = true;
-                const size_t num = mNumBuffers;
-                for (size_t i=0 ; i<num ; i++) {
-                    destroyTexture(&mBufferData[i].texture, dpy);
-                }
-            }
-        } else {
-            // we failed once, don't try again
-            err = BAD_VALUE;
-        }
-    }
-    return err;
-}
-
-status_t Layer::BufferManager::loadTexture(
-        const Region& dirty, const GGLSurface& t)
-{
-    return mTextureManager.loadTexture(&mFailoverTexture, dirty, t);
-}
-
-status_t Layer::BufferManager::destroyTexture(Image* tex, EGLDisplay dpy)
-{
-    if (tex->name != -1U) {
-        glDeleteTextures(1, &tex->name);
-        tex->name = -1U;
-    }
-    if (tex->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, tex->image);
-        tex->image = EGL_NO_IMAGE_KHR;
-    }
-    return NO_ERROR;
-}
-
-// ---------------------------------------------------------------------------
-
-Layer::SurfaceLayer::SurfaceLayer(const sp<SurfaceFlinger>& flinger,
-        const sp<Layer>& owner)
-    : Surface(flinger, owner->getIdentity(), owner)
-{
-}
-
-Layer::SurfaceLayer::~SurfaceLayer()
-{
-}
-
-sp<GraphicBuffer> Layer::SurfaceLayer::requestBuffer(int index,
-        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
-    sp<GraphicBuffer> buffer;
-    sp<Layer> owner(getOwner());
-    if (owner != 0) {
-        /*
-         * requestBuffer() cannot be called from the main thread
-         * as it could cause a dead-lock, since it may have to wait
-         * on conditions updated my the main thread.
-         */
-        buffer = owner->requestBuffer(index, w, h, format, usage);
-    }
-    return buffer;
-}
-
-status_t Layer::SurfaceLayer::setBufferCount(int bufferCount)
-{
-    status_t err = DEAD_OBJECT;
-    sp<Layer> owner(getOwner());
-    if (owner != 0) {
-        /*
-         * setBufferCount() cannot be called from the main thread
-         * as it could cause a dead-lock, since it may have to wait
-         * on conditions updated my the main thread.
-         */
-        err = owner->setBufferCount(bufferCount);
-    }
-    return err;
+    return usage;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 278d64e..e3fc13d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -20,9 +20,11 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <gui/SurfaceTexture.h>
+
+#include <pixelflinger/pixelflinger.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
-#include <pixelflinger/pixelflinger.h>
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
@@ -30,8 +32,8 @@
 #include <GLES/glext.h>
 
 #include "LayerBase.h"
+#include "SurfaceTextureLayer.h"
 #include "Transform.h"
-#include "TextureManager.h"
 
 namespace android {
 
@@ -40,11 +42,10 @@
 class FreezeLock;
 class Client;
 class GLExtensions;
-class UserClient;
 
 // ---------------------------------------------------------------------------
 
-class Layer : public LayerBaseClient
+class Layer : public LayerBaseClient, private RefBase::Destroyer
 {
 public:
             Layer(SurfaceFlinger* flinger, DisplayID display,
@@ -58,164 +59,59 @@
     status_t setBuffers(uint32_t w, uint32_t h, 
             PixelFormat format, uint32_t flags=0);
 
-    // associate a UserClient to this Layer
-    status_t setToken(const sp<UserClient>& uc, SharedClient* sc, int32_t idx);
-    int32_t getToken() const;
-    sp<UserClient> getClient() const;
-
     // Set this Layer's buffers size
-    void setBufferSize(uint32_t w, uint32_t h);
     bool isFixedSize() const;
 
     // LayerBase interface
     virtual void setGeometry(hwc_layer_t* hwcl);
     virtual void setPerFrameData(hwc_layer_t* hwcl);
-    virtual void drawForSreenShot() const;
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
-    virtual bool needsBlending(const sp<GraphicBuffer>& buffer) const;
-    virtual bool needsBlending() const;
+    virtual bool isOpaque() const;
     virtual bool needsDithering() const     { return mNeedsDithering; }
-    virtual bool needsFiltering() const;
     virtual bool isSecure() const           { return mSecure; }
     virtual bool isProtected() const;
-    virtual sp<Surface> createSurface() const;
     virtual void onRemoved();
 
     // only for debugging
-    inline sp<GraphicBuffer> getBuffer(int i) const {
-        return mBufferManager.getBuffer(i); }
-    // only for debugging
-    inline const sp<FreezeLock>&  getFreezeLock() const {
-        return mFreezeLock; }
+    inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
 
 protected:
-    virtual void destroy() const;
+    virtual void destroy(RefBase const* base);
+    virtual void onFirstRef();
     virtual void dump(String8& result, char* scratch, size_t size) const;
 
 private:
-    void reloadTexture(const Region& dirty);
+    friend class SurfaceTextureLayer;
+    void onFrameQueued();
+    virtual sp<ISurface> createSurface();
     uint32_t getEffectiveUsage(uint32_t usage) const;
-    sp<GraphicBuffer> requestBuffer(int bufferIdx,
-            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-    status_t setBufferCount(int bufferCount);
+    void setFixedSize(bool fixedSize);
+    bool isCropped() const;
+    static bool getOpacityForFormat(uint32_t format);
 
     // -----------------------------------------------------------------------
 
-    class SurfaceLayer : public LayerBaseClient::Surface {
-    public:
-        SurfaceLayer(const sp<SurfaceFlinger>& flinger, const sp<Layer>& owner);
-        ~SurfaceLayer();
-    private:
-        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-        virtual status_t setBufferCount(int bufferCount);
-        sp<Layer> getOwner() const {
-            return static_cast<Layer*>(Surface::getOwner().get());
-        }
-    };
-    friend class SurfaceLayer;
-
-    // -----------------------------------------------------------------------
-
-    class ClientRef {
-        ClientRef(const ClientRef& rhs);
-        ClientRef& operator = (const ClientRef& rhs);
-        mutable Mutex mLock;
-        // binder thread, page-flip thread
-        sp<SharedBufferServer> mControlBlock;
-        wp<UserClient> mUserClient;
-        int32_t mToken;
-    public:
-        ClientRef();
-        ~ClientRef();
-        int32_t getToken() const;
-        sp<UserClient> getClient() const;
-        status_t setToken(const sp<UserClient>& uc,
-                const sp<SharedBufferServer>& sharedClient, int32_t token);
-        sp<UserClient> getUserClientUnsafe() const;
-        class Access {
-            Access(const Access& rhs);
-            Access& operator = (const Access& rhs);
-            sp<UserClient> mUserClientStrongRef;
-            sp<SharedBufferServer> mControlBlock;
-        public:
-            Access(const ClientRef& ref);
-            ~Access();
-            inline SharedBufferServer* get() const { return mControlBlock.get(); }
-        };
-        friend class Access;
-    };
-
-    // -----------------------------------------------------------------------
-
-    class BufferManager {
-        static const size_t NUM_BUFFERS = 2;
-        struct BufferData {
-            sp<GraphicBuffer>   buffer;
-            Image               texture;
-        };
-        // this lock protect mBufferData[].buffer but since there
-        // is very little contention, we have only one like for
-        // the whole array, we also use it to protect mNumBuffers.
-        mutable Mutex mLock;
-        BufferData          mBufferData[SharedBufferStack::NUM_BUFFER_MAX];
-        size_t              mNumBuffers;
-        Texture             mFailoverTexture;
-        TextureManager&     mTextureManager;
-        ssize_t             mActiveBufferIndex;
-        sp<GraphicBuffer>   mActiveBuffer;
-        bool                mFailover;
-        static status_t destroyTexture(Image* tex, EGLDisplay dpy);
-
-    public:
-        static size_t getDefaultBufferCount() { return NUM_BUFFERS; }
-        BufferManager(TextureManager& tm);
-        ~BufferManager();
-
-        // detach/attach buffer from/to given index
-        sp<GraphicBuffer> detachBuffer(size_t index);
-        status_t attachBuffer(size_t index, const sp<GraphicBuffer>& buffer);
-        // resize the number of active buffers
-        status_t resize(size_t size, const sp<SurfaceFlinger>& flinger,
-                EGLDisplay dpy);
-
-        // ----------------------------------------------
-        // must be called from GL thread
-
-        // set/get active buffer index
-        status_t setActiveBufferIndex(size_t index);
-        size_t getActiveBufferIndex() const;
-        // return the active buffer
-        sp<GraphicBuffer> getActiveBuffer() const;
-        // return wether we have an active buffer
-        bool hasActiveBuffer() const;
-        // return the active texture (or fail-over)
-        Texture getActiveTexture() const;
-        // frees resources associated with all buffers
-        status_t destroy(EGLDisplay dpy);
-        // load bitmap data into the active buffer
-        status_t loadTexture(const Region& dirty, const GGLSurface& t);
-        // make active buffer an EGLImage if needed
-        status_t initEglImage(EGLDisplay dpy,
-                const sp<GraphicBuffer>& buffer);
-
-        // ----------------------------------------------
-        // only for debugging
-        sp<GraphicBuffer> getBuffer(size_t index) const;
-    };
-
-    // -----------------------------------------------------------------------
+    // constants
+    sp<SurfaceTextureLayer> mSurfaceTexture;
+    GLuint mTextureName;
 
     // thread-safe
-    ClientRef mUserClientRef;
+    volatile int32_t mQueuedFrames;
+
+    // main thread
+    sp<GraphicBuffer> mActiveBuffer;
+    GLfloat mTextureMatrix[16];
+    Rect mCurrentCrop;
+    uint32_t mCurrentTransform;
+    bool mCurrentOpacity;
 
     // constants
     PixelFormat mFormat;
     const GLExtensions& mGLExtensions;
-    bool mNeedsBlending;
+    bool mOpaqueLayer;
     bool mNeedsDithering;
 
     // page-flip thread (currently main thread)
@@ -226,18 +122,8 @@
     // page-flip thread and transaction thread (currently main thread)
     sp<FreezeLock>  mFreezeLock;
 
-    // see threading usage in declaration
-    TextureManager mTextureManager;
-    BufferManager mBufferManager;
-
     // binder thread, transaction thread
     mutable Mutex mLock;
-    uint32_t mWidth;
-    uint32_t mHeight;
-    uint32_t mReqWidth;
-    uint32_t mReqHeight;
-    uint32_t mReqFormat;
-    bool mNeedsScaling;
     bool mFixedSize;
 };
 
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 022f251..bcd8c83 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -32,8 +32,6 @@
 #include "LayerBase.h"
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
-#include "TextureManager.h"
-
 
 namespace android {
 
@@ -44,7 +42,7 @@
 LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display)
     : dpy(display), contentDirty(false),
       sequence(uint32_t(android_atomic_inc(&sSequence))),
-      mFlinger(flinger),
+      mFlinger(flinger), mFiltering(false),
       mNeedsFiltering(false),
       mOrientation(0),
       mLeft(0), mTop(0),
@@ -54,8 +52,6 @@
 {
     const DisplayHardware& hw(flinger->graphicPlane(0).displayHardware());
     mFlags = hw.getFlags();
-    mBufferCrop.makeInvalid();
-    mBufferTransform = 0;
 }
 
 LayerBase::~LayerBase()
@@ -310,6 +306,16 @@
     hwcl->handle = NULL;
 }
 
+void LayerBase::setFiltering(bool filtering)
+{
+    mFiltering = filtering;
+}
+
+bool LayerBase::getFiltering() const
+{
+    return mFiltering;
+}
+
 void LayerBase::draw(const Region& clip) const
 {
     // reset GL state
@@ -318,10 +324,12 @@
     onDraw(clip);
 }
 
-void LayerBase::drawForSreenShot() const
+void LayerBase::drawForSreenShot()
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    setFiltering(true);
     onDraw( Region(hw.bounds()) );
+    setFiltering(false);
 }
 
 void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
@@ -332,8 +340,12 @@
     const uint32_t fbHeight = hw.getHeight();
     glColor4f(red,green,blue,alpha);
 
-    TextureManager::deactivateTextures();
-
+#if defined(GL_OES_EGL_image_external)
+        if (GLExtensions::getInstance().haveTextureExternal()) {
+            glDisable(GL_TEXTURE_EXTERNAL_OES);
+        }
+#endif
+    glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
     glDisable(GL_DITHER);
 
@@ -354,24 +366,11 @@
     clearWithOpenGL(clip,0,0,0,0);
 }
 
-template <typename T>
-static inline
-void swap(T& a, T& b) {
-    T t(a);
-    a = b;
-    b = t;
-}
-
-void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const
+void LayerBase::drawWithOpenGL(const Region& clip) const
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     const uint32_t fbHeight = hw.getHeight();
     const State& s(drawingState());
-    
-    // bind our texture
-    TextureManager::activateTexture(texture, needsFiltering());
-    uint32_t width  = texture.width; 
-    uint32_t height = texture.height;
 
     GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
     if (UNLIKELY(s.alpha < 0xFF)) {
@@ -387,7 +386,7 @@
     } else {
         glColor4f(1, 1, 1, 1);
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        if (needsBlending()) {
+        if (!isOpaque()) {
             glEnable(GL_BLEND);
             glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
         } else {
@@ -395,86 +394,20 @@
         }
     }
 
-    /*
-     *  compute texture coordinates
-     *  here, we handle NPOT, cropping and buffer transformations
-     */
-
-    GLfloat cl, ct, cr, cb;
-    if (!mBufferCrop.isEmpty()) {
-        // source is cropped
-        const GLfloat us = (texture.NPOTAdjust ? texture.wScale : 1.0f) / width;
-        const GLfloat vs = (texture.NPOTAdjust ? texture.hScale : 1.0f) / height;
-        cl = mBufferCrop.left   * us;
-        ct = mBufferCrop.top    * vs;
-        cr = mBufferCrop.right  * us;
-        cb = mBufferCrop.bottom * vs;
-    } else {
-        cl = 0;
-        ct = 0;
-        cr = (texture.NPOTAdjust ? texture.wScale : 1.0f);
-        cb = (texture.NPOTAdjust ? texture.hScale : 1.0f);
-    }
-
-    /*
-     * For the buffer transformation, we apply the rotation last.
-     * Since we're transforming the texture-coordinates, we need
-     * to apply the inverse of the buffer transformation:
-     *   inverse( FLIP_V -> FLIP_H -> ROT_90 )
-     *   <=> inverse( ROT_90 * FLIP_H * FLIP_V )
-     *    =  inverse(FLIP_V) * inverse(FLIP_H) * inverse(ROT_90)
-     *    =  FLIP_V * FLIP_H * ROT_270
-     *   <=> ROT_270 -> FLIP_H -> FLIP_V
-     *
-     * The rotation is performed first, in the texture coordinate space.
-     *
-     */
-
     struct TexCoords {
         GLfloat u;
         GLfloat v;
     };
 
-    enum {
-        // name of the corners in the texture map
-        LB = 0, // left-bottom
-        LT = 1, // left-top
-        RT = 2, // right-top
-        RB = 3  // right-bottom
-    };
-
-    // vertices in screen space
-    int vLT = LB;
-    int vLB = LT;
-    int vRB = RT;
-    int vRT = RB;
-
-    // the texture's source is rotated
-    uint32_t transform = mBufferTransform;
-    if (transform & HAL_TRANSFORM_ROT_90) {
-        vLT = RB;
-        vLB = LB;
-        vRB = LT;
-        vRT = RT;
-    }
-    if (transform & HAL_TRANSFORM_FLIP_V) {
-        swap(vLT, vLB);
-        swap(vRT, vRB);
-    }
-    if (transform & HAL_TRANSFORM_FLIP_H) {
-        swap(vLT, vRT);
-        swap(vLB, vRB);
-    }
-
     TexCoords texCoords[4];
-    texCoords[vLT].u = cl;
-    texCoords[vLT].v = ct;
-    texCoords[vLB].u = cl;
-    texCoords[vLB].v = cb;
-    texCoords[vRB].u = cr;
-    texCoords[vRB].v = cb;
-    texCoords[vRT].u = cr;
-    texCoords[vRT].v = ct;
+    texCoords[0].u = 0;
+    texCoords[0].v = 1;
+    texCoords[1].u = 0;
+    texCoords[1].v = 0;
+    texCoords[2].u = 1;
+    texCoords[2].v = 0;
+    texCoords[3].u = 1;
+    texCoords[3].v = 1;
 
     if (needsDithering()) {
         glEnable(GL_DITHER);
@@ -497,20 +430,6 @@
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
-void LayerBase::setBufferCrop(const Rect& crop) {
-    if (mBufferCrop != crop) {
-        mBufferCrop = crop;
-        mFlinger->invalidateHwcGeometry();
-    }
-}
-
-void LayerBase::setBufferTransform(uint32_t transform) {
-    if (mBufferTransform != transform) {
-        mBufferTransform = transform;
-        mFlinger->invalidateHwcGeometry();
-    }
-}
-
 void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
     const Layer::State& s(drawingState());
@@ -518,10 +437,10 @@
             "+ %s %p\n"
             "      "
             "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), "
-            "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, "
+            "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
             getTypeId(), this, s.z, tx(), ty(), s.w, s.h,
-            needsBlending(), needsDithering(), contentDirty,
+            isOpaque(), needsDithering(), contentDirty,
             s.alpha, s.flags,
             s.transform[0][0], s.transform[0][1],
             s.transform[1][0], s.transform[1][1]);
@@ -555,9 +474,22 @@
     }
 }
 
-sp<LayerBaseClient::Surface> LayerBaseClient::getSurface()
+sp<ISurface> LayerBaseClient::createSurface()
 {
-    sp<Surface> s;
+    class BSurface : public BnSurface, public LayerCleaner {
+        virtual sp<ISurfaceTexture> getSurfaceTexture() const { return 0; }
+    public:
+        BSurface(const sp<SurfaceFlinger>& flinger,
+                const sp<LayerBaseClient>& layer)
+            : LayerCleaner(flinger, layer) { }
+    };
+    sp<ISurface> sur(new BSurface(mFlinger, this));
+    return sur;
+}
+
+sp<ISurface> LayerBaseClient::getSurface()
+{
+    sp<ISurface> s;
     Mutex::Autolock _l(mLock);
 
     LOG_ALWAYS_FATAL_IF(mHasSurface,
@@ -573,12 +505,6 @@
     return mClientSurfaceBinder;
 }
 
-sp<LayerBaseClient::Surface> LayerBaseClient::createSurface() const
-{
-    return new Surface(mFlinger, mIdentity,
-            const_cast<LayerBaseClient *>(this));
-}
-
 void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
 {
     LayerBase::dump(result, buffer, SIZE);
@@ -601,44 +527,14 @@
 
 // ---------------------------------------------------------------------------
 
-LayerBaseClient::Surface::Surface(
-        const sp<SurfaceFlinger>& flinger,
-        int identity,
-        const sp<LayerBaseClient>& owner) 
-    : mFlinger(flinger), mIdentity(identity), mOwner(owner)
-{
+LayerBaseClient::LayerCleaner::LayerCleaner(const sp<SurfaceFlinger>& flinger,
+        const sp<LayerBaseClient>& layer)
+    : mFlinger(flinger), mLayer(layer) {
 }
 
-LayerBaseClient::Surface::~Surface() 
-{
-    /*
-     * This is a good place to clean-up all client resources 
-     */
-
+LayerBaseClient::LayerCleaner::~LayerCleaner() {
     // destroy client resources
-    mFlinger->destroySurface(mOwner);
-}
-
-sp<LayerBaseClient> LayerBaseClient::Surface::getOwner() const {
-    sp<LayerBaseClient> owner(mOwner.promote());
-    return owner;
-}
-
-status_t LayerBaseClient::Surface::onTransact(
-        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
-    return BnSurface::onTransact(code, data, reply, flags);
-}
-
-sp<GraphicBuffer> LayerBaseClient::Surface::requestBuffer(int bufferIdx,
-        uint32_t w, uint32_t h, uint32_t format, uint32_t usage)
-{
-    return NULL; 
-}
-
-status_t LayerBaseClient::Surface::setBufferCount(int bufferCount)
-{
-    return INVALID_OPERATION;
+    mFlinger->destroySurface(mLayer);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 6c49a19..faf71dd 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -29,7 +29,6 @@
 #include <ui/Region.h>
 
 #include <surfaceflinger/ISurfaceComposerClient.h>
-#include <private/surfaceflinger/SharedBufferStack.h>
 #include <private/surfaceflinger/LayerState.h>
 
 #include <pixelflinger/pixelflinger.h>
@@ -43,13 +42,12 @@
 
 // ---------------------------------------------------------------------------
 
-class DisplayHardware;
 class Client;
+class DisplayHardware;
 class GraphicBuffer;
 class GraphicPlane;
 class LayerBaseClient;
 class SurfaceFlinger;
-class Texture;
 
 // ---------------------------------------------------------------------------
 
@@ -121,7 +119,7 @@
      * to perform the actual drawing.  
      */
     virtual void draw(const Region& clip) const;
-    virtual void drawForSreenShot() const;
+    virtual void drawForSreenShot();
     
     /**
      * onDraw - draws the surface.
@@ -174,9 +172,9 @@
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
     
     /**
-     * needsBlending - true if this surface needs blending
+     * isOpaque - true if this surface is opaque
      */
-    virtual bool needsBlending() const  { return false; }
+    virtual bool isOpaque() const  { return true; }
 
     /**
      * needsDithering - true if this surface needs dithering
@@ -184,11 +182,9 @@
     virtual bool needsDithering() const { return false; }
 
     /**
-     * needsLinearFiltering - true if this surface needs filtering
+     * needsLinearFiltering - true if this surface's state requires filtering
      */
-    virtual bool needsFiltering() const {
-        return (!(mFlags & DisplayHardware::SLOW_CONFIG)) && mNeedsFiltering;
-    }
+    virtual bool needsFiltering() const { return mNeedsFiltering; }
 
     /**
      * isSecure - true if this surface is secure, that is if it prevents
@@ -231,21 +227,25 @@
           void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
                                GLclampf b, GLclampf alpha) const;
           void clearWithOpenGL(const Region& clip) const;
-          void drawWithOpenGL(const Region& clip, const Texture& texture) const;
-          
-          // these must be called from the post/drawing thread
-          void setBufferCrop(const Rect& crop);
-          void setBufferTransform(uint32_t transform);
+          void drawWithOpenGL(const Region& clip) const;
+
+          void setFiltering(bool filtering);
+          bool getFiltering() const;
 
                 sp<SurfaceFlinger> mFlinger;
                 uint32_t        mFlags;
 
-                // post/drawing thread
-                Rect mBufferCrop;
-                uint32_t mBufferTransform;
+private:
+                // accessed only in the main thread
+                // Whether filtering is forced on or not
+                bool            mFiltering;
 
                 // cached during validateVisibility()
+                // Whether filtering is needed b/c of the drawingstate
                 bool            mNeedsFiltering;
+
+protected:
+                // cached during validateVisibility()
                 int32_t         mOrientation;
                 GLfloat         mVertices[4][2];
                 Rect            mTransformedBounds;
@@ -281,52 +281,38 @@
 class LayerBaseClient : public LayerBase
 {
 public:
-    class Surface;
-
             LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
                         const sp<Client>& client);
-    virtual ~LayerBaseClient();
 
-            sp<Surface> getSurface();
+            virtual ~LayerBaseClient();
+
+            sp<ISurface> getSurface();
             wp<IBinder> getSurfaceBinder() const;
-    virtual sp<Surface> createSurface() const;
+
     virtual sp<LayerBaseClient> getLayerBaseClient() const {
         return const_cast<LayerBaseClient*>(this); }
+
     virtual const char* getTypeId() const { return "LayerBaseClient"; }
 
     uint32_t getIdentity() const { return mIdentity; }
 
-    class Surface : public BnSurface  {
-    public:
-        int32_t getIdentity() const { return mIdentity; }
-        
-    protected:
-        Surface(const sp<SurfaceFlinger>& flinger, int identity,
-                const sp<LayerBaseClient>& owner);
-        virtual ~Surface();
-        virtual status_t onTransact(uint32_t code, const Parcel& data,
-                Parcel* reply, uint32_t flags);
-        sp<LayerBaseClient> getOwner() const;
-
-    private:
-        virtual sp<GraphicBuffer> requestBuffer(int bufferIdx,
-                uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
-        virtual status_t setBufferCount(int bufferCount);
-
-    protected:
-        friend class LayerBaseClient;
-        sp<SurfaceFlinger>  mFlinger;
-        int32_t             mIdentity;
-        wp<LayerBaseClient> mOwner;
-    };
-
-    friend class Surface;
-
 protected:
     virtual void dump(String8& result, char* scratch, size_t size) const;
     virtual void shortDump(String8& result, char* scratch, size_t size) const;
 
+    class LayerCleaner {
+        sp<SurfaceFlinger> mFlinger;
+        wp<LayerBaseClient> mLayer;
+    protected:
+        ~LayerCleaner();
+    public:
+        LayerCleaner(const sp<SurfaceFlinger>& flinger,
+                const sp<LayerBaseClient>& layer);
+    };
+
 private:
+    virtual sp<ISurface> createSurface();
+
     mutable Mutex mLock;
     mutable bool mHasSurface;
     wp<IBinder> mClientSurfaceBinder;
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index f79166d..654817d 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -65,8 +65,6 @@
             glDisable(GL_TEXTURE_EXTERNAL_OES);
         }
 #endif
-        glDisable(GL_TEXTURE_2D);
-
         glVertexPointer(2, GL_FLOAT, 0, mVertices);
 
         while (it != end) {
diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h
index 75f9a89..8770e6d 100644
--- a/services/surfaceflinger/LayerDim.h
+++ b/services/surfaceflinger/LayerDim.h
@@ -37,7 +37,7 @@
         virtual ~LayerDim();
 
     virtual void onDraw(const Region& clip) const;
-    virtual bool needsBlending() const    { return true; }
+    virtual bool isOpaque() const         { return false; }
     virtual bool isSecure() const         { return false; }
     virtual bool isProtectedByApp() const { return false; }
     virtual bool isProtectedByDRM() const { return false; }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index b7a51a4..1c57bc1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -32,6 +32,7 @@
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
 #include <binder/MemoryHeapBase.h>
+#include <binder/PermissionCache.h>
 
 #include <utils/String8.h>
 #include <utils/String16.h>
@@ -53,6 +54,8 @@
 #include "DisplayHardware/DisplayHardware.h"
 #include "DisplayHardware/HWComposer.h"
 
+#include <private/surfaceflinger/SharedBufferStack.h>
+
 /* ideally AID_GRAPHICS would be in a semi-public header
  * or there would be a way to map a user/group name to its id
  */
@@ -65,17 +68,19 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
+const String16 sHardwareTest("android.permission.HARDWARE_TEST");
+const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
+const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
+const String16 sDump("android.permission.DUMP");
+
+// ---------------------------------------------------------------------------
+
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(), Thread(false),
         mTransactionFlags(0),
-        mTransactionCount(0),
         mResizeTransationPending(false),
         mLayersRemoved(false),
         mBootTime(systemTime()),
-        mHardwareTest("android.permission.HARDWARE_TEST"),
-        mAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"),
-        mReadFramebuffer("android.permission.READ_FRAME_BUFFER"),
-        mDump("android.permission.DUMP"),
         mVisibleRegionsDirty(false),
         mHwWorkListDirty(false),
         mDeferReleaseConsole(false),
@@ -133,17 +138,6 @@
     return bclient;
 }
 
-sp<ISurfaceComposerClient> SurfaceFlinger::createClientConnection()
-{
-    sp<ISurfaceComposerClient> bclient;
-    sp<UserClient> client(new UserClient(this));
-    status_t err = client->initCheck();
-    if (err == NO_ERROR) {
-        bclient = client;
-    }
-    return bclient;
-}
-
 sp<IGraphicBufferAlloc> SurfaceFlinger::createGraphicBufferAlloc()
 {
     sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc());
@@ -322,11 +316,6 @@
     mEventQueue.invalidate();
 }
 
-void SurfaceFlinger::signal() const {
-    // this is the IPC call
-    const_cast<SurfaceFlinger*>(this)->signalEvent();
-}
-
 bool SurfaceFlinger::authenticateSurface(const sp<ISurface>& surface) const {
     Mutex::Autolock _l(mStateLock);
     sp<IBinder> surfBinder(surface->asBinder());
@@ -395,13 +384,11 @@
         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 = peekTransactionFlags(mask);
-        if (LIKELY(transactionFlags)) {
-            handleTransaction(transactionFlags);
-        }
+    // if we're in a global transaction, don't do anything.
+    const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+    uint32_t transactionFlags = peekTransactionFlags(mask);
+    if (UNLIKELY(transactionFlags)) {
+        handleTransaction(transactionFlags);
     }
 
     // post surfaces (if needed)
@@ -658,7 +645,7 @@
 
         // handle hidden surfaces by setting the visible region to empty
         if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) {
-            const bool translucent = layer->needsBlending();
+            const bool translucent = !layer->isOpaque();
             const Rect bounds(layer->visibleBounds());
             visibleRegion.set(bounds);
             visibleRegion.andSelf(screenRegion);
@@ -921,7 +908,7 @@
             for (size_t i=0 ; i<count ; i++) {
                 if (cur[i].hints & HWC_HINT_CLEAR_FB) {
                     const sp<LayerBase>& layer(layers[i]);
-                    if (!(layer->needsBlending())) {
+                    if (layer->isOpaque()) {
                         transparent.orSelf(layer->visibleRegionScreen);
                     }
                 }
@@ -979,8 +966,6 @@
         composeSurfaces(repaint);
     }
 
-    TextureManager::deactivateTextures();
-
     glDisable(GL_BLEND);
     glDisable(GL_DITHER);
     glDisable(GL_SCISSOR_TEST);
@@ -1070,6 +1055,7 @@
             glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
         }
         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+        glDisable(GL_TEXTURE_2D);
         glLoadIdentity();
         glMatrixMode(GL_MODELVIEW);
     }
@@ -1187,28 +1173,33 @@
     return old;
 }
 
-void SurfaceFlinger::openGlobalTransaction()
-{
-    android_atomic_inc(&mTransactionCount);
-}
 
-void SurfaceFlinger::closeGlobalTransaction()
-{
-    if (android_atomic_dec(&mTransactionCount) == 1) {
-        signalEvent();
+void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state) {
+    Mutex::Autolock _l(mStateLock);
 
-        // if there is a transaction with a resize, wait for it to
-        // take effect before returning.
-        Mutex::Autolock _l(mStateLock);
-        while (mResizeTransationPending) {
-            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
-            if (CC_UNLIKELY(err != NO_ERROR)) {
-                // just in case something goes wrong in SF, return to the
-                // called after a few seconds.
-                LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
-                mResizeTransationPending = false;
-                break;
-            }
+    uint32_t flags = 0;
+    const size_t count = state.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const ComposerState& s(state[i]);
+        sp<Client> client( static_cast<Client *>(s.client.get()) );
+        flags |= setClientStateLocked(client, s.state);
+    }
+    if (flags) {
+        setTransactionFlags(flags);
+    }
+
+    signalEvent();
+
+    // if there is a transaction with a resize, wait for it to
+    // take effect before returning.
+    while (mResizeTransationPending) {
+        status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+        if (CC_UNLIKELY(err != NO_ERROR)) {
+            // just in case something goes wrong in SF, return to the
+            // called after a few seconds.
+            LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+            mResizeTransationPending = false;
+            break;
         }
     }
 }
@@ -1269,7 +1260,7 @@
         uint32_t flags)
 {
     sp<LayerBaseClient> layer;
-    sp<LayerBaseClient::Surface> surfaceHandle;
+    sp<ISurface> surfaceHandle;
 
     if (int32_t(w|h) < 0) {
         LOGE("createSurface() failed, w or h is negative (w=%d, h=%d)",
@@ -1300,13 +1291,13 @@
         surfaceHandle = layer->getSurface();
         if (surfaceHandle != 0) {
             params->token = token;
-            params->identity = surfaceHandle->getIdentity();
+            params->identity = layer->getIdentity();
             params->width = w;
             params->height = h;
             params->format = format;
             if (normalLayer != 0) {
                 Mutex::Autolock _l(mStateLock);
-                mLayerMap.add(surfaceHandle->asBinder(), normalLayer);
+                mLayerMap.add(layer->getSurfaceBinder(), normalLayer);
             }
         }
 
@@ -1404,60 +1395,52 @@
     return err;
 }
 
-status_t SurfaceFlinger::setClientState(
+uint32_t SurfaceFlinger::setClientStateLocked(
         const sp<Client>& client,
-        int32_t count,
-        const layer_state_t* states)
+        const layer_state_t& s)
 {
-    Mutex::Autolock _l(mStateLock);
     uint32_t flags = 0;
-    for (int i=0 ; i<count ; i++) {
-        const layer_state_t& s(states[i]);
-        sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
-        if (layer != 0) {
-            const uint32_t what = s.what;
-            if (what & ePositionChanged) {
-                if (layer->setPosition(s.x, s.y))
-                    flags |= eTraversalNeeded;
-            }
-            if (what & eLayerChanged) {
-                ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
-                if (layer->setLayer(s.z)) {
-                    mCurrentState.layersSortedByZ.removeAt(idx);
-                    mCurrentState.layersSortedByZ.add(layer);
-                    // we need traversal (state changed)
-                    // AND transaction (list changed)
-                    flags |= eTransactionNeeded|eTraversalNeeded;
-                }
-            }
-            if (what & eSizeChanged) {
-                if (layer->setSize(s.w, s.h)) {
-                    flags |= eTraversalNeeded;
-                    mResizeTransationPending = true;
-                }
-            }
-            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;
+    sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
+    if (layer != 0) {
+        const uint32_t what = s.what;
+        if (what & ePositionChanged) {
+            if (layer->setPosition(s.x, s.y))
+                flags |= eTraversalNeeded;
+        }
+        if (what & eLayerChanged) {
+            ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+            if (layer->setLayer(s.z)) {
+                mCurrentState.layersSortedByZ.removeAt(idx);
+                mCurrentState.layersSortedByZ.add(layer);
+                // we need traversal (state changed)
+                // AND transaction (list changed)
+                flags |= eTransactionNeeded|eTraversalNeeded;
             }
         }
+        if (what & eSizeChanged) {
+            if (layer->setSize(s.w, s.h)) {
+                flags |= eTraversalNeeded;
+                mResizeTransationPending = true;
+            }
+        }
+        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;
+    return flags;
 }
 
 void SurfaceFlinger::screenReleased(int dpy)
@@ -1479,7 +1462,8 @@
     const size_t SIZE = 4096;
     char buffer[SIZE];
     String8 result;
-    if (!mDump.checkCalling()) {
+
+    if (!PermissionCache::checkCallingPermission(sDump)) {
         snprintf(buffer, SIZE, "Permission Denial: "
                 "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
                 IPCThreadState::self()->getCallingPid(),
@@ -1598,8 +1582,7 @@
 {
     switch (code) {
         case CREATE_CONNECTION:
-        case OPEN_GLOBAL_TRANSACTION:
-        case CLOSE_GLOBAL_TRANSACTION:
+        case SET_TRANSACTION_STATE:
         case SET_ORIENTATION:
         case FREEZE_DISPLAY:
         case UNFREEZE_DISPLAY:
@@ -1611,7 +1594,8 @@
             IPCThreadState* ipc = IPCThreadState::self();
             const int pid = ipc->getCallingPid();
             const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS) && !mAccessSurfaceFlinger.check(pid, uid)) {
+            if ((uid != AID_GRAPHICS) &&
+                    !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) {
                 LOGE("Permission Denial: "
                         "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid);
                 return PERMISSION_DENIED;
@@ -1624,7 +1608,8 @@
             IPCThreadState* ipc = IPCThreadState::self();
             const int pid = ipc->getCallingPid();
             const int uid = ipc->getCallingUid();
-            if ((uid != AID_GRAPHICS) && !mReadFramebuffer.check(pid, uid)) {
+            if ((uid != AID_GRAPHICS) &&
+                    !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
                 LOGE("Permission Denial: "
                         "can't read framebuffer pid=%d, uid=%d", pid, uid);
                 return PERMISSION_DENIED;
@@ -1636,7 +1621,7 @@
     status_t err = BnSurfaceComposer::onTransact(code, data, reply, flags);
     if (err == UNKNOWN_TRANSACTION || err == PERMISSION_DENIED) {
         CHECK_INTERFACE(ISurfaceComposer, data, reply);
-        if (UNLIKELY(!mHardwareTest.checkCalling())) {
+        if (UNLIKELY(!PermissionCache::checkCallingPermission(sHardwareTest))) {
             IPCThreadState* ipc = IPCThreadState::self();
             const int pid = ipc->getCallingPid();
             const int uid = ipc->getCallingUid();
@@ -1782,7 +1767,6 @@
 
     GLfloat vtx[8];
     const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
-    glEnable(GL_TEXTURE_2D);
     glBindTexture(GL_TEXTURE_2D, tname);
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -1900,6 +1884,7 @@
     glEnable(GL_SCISSOR_TEST);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDeleteTextures(1, &tname);
+    glDisable(GL_TEXTURE_2D);
     return NO_ERROR;
 }
 
@@ -1930,7 +1915,6 @@
 
     GLfloat vtx[8];
     const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
-    glEnable(GL_TEXTURE_2D);
     glBindTexture(GL_TEXTURE_2D, tname);
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -2044,6 +2028,7 @@
     glEnable(GL_SCISSOR_TEST);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDeleteTextures(1, &tname);
+    glDisable(GL_TEXTURE_2D);
 
     return NO_ERROR;
 }
@@ -2408,134 +2393,75 @@
     return lbc;
 }
 
-sp<IMemoryHeap> Client::getControlBlock() const {
-    return 0;
+
+status_t Client::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    // these must be checked
+     IPCThreadState* ipc = IPCThreadState::self();
+     const int pid = ipc->getCallingPid();
+     const int uid = ipc->getCallingUid();
+     const int self_pid = getpid();
+     if (UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) {
+         // we're called from a different process, do the real check
+         if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger))
+         {
+             LOGE("Permission Denial: "
+                     "can't openGlobalTransaction pid=%d, uid=%d", pid, uid);
+             return PERMISSION_DENIED;
+         }
+     }
+     return BnSurfaceComposerClient::onTransact(code, data, reply, flags);
 }
-ssize_t Client::getTokenForSurface(const sp<ISurface>& sur) const {
-    return -1;
-}
+
+
 sp<ISurface> Client::createSurface(
         ISurfaceComposerClient::surface_data_t* params,
         const String8& name,
         DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
         uint32_t flags)
 {
-    return mFlinger->createSurface(params, name, this,
-            display, w, h, format, flags);
+    /*
+     * createSurface must be called from the GL thread so that it can
+     * have access to the GL context.
+     */
+
+    class MessageCreateSurface : public MessageBase {
+        sp<ISurface> result;
+        SurfaceFlinger* flinger;
+        ISurfaceComposerClient::surface_data_t* params;
+        Client* client;
+        const String8& name;
+        DisplayID display;
+        uint32_t w, h;
+        PixelFormat format;
+        uint32_t flags;
+    public:
+        MessageCreateSurface(SurfaceFlinger* flinger,
+                ISurfaceComposerClient::surface_data_t* params,
+                const String8& name, Client* client,
+                DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
+                uint32_t flags)
+            : flinger(flinger), params(params), client(client), name(name),
+              display(display), w(w), h(h), format(format), flags(flags)
+        {
+        }
+        sp<ISurface> getResult() const { return result; }
+        virtual bool handler() {
+            result = flinger->createSurface(params, name, client,
+                    display, w, h, format, flags);
+            return true;
+        }
+    };
+
+    sp<MessageBase> msg = new MessageCreateSurface(mFlinger.get(),
+            params, name, this, display, w, h, format, flags);
+    mFlinger->postMessageSync(msg);
+    return static_cast<MessageCreateSurface*>( msg.get() )->getResult();
 }
 status_t Client::destroySurface(SurfaceID sid) {
     return mFlinger->removeSurface(this, sid);
 }
-status_t Client::setState(int32_t count, const layer_state_t* states) {
-    return mFlinger->setClientState(this, count, states);
-}
-
-// ---------------------------------------------------------------------------
-
-UserClient::UserClient(const sp<SurfaceFlinger>& flinger)
-    : ctrlblk(0), mBitmap(0), mFlinger(flinger)
-{
-    const int pgsize = getpagesize();
-    const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));
-
-    mCblkHeap = new MemoryHeapBase(cblksize, 0,
-            "SurfaceFlinger Client control-block");
-
-    ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());
-    if (ctrlblk) { // construct the shared structure in-place.
-        new(ctrlblk) SharedClient;
-    }
-}
-
-UserClient::~UserClient()
-{
-    if (ctrlblk) {
-        ctrlblk->~SharedClient();  // destroy our shared-structure.
-    }
-
-    /*
-     * When a UserClient dies, it's unclear what to do exactly.
-     * We could go ahead and destroy all surfaces linked to that client
-     * however, it wouldn't be fair to the main Client
-     * (usually the the window-manager), which might want to re-target
-     * the layer to another UserClient.
-     * I think the best is to do nothing, or not much; in most cases the
-     * WM itself will go ahead and clean things up when it detects a client of
-     * his has died.
-     * The remaining question is what to display? currently we keep
-     * just keep the current buffer.
-     */
-}
-
-status_t UserClient::initCheck() const {
-    return ctrlblk == 0 ? NO_INIT : NO_ERROR;
-}
-
-void UserClient::detachLayer(const Layer* layer)
-{
-    int32_t name = layer->getToken();
-    if (name >= 0) {
-        int32_t mask = 1LU<<name;
-        if ((android_atomic_and(~mask, &mBitmap) & mask) == 0) {
-            LOGW("token %d wasn't marked as used %08x", name, int(mBitmap));
-        }
-    }
-}
-
-sp<IMemoryHeap> UserClient::getControlBlock() const {
-    return mCblkHeap;
-}
-
-ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
-{
-    int32_t name = NAME_NOT_FOUND;
-    sp<Layer> layer(mFlinger->getLayer(sur));
-    if (layer == 0) {
-        return name;
-    }
-
-    // if this layer already has a token, just return it
-    name = layer->getToken();
-    if ((name >= 0) && (layer->getClient() == this)) {
-        return name;
-    }
-
-    name = 0;
-    do {
-        int32_t mask = 1LU<<name;
-        if ((android_atomic_or(mask, &mBitmap) & mask) == 0) {
-            // we found and locked that name
-            status_t err = layer->setToken(
-                    const_cast<UserClient*>(this), ctrlblk, name);
-            if (err != NO_ERROR) {
-                // free the name
-                android_atomic_and(~mask, &mBitmap);
-                name = err;
-            }
-            break;
-        }
-        if (++name >= int32_t(SharedBufferStack::NUM_LAYERS_MAX))
-            name = NO_MEMORY;
-    } while(name >= 0);
-
-    //LOGD("getTokenForSurface(%p) => %d (client=%p, bitmap=%08lx)",
-    //        sur->asBinder().get(), name, this, mBitmap);
-    return name;
-}
-
-sp<ISurface> UserClient::createSurface(
-        ISurfaceComposerClient::surface_data_t* params,
-        const String8& name,
-        DisplayID display, uint32_t w, uint32_t h, PixelFormat format,
-        uint32_t flags) {
-    return 0;
-}
-status_t UserClient::destroySurface(SurfaceID sid) {
-    return INVALID_OPERATION;
-}
-status_t UserClient::setState(int32_t count, const layer_state_t* states) {
-    return INVALID_OPERATION;
-}
 
 // ---------------------------------------------------------------------------
 
@@ -2547,11 +2473,11 @@
         PixelFormat format, uint32_t usage) {
     sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage));
     status_t err = graphicBuffer->initCheck();
-    if (err != 0) {
-        LOGE("createGraphicBuffer: init check failed: %d", err);
-        return 0;
-    } else if (graphicBuffer->handle == 0) {
-        LOGE("createGraphicBuffer: unable to create GraphicBuffer");
+    if (err != 0 || graphicBuffer->handle == 0) {
+        GraphicBuffer::dumpAllocationsToSystemLog();
+        LOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) "
+             "failed (%s), handle=%p",
+                w, h, strerror(-err), graphicBuffer->handle);
         return 0;
     }
     return graphicBuffer;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 992861a..b49fa36 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -20,21 +20,20 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <utils/SortedVector.h>
-#include <utils/KeyedVector.h>
-#include <utils/threads.h>
 #include <utils/Atomic.h>
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/threads.h>
 
-#include <binder/IMemory.h>
-#include <binder/Permission.h>
 #include <binder/BinderService.h>
+#include <binder/IMemory.h>
 
 #include <ui/PixelFormat.h>
+#include <surfaceflinger/IGraphicBufferAlloc.h>
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/ISurfaceComposerClient.h>
-#include <surfaceflinger/IGraphicBufferAlloc.h>
 
 #include "Barrier.h"
 #include "Layer.h"
@@ -50,6 +49,7 @@
 class FreezeLock;
 class Layer;
 class LayerDim;
+struct surface_flinger_cblk_t;
 
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
@@ -70,16 +70,14 @@
     sp<LayerBaseClient> getLayerUser(int32_t i) const;
 
 private:
-
     // ISurfaceComposerClient interface
-    virtual sp<IMemoryHeap> getControlBlock() const;
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
     virtual sp<ISurface> createSurface(
             surface_data_t* params, const String8& name,
             DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
             uint32_t flags);
     virtual status_t destroySurface(SurfaceID surfaceId);
-    virtual status_t setState(int32_t count, const layer_state_t* states);
+    virtual status_t onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
 
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -92,40 +90,6 @@
     mutable Mutex mLock;
 };
 
-class UserClient : public BnSurfaceComposerClient
-{
-public:
-    // pointer to this client's control block
-    SharedClient* ctrlblk;
-
-public:
-        UserClient(const sp<SurfaceFlinger>& flinger);
-        ~UserClient();
-
-    status_t initCheck() const;
-
-    // protected by SurfaceFlinger::mStateLock
-    void detachLayer(const Layer* layer);
-
-private:
-
-    // ISurfaceComposerClient interface
-    virtual sp<IMemoryHeap> getControlBlock() const;
-    virtual ssize_t getTokenForSurface(const sp<ISurface>& sur) const;
-    virtual sp<ISurface> createSurface(
-            surface_data_t* params, const String8& name,
-            DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
-            uint32_t flags);
-    virtual status_t destroySurface(SurfaceID surfaceId);
-    virtual status_t setState(int32_t count, const layer_state_t* states);
-
-    // atomic-ops
-    mutable volatile int32_t mBitmap;
-
-    sp<IMemoryHeap> mCblkHeap;
-    sp<SurfaceFlinger> mFlinger;
-};
-
 class GraphicBufferAlloc : public BnGraphicBufferAlloc
 {
 public:
@@ -199,16 +163,13 @@
 
     // ISurfaceComposer interface
     virtual sp<ISurfaceComposerClient>  createConnection();
-    virtual sp<ISurfaceComposerClient>  createClientConnection();
     virtual sp<IGraphicBufferAlloc>     createGraphicBufferAlloc();
     virtual sp<IMemoryHeap>             getCblk() const;
     virtual void                        bootFinished();
-    virtual void                        openGlobalTransaction();
-    virtual void                        closeGlobalTransaction();
+    virtual void                        setTransactionState(const Vector<ComposerState>& state);
     virtual status_t                    freezeDisplay(DisplayID dpy, uint32_t flags);
     virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
     virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
-    virtual void                        signal() const;
     virtual bool                        authenticateSurface(const sp<ISurface>& surface) const;
 
     virtual status_t captureScreen(DisplayID dpy,
@@ -235,7 +196,6 @@
     friend class Client;
     friend class LayerBase;
     friend class LayerBaseClient;
-    friend class LayerBaseClient::Surface;
     friend class Layer;
     friend class LayerDim;
 
@@ -257,8 +217,7 @@
 
     status_t removeSurface(const sp<Client>& client, SurfaceID sid);
     status_t destroySurface(const wp<LayerBaseClient>& layer);
-    status_t setClientState(const sp<Client>& client,
-            int32_t count, const layer_state_t* states);
+    uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
 
     class LayerVector : public SortedVector< sp<LayerBase> > {
     public:
@@ -374,7 +333,6 @@
     mutable     Mutex                   mStateLock;
                 State                   mCurrentState;
     volatile    int32_t                 mTransactionFlags;
-    volatile    int32_t                 mTransactionCount;
                 Condition               mTransactionCV;
                 SortedVector< sp<LayerBase> > mLayerPurgatory;
                 bool                    mResizeTransationPending;
@@ -389,11 +347,7 @@
                 surface_flinger_cblk_t*     mServerCblk;
                 GLuint                      mWormholeTexName;
                 nsecs_t                     mBootTime;
-                Permission                  mHardwareTest;
-                Permission                  mAccessSurfaceFlinger;
-                Permission                  mReadFramebuffer;
-                Permission                  mDump;
-                
+
                 // Can only accessed from the main thread, these members
                 // don't need synchronization
                 State                       mDrawingState;
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
new file mode 100644
index 0000000..60fa965
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+
+#include "Layer.h"
+#include "SurfaceTextureLayer.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+
+SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer)
+    : SurfaceTexture(tex), mLayer(layer) {
+}
+
+SurfaceTextureLayer::~SurfaceTextureLayer() {
+}
+
+
+status_t SurfaceTextureLayer::setDefaultBufferSize(uint32_t w, uint32_t h)
+{
+    //LOGD("%s, w=%u, h=%u", __PRETTY_FUNCTION__, w, h);
+    return SurfaceTexture::setDefaultBufferSize(w, h);
+}
+
+status_t SurfaceTextureLayer::setDefaultBufferFormat(uint32_t format)
+{
+    mDefaultFormat = format;
+    return NO_ERROR;
+}
+
+status_t SurfaceTextureLayer::setBufferCount(int bufferCount) {
+    status_t res = SurfaceTexture::setBufferCount(bufferCount);
+    return res;
+}
+
+status_t SurfaceTextureLayer::dequeueBuffer(int *buf,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+
+    status_t res(NO_INIT);
+    sp<Layer> layer(mLayer.promote());
+    if (layer != NULL) {
+        if (format == 0)
+            format = mDefaultFormat;
+        uint32_t effectiveUsage = layer->getEffectiveUsage(usage);
+        //LOGD("%s, w=%u, h=%u, format=%u, usage=%08x, effectiveUsage=%08x",
+        //        __PRETTY_FUNCTION__, w, h, format, usage, effectiveUsage);
+        res = SurfaceTexture::dequeueBuffer(buf, w, h, format, effectiveUsage);
+        if (res == NO_ERROR) {
+            layer->setFixedSize(w && h);
+        }
+    }
+    return res;
+}
+
+
+// ---------------------------------------------------------------------------
+}; // namespace android
diff --git a/services/surfaceflinger/SurfaceTextureLayer.h b/services/surfaceflinger/SurfaceTextureLayer.h
new file mode 100644
index 0000000..7faff54
--- /dev/null
+++ b/services/surfaceflinger/SurfaceTextureLayer.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2011 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 ANDROID_SURFACE_TEXTURE_LAYER_H
+#define ANDROID_SURFACE_TEXTURE_LAYER_H
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <gui/SurfaceTexture.h>
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class Layer;
+
+class SurfaceTextureLayer : public SurfaceTexture
+{
+    wp<Layer> mLayer;
+    uint32_t mDefaultFormat;
+
+public:
+    SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer);
+    ~SurfaceTextureLayer();
+
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+    status_t setDefaultBufferFormat(uint32_t format);
+
+public:
+    virtual status_t setBufferCount(int bufferCount);
+
+protected:
+    virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
+            uint32_t format, uint32_t usage);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SURFACE_TEXTURE_LAYER_H
diff --git a/services/surfaceflinger/clz.h b/services/surfaceflinger/clz.h
index 0ddf986..ca44555 100644
--- a/services/surfaceflinger/clz.h
+++ b/services/surfaceflinger/clz.h
@@ -20,18 +20,10 @@
 
 namespace android {
 
-int clz_impl(int32_t x);
-
-int inline clz(int32_t x)
-{
-#if defined(__arm__) && !defined(__thumb__)
+int inline clz(int32_t x) {
     return __builtin_clz(x);
-#else
-    return clz_impl(x);
-#endif
 }
 
-
 }; // namespace android
 
 #endif /* ANDROID_SURFACE_FLINGER_CLZ_H */
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
index 18c54b3..56b2a8f 100644
--- a/services/surfaceflinger/tests/resize/resize.cpp
+++ b/services/surfaceflinger/tests/resize/resize.cpp
@@ -43,9 +43,9 @@
             PIXEL_FORMAT_RGB_565);
 
 
-    client->openTransaction();
+    SurfaceComposerClient::openGlobalTransaction();
     surface->setLayer(100000);
-    client->closeTransaction();
+    SurfaceComposerClient::closeGlobalTransaction();
 
     Surface::SurfaceInfo info;
     surface->lock(&info);
@@ -57,9 +57,9 @@
     android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h);
     surface->unlockAndPost();
 
-    client->openTransaction();
+    SurfaceComposerClient::openGlobalTransaction();
     surface->setSize(320, 240);
-    client->closeTransaction();
+    SurfaceComposerClient::closeGlobalTransaction();
 
     
     IPCThreadState::self()->joinThreadPool();
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 5265f91..8e1c3fe 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -39,9 +39,9 @@
     
     sp<SurfaceControl> surfaceControl = client->createSurface(
             getpid(), 0, 160, 240, PIXEL_FORMAT_RGB_565);
-    client->openTransaction();
+    SurfaceComposerClient::openGlobalTransaction();
     surfaceControl->setLayer(100000);
-    client->closeTransaction();
+    SurfaceComposerClient::closeGlobalTransaction();
 
     // pretend it went cross-process
     Parcel parcel;