diff options
40 files changed, 1165 insertions, 1709 deletions
diff --git a/cmds/keystore/certtool.h b/cmds/keystore/certtool.h deleted file mode 100644 index 9b72bf7..0000000 --- a/cmds/keystore/certtool.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -** -** Copyright 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 __CERTTOOL_H__ -#define __CERTTOOL_H__ - -#include <stdio.h> -#include <string.h> -#include <cutils/sockets.h> -#include <cutils/log.h> - -#include "common.h" -#include "netkeystore.h" - -#define CERT_NAME_LEN (2 * MAX_KEY_NAME_LENGTH + 2) - -/* - * The specific function 'get_cert' is used in daemons to get the key value - * from keystore. Caller should allocate the buffer and the length of the buffer - * should be MAX_KEY_VALUE_LENGTH. - */ -static inline int get_cert(const char *certname, unsigned char *value, int *size) -{ - int count, fd, ret = -1; - LPC_MARSHAL cmd; - char delimiter[] = "_"; - char *p = NULL; - char *context = NULL; - char *cname = (char*)cmd.data; - - if ((certname == NULL) || (value == NULL)) { - LOGE("get_cert: certname or value is null\n"); - return -1; - } - - if (strlcpy(cname, certname, CERT_NAME_LEN) >= CERT_NAME_LEN) { - LOGE("get_cert: keyname is too long\n"); - return -1; - } - - fd = socket_local_client(SOCKET_PATH, - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (fd == -1) { - LOGE("Keystore service is not up and running.\n"); - return -1; - } - - cmd.opcode = GET; - p = strstr(cname, delimiter); - cmd.len = strlen(certname) + 1; - if (p == NULL) goto err; - *p = 0; // replace the delimiter with \0 . - - if (write_marshal(fd, &cmd)) { - LOGE("Incorrect command or command line is too long.\n"); - goto err; - } - if (read_marshal(fd, &cmd)) { - LOGE("Failed to read the result.\n"); - goto err; - } - - // copy the result if succeeded. - if (!cmd.retcode && cmd.len <= BUFFER_MAX) { - memcpy(value, cmd.data, cmd.len); - ret = 0; - *size = cmd.len; - } -err: - close(fd); - return ret; -} - -#endif diff --git a/cmds/keystore/common.h b/cmds/keystore/common.h deleted file mode 100644 index a18114e..0000000 --- a/cmds/keystore/common.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -** -** Copyright 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 __COMMON_H__ -#define __COMMON_H__ - -#define SOCKET_PATH "keystore" -#define KEYSTORE_DIR "/data/misc/keystore/" - -#define READ_TIMEOUT 3 -#define MAX_KEY_NAME_LENGTH 64 -#define MAX_NAMESPACE_LENGTH MAX_KEY_NAME_LENGTH -#define MAX_KEY_VALUE_LENGTH 4096 - -#define BUFFER_MAX MAX_KEY_VALUE_LENGTH - -typedef enum { - BOOTUP, - UNINITIALIZED, - LOCKED, - UNLOCKED, -} KEYSTORE_STATE; - -typedef enum { - LOCK, - UNLOCK, - PASSWD, - GETSTATE, - LISTKEYS, - GET, - PUT, - REMOVE, - RESET, - MAX_OPCODE -} KEYSTORE_OPCODE; - -typedef struct { - uint32_t len; - union { - uint32_t opcode; - uint32_t retcode; - }; - unsigned char data[BUFFER_MAX + 1]; -} LPC_MARSHAL; - -#endif diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c deleted file mode 100644 index b5ace86..0000000 --- a/cmds/keystore/keymgmt.c +++ /dev/null @@ -1,421 +0,0 @@ -/* -** Copyright 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 <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <ctype.h> -#include <fcntl.h> -#include <dirent.h> -#include <errno.h> -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <cutils/log.h> - -#include "common.h" -#include "keymgmt.h" - -static int retry_count = 0; -static unsigned char iv[IV_LEN]; -static KEYSTORE_STATE state = BOOTUP; -static AES_KEY encryptKey, decryptKey; - -inline void unlock_keystore(unsigned char *master_key) -{ - AES_set_encrypt_key(master_key, AES_KEY_LEN, &encryptKey); - AES_set_decrypt_key(master_key, AES_KEY_LEN, &decryptKey); - memset(master_key, 0, sizeof(master_key)); - state = UNLOCKED; -} - -inline void lock_keystore() -{ - memset(&encryptKey, 0 , sizeof(AES_KEY)); - memset(&decryptKey, 0 , sizeof(AES_KEY)); - state = LOCKED; -} - -inline void get_encrypt_key(char *passwd, AES_KEY *key) -{ - unsigned char user_key[USER_KEY_LEN]; - gen_key(passwd, user_key, USER_KEY_LEN); - AES_set_encrypt_key(user_key, AES_KEY_LEN, key); -} - -inline void get_decrypt_key(char *passwd, AES_KEY *key) -{ - unsigned char user_key[USER_KEY_LEN]; - gen_key(passwd, user_key, USER_KEY_LEN); - AES_set_decrypt_key(user_key, AES_KEY_LEN, key); -} - -static int gen_random_blob(unsigned char *key, int size) -{ - int ret = 0; - int fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) return -1; - if (read(fd, key, size) != size) ret = -1; - close(fd); - return ret; -} - -static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob, - const char *keyfile) -{ - int size, fd, ret = -1; - unsigned char enc_blob[MAX_BLOB_LEN]; - char tmpfile[KEYFILE_LEN]; - - if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) { - LOGE("keyfile name is too long or null"); - return -1; - } - strcpy(tmpfile, keyfile); - strcat(tmpfile, ".tmp"); - - // prepare the blob - if (IV_LEN > USER_KEY_LEN) { - LOGE("iv length is too long."); - return -1; - } - memcpy(blob->iv, iv, IV_LEN); - blob->blob_size = get_blob_size(blob); - if (blob->blob_size > MAX_BLOB_LEN) { - LOGE("blob data size is too large."); - return -1; - } - memcpy(enc_blob, blob->blob, blob->blob_size); - AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob, - blob->blob_size, enc_key, iv, AES_ENCRYPT); - // write to keyfile - size = data_blob_size(blob); - if ((fd = open(tmpfile, O_CREAT|O_RDWR)) == -1) return -1; - if (write(fd, blob, size) == size) ret = 0; - close(fd); - if (!ret) { - unlink(keyfile); - rename(tmpfile, keyfile); - chmod(keyfile, 0440); - } - return ret; -} - -static int load_n_decrypt(const char *keyname, const char *keyfile, - AES_KEY *key, DATA_BLOB *blob) -{ - int fd, ret = -1; - if ((fd = open(keyfile, O_RDONLY)) == -1) return -1; - // get the encrypted blob and iv - if ((read(fd, blob->iv, sizeof(blob->iv)) != sizeof(blob->iv)) || - (read(fd, &blob->blob_size, sizeof(uint32_t)) != sizeof(uint32_t)) || - (blob->blob_size > MAX_BLOB_LEN)) { - goto err; - } else { - unsigned char enc_blob[MAX_BLOB_LEN]; - if (read(fd, enc_blob, blob->blob_size) != - (int) blob->blob_size) goto err; - // decrypt the blob - AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char*)blob->blob, - blob->blob_size, key, blob->iv, AES_DECRYPT); - if (strcmp(keyname, (char*)blob->keyname) == 0) ret = 0; - } -err: - close(fd); - return ret; -} - -static int store_master_key(char *upasswd, unsigned char *master_key) -{ - AES_KEY key; - DATA_BLOB blob; - - // prepare the blob - if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1; - strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN); - blob.value_size = USER_KEY_LEN; - if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) { - LOGE("master_key length is too long."); - return -1; - } - memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN); - - // generate the encryption key - get_encrypt_key(upasswd, &key); - return encrypt_n_save(&key, &blob, MASTER_KEY); -} - -static int get_master_key(char *upasswd, unsigned char *master_key) -{ - AES_KEY key; - int size, ret = 0; - DATA_BLOB blob; - - get_decrypt_key(upasswd, &key); - ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob); - if (blob.value_size > USER_KEY_LEN) { - LOGE("the blob's value size is too large"); - return -1; - } - if (!ret) memcpy(master_key, blob.value, blob.value_size); - return ret; -} - -static int create_master_key(char *upasswd) -{ - int ret; - unsigned char mpasswd[AES_KEY_LEN]; - unsigned char master_key[USER_KEY_LEN]; - - gen_random_blob(mpasswd, AES_KEY_LEN); - gen_key((char*)mpasswd, master_key, USER_KEY_LEN); - if ((ret = store_master_key(upasswd, master_key)) == 0) { - unlock_keystore(master_key); - } - memset(master_key, 0, USER_KEY_LEN); - memset(mpasswd, 0, AES_KEY_LEN); - - return ret; -} - -int change_passwd(char *old_pass, char *new_pass) -{ - unsigned char master_key[USER_KEY_LEN]; - int ret; - - if (state == UNINITIALIZED) return -1; - if ((strlen(old_pass) < MIN_PASSWD_LENGTH) || - (strlen(new_pass) < MIN_PASSWD_LENGTH)) return -1; - - if ((ret = get_master_key(old_pass, master_key)) == 0) { - ret = store_master_key(new_pass, master_key); - retry_count = 0; - } else { - ret = MAX_RETRY_COUNT - ++retry_count; - if (ret == 0) { - retry_count = 0; - LOGE("passwd:reach max retry count, reset the keystore now."); - reset_keystore(); - return -1; - } - - } - return ret; -} - -int remove_key(const char *namespace, const char *keyname) -{ - char keyfile[KEYFILE_LEN]; - - if (state != UNLOCKED) return -state; - if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || - (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { - LOGE("keyname is too long."); - return -1; - } - sprintf(keyfile, KEYFILE_NAME, namespace, keyname); - return unlink(keyfile); -} - -int put_key(const char *namespace, const char *keyname, - unsigned char *data, int size) -{ - DATA_BLOB blob; - uint32_t real_size; - char keyfile[KEYFILE_LEN]; - - if (state != UNLOCKED) { - LOGE("Can not store key with current state %d\n", state); - return -state; - } - if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || - (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { - LOGE("keyname is too long."); - return -1; - } - sprintf(keyfile, KEYFILE_NAME, namespace, keyname); - strcpy(blob.keyname, keyname); - blob.value_size = size; - if (size > MAX_KEY_VALUE_LENGTH) { - LOGE("the data size is too large."); - return -1; - } - memcpy(blob.value, data, size); - return encrypt_n_save(&encryptKey, &blob, keyfile); -} - -int get_key(const char *namespace, const char *keyname, - unsigned char *data, int *size) -{ - int ret; - DATA_BLOB blob; - uint32_t blob_size; - char keyfile[KEYFILE_LEN]; - - if (state != UNLOCKED) { - LOGE("Can not retrieve key value with current state %d\n", state); - return -state; - } - if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || - (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { - LOGE("keyname is too long."); - return -1; - } - sprintf(keyfile, KEYFILE_NAME, namespace, keyname); - ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob); - if (!ret) { - if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) { - LOGE("blob value size is too large."); - ret = -1; - } else { - *size = blob.value_size; - memcpy(data, blob.value, *size); - } - } - return ret; -} - -int list_keys(const char *namespace, char reply[BUFFER_MAX]) -{ - DIR *d; - struct dirent *de; - - if (state != UNLOCKED) { - LOGE("Can not list key with current state %d\n", state); - return -1; - } - - if (!namespace || ((d = opendir("."))) == NULL) { - LOGE("cannot open keystore dir or namespace is null\n"); - return -1; - } - - if (strlen(namespace) >= MAX_KEY_NAME_LENGTH) { - LOGE("namespace is too long."); - return -1; - } - - reply[0] = 0; - while ((de = readdir(d))) { - char *prefix, *name, *keyfile = de->d_name; - char *context = NULL; - - if (de->d_type != DT_REG) continue; - if ((prefix = strtok_r(keyfile, NAME_DELIMITER, &context)) - == NULL) continue; - if (strcmp(prefix, namespace)) continue; - if ((name = strtok_r(NULL, NAME_DELIMITER, &context)) == NULL) continue; - // append the key name into reply - if (reply[0] != 0) strlcat(reply, " ", BUFFER_MAX); - if (strlcat(reply, name, BUFFER_MAX) >= BUFFER_MAX) { - LOGE("too many files under keystore directory\n"); - return -1; - } - } - closedir(d); - return 0; -} - -int new_passwd(char *password) -{ - int passwdlen = strlen(password); - - if ((state != UNINITIALIZED) || (passwdlen < MIN_PASSWD_LENGTH)) return -1; - return create_master_key(password); -} - -int lock() -{ - switch(state) { - case UNLOCKED: - lock_keystore(); - case LOCKED: - return 0; - default: - return -1; - } -} - -int unlock(char *passwd) -{ - unsigned char master_key[USER_KEY_LEN]; - int ret = get_master_key(passwd, master_key); - if (!ret) { - unlock_keystore(master_key); - retry_count = 0; - } else { - ret = MAX_RETRY_COUNT - ++retry_count; - if (ret == 0) { - retry_count = 0; - LOGE("unlock:reach max retry count, reset the keystore now."); - reset_keystore(); - return -1; - } - } - return ret; -} - -KEYSTORE_STATE get_state() -{ - return state; -} - -int reset_keystore() -{ - int ret = 0; - DIR *d; - struct dirent *de; - - if ((d = opendir(".")) == NULL) { - LOGE("cannot open keystore dir\n"); - return -1; - } - while ((de = readdir(d))) { - char *dirname = de->d_name; - if (strcmp(".", dirname) == 0) continue; - if (strcmp("..", dirname) == 0) continue; - if (unlink(dirname) != 0) ret = -1; - } - closedir(d); - state = UNINITIALIZED; - if (ret == 0) { - LOGI("keystore is reset."); - } else { - LOGI("keystore can not be cleaned up entirely."); - } - return ret; -} - -int init_keystore(const char *dir) -{ - int fd; - - if (dir) mkdir(dir, 0770); - if (!dir || chdir(dir)) { - LOGE("Can not open/create the keystore directory %s\n", - dir ? dir : "(null)"); - return -1; - } - gen_random_blob(iv, IV_LEN); - if ((fd = open(MASTER_KEY, O_RDONLY)) == -1) { - state = UNINITIALIZED; - return 0; - } - close(fd); - state = LOCKED; - return 0; -} diff --git a/cmds/keystore/keymgmt.h b/cmds/keystore/keymgmt.h deleted file mode 100644 index 116d7a3..0000000 --- a/cmds/keystore/keymgmt.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -** Copyright 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 __KEYMGMT_H__ -#define __KEYMGMT_H__ - -#define MASTER_KEY_TAG "master_key" -#define MASTER_KEY ".keymaster" -#define MAX_PATH_LEN 128 -#define SALT "Android Keystore 0.1" -#define NAME_DELIMITER "_" -#define KEYFILE_NAME "%s"NAME_DELIMITER"%s" -#define KEYGEN_ITER 1024 -#define AES_KEY_LEN 128 -#define USER_KEY_LEN (AES_KEY_LEN/8) -#define IV_LEN USER_KEY_LEN -#define MAX_RETRY_COUNT 6 -#define MIN_PASSWD_LENGTH 8 - -#define gen_key(passwd, key, len) \ - PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), \ - (unsigned char*)SALT, \ - strlen(SALT), KEYGEN_ITER, \ - len, key) - -#define KEYFILE_LEN MAX_NAMESPACE_LENGTH + MAX_KEY_NAME_LENGTH + 6 - -#define get_blob_size(blob) \ - (((blob->value_size + sizeof(uint32_t) + MAX_KEY_NAME_LENGTH \ - + USER_KEY_LEN - 1) / USER_KEY_LEN) * USER_KEY_LEN) - -#define MAX_BLOB_LEN ((MAX_KEY_VALUE_LENGTH + MAX_KEY_NAME_LENGTH + \ - sizeof(uint32_t) + USER_KEY_LEN - 1) / USER_KEY_LEN)\ - * USER_KEY_LEN - -#define data_blob_size(blob) USER_KEY_LEN + sizeof(uint32_t) + blob->blob_size - -typedef struct { - unsigned char iv[USER_KEY_LEN]; - uint32_t blob_size; - union { - unsigned char blob[1]; - struct { - uint32_t value_size; - char keyname[MAX_KEY_NAME_LENGTH]; - unsigned char value[MAX_KEY_VALUE_LENGTH]; - } __attribute__((packed)); - }; -} DATA_BLOB; - -typedef struct { - char tag[USER_KEY_LEN]; - unsigned char master_key[USER_KEY_LEN]; -} MASTER_BLOB; - -int put_key(const char *namespace, const char *keyname, - unsigned char *data, int size); -int get_key(const char *namespace, const char *keyname, - unsigned char *data, int *size); -int remove_key(const char *namespace, const char *keyname); -int list_keys(const char *namespace, char reply[BUFFER_MAX]); -int new_passwd(char *password); -int change_passwd(char *old_pass, char *new_pass); -int lock(); -int unlock(char *passwd); -KEYSTORE_STATE get_state(); -int reset_keystore(); -int init_keystore(const char *dir); - -#endif diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c deleted file mode 100644 index 87fdc80..0000000 --- a/cmds/keystore/netkeystore.c +++ /dev/null @@ -1,429 +0,0 @@ -/* -** Copyright 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 <stdlib.h> -#include <sys/stat.h> -#include <dirent.h> -#include <unistd.h> -#include <ctype.h> -#include <fcntl.h> -#include <errno.h> -#include <utime.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <private/android_filesystem_config.h> - -#include <cutils/sockets.h> -#include <cutils/log.h> -#include <cutils/properties.h> - -#include "netkeystore.h" -#include "keymgmt.h" - -#define DBG 1 -#define CMD_PUT_WITH_FILE "putfile" - -typedef void CMD_FUNC(LPC_MARSHAL *cmd, LPC_MARSHAL *reply); - -struct cmdinfo { - const char *name; - CMD_FUNC *func; -}; - -static CMD_FUNC do_lock; -static CMD_FUNC do_unlock; -static CMD_FUNC do_passwd; -static CMD_FUNC do_get_state;; -static CMD_FUNC do_listkeys; -static CMD_FUNC do_get_key; -static CMD_FUNC do_put_key; -static CMD_FUNC do_remove_key; -static CMD_FUNC do_reset_keystore; - -#define str(x) #x - -struct cmdinfo cmds[] = { - { str(LOCK), do_lock }, - { str(UNLOCK), do_unlock }, - { str(PASSWD), do_passwd }, - { str(GETSTATE), do_get_state }, - { str(LISTKEYS), do_listkeys }, - { str(GET), do_get_key }, - { str(PUT), do_put_key }, - { str(REMOVE), do_remove_key }, - { str(RESET), do_reset_keystore }, -}; - -static struct ucred cr; - -static int check_get_perm(int uid) -{ - if (uid == AID_WIFI || uid == AID_VPN) return 0; - return -1; -} - -static int check_reset_perm(int uid) -{ - if (uid == AID_SYSTEM) return 0; - return -1; -} - -/** - * The function parse_strings() only handle two or three tokens just for - * keystore's need. - */ -static int parse_strings(char *data, int data_len, int ntokens, ...) -{ - int count = 0; - va_list args; - char *p = data, **q; - - va_start(args, ntokens); - q = va_arg(args, char**); - *q = p; - while (p < (data + data_len)) { - if (*(p++) == 0) { - if (++count == ntokens) break; - if ((q = va_arg(args, char**)) == NULL) break; - *q = p; - } - } - va_end(args); - // the first two strings should be null-terminated and the third could - // ignore the delimiter. - if (count >= 2) { - if ((ntokens == 3) || ((ntokens == 2) && (p == (data + data_len)))) { - return 0; - } - } - return -1; -} - -static int is_alnum_string(char *s) -{ - char *s0 = s; - while (*s != 0) { - if (!isalnum(*s++)) { - LOGE("The string '%s' is not an alphanumeric string\n", s0); - return 0; - } - } - return 1; -} - -// args of passwd(): -// firstPassword - for the first time -// oldPassword newPassword - for changing the password -static void do_passwd(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - char *p1 = NULL, *p2 = NULL; - - if (strlen((char*)cmd->data) == (cmd->len - 1)) { - reply->retcode = new_passwd((char*)cmd->data); - } else { - if (parse_strings((char *)cmd->data, cmd->len, 2, &p1, &p2) != 0) { - reply->retcode = -1; - } else { - reply->retcode = change_passwd(p1, p2); - } - } -} - -// args of lock(): -// no argument -static void do_lock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = lock(); -} - -// args of unlock(): -// password -static void do_unlock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = unlock((char*)cmd->data); -} - -// args of get_state(): -// no argument -static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - int s = get_state(); - if (DBG) LOGD("keystore state = %d\n", s); - reply->retcode = s; -} - -// args of listkeys(): -// namespace -static void do_listkeys(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = list_keys((const char*)cmd->data, (char*)reply->data); - if (!reply->retcode) reply->len = strlen((char*)reply->data); -} - -// args of get(): -// namespace keyname -static void do_get_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - char *namespace = NULL, *keyname = NULL; - - if (check_get_perm(cr.uid)) { - LOGE("uid %d doesn't have the permission to get key value\n", cr.uid); - reply->retcode = -1; - return; - } - - if (parse_strings((char*)cmd->data, cmd->len, 2, &namespace, &keyname) || - !is_alnum_string(namespace) || !is_alnum_string(keyname)) { - reply->retcode = -1; - } else { - reply->retcode = get_key(namespace, keyname, reply->data, - (int*)&reply->len); - } -} - -static int get_value_index(LPC_MARSHAL *cmd) -{ - uint32_t count = 0, i; - for (i = 0 ; i < cmd->len ; ++i) { - if (cmd->data[i] == ' ') { - if (++count == 2) return ++i; - } - } - return -1; -} - -// args of put(): -// namespace keyname keyvalue -static void do_put_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - char *namespace = NULL, *keyname = NULL; - char *value = NULL; - - if (parse_strings((char*)cmd->data, cmd->len, 3, &namespace, &keyname, &value) || - !is_alnum_string(namespace) || !is_alnum_string(keyname)) { - reply->retcode = -1; - return; - } - int len = cmd->len - (value - namespace); - reply->retcode = put_key(namespace, keyname, (unsigned char *)value, len); -} - -// args of remove_key(): -// namespace keyname -static void do_remove_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - char *namespace = NULL, *keyname = NULL; - - if (parse_strings((char*)cmd->data, cmd->len, 2, &namespace, &keyname) || - !is_alnum_string(namespace) || !is_alnum_string(keyname)) { - reply->retcode = -1; - return; - } - reply->retcode = remove_key(namespace, keyname); -} - -// args of reset_keystore(): -// no argument -static void do_reset_keystore(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - if (check_reset_perm(cr.uid)) { - LOGE("uid %d doesn't have the permission to reset the keystore\n", - cr.uid); - reply->retcode = -1; - return; - } - reply->retcode = reset_keystore(); -} - -void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - uint32_t cmd_max = sizeof(cmds)/sizeof(struct cmdinfo); - - if (cmd->opcode >= cmd_max) { - LOGE("the opcode (%d) is not valid", cmd->opcode); - reply->retcode = -1; - return; - } - cmds[cmd->opcode].func(cmd, reply); -} - -static int set_read_timeout(int socket) -{ - struct timeval tv; - tv.tv_sec = READ_TIMEOUT; - tv.tv_usec = 0; - if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv)) - { - LOGE("setsockopt failed"); - return -1; - } - return 0; -} - -static int append_input_from_file(const char *filename, LPC_MARSHAL *cmd) -{ - int fd, len, ret = 0; - - // get opcode of the function put() - if ((fd = open(filename, O_RDONLY)) == -1) { - fprintf(stderr, "Can not open file %s\n", filename); - return -1; - } - len = read(fd, cmd->data + cmd->len, BUFFER_MAX - cmd->len); - if (len < 0 || (len == (int)(BUFFER_MAX - cmd->len))) { - ret = -1; - } else { - cmd->len += len; - } - close(fd); - return ret; -} - -static int flatten_str_args(int argc, const char **argv, LPC_MARSHAL *cmd) -{ - int i, len = 0; - char *buf = (char*)cmd->data; - buf[0] = 0; - for (i = 0 ; i < argc ; ++i) { - // we also include the \0 character in the input. - if (i == 0) { - len = (strlcpy(buf, argv[i], BUFFER_MAX) + 1); - } else { - len += (snprintf(buf + len, BUFFER_MAX - len, "%s", argv[i]) + 1); - } - if (len >= BUFFER_MAX) return -1; - } - if (len) cmd->len = len ; - return 0; -} - -int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd) -{ - uint32_t i, len = 0; - uint32_t cmd_max = sizeof(cmds)/sizeof(cmds[0]); - - for (i = 0 ; i < cmd_max ; ++i) { - if (!strcasecmp(argv[0], cmds[i].name)) break; - } - - if (i == cmd_max) { - // check if this is a command to put the key value with a file. - if (strcmp(argv[0], CMD_PUT_WITH_FILE) != 0) return -1; - cmd->opcode = PUT; - if (argc != 4) { - fprintf(stderr, "%s args\n\tnamespace keyname filename\n", - argv[0]); - return -1; - } - if (flatten_str_args(argc - 2, argv + 1, cmd)) return -1; - return append_input_from_file(argv[3], cmd); - } else { - cmd->opcode = i; - return flatten_str_args(argc - 1, argv + 1, cmd); - } -} - -int shell_command(const int argc, const char **argv) -{ - int fd, i; - LPC_MARSHAL cmd; - - if (parse_cmd(argc, argv, &cmd)) { - fprintf(stderr, "Incorrect command or command line is too long.\n"); - return -1; - } - fd = socket_local_client(SOCKET_PATH, - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (fd == -1) { - fprintf(stderr, "Keystore service is not up and running.\n"); - return -1; - } - - if (write_marshal(fd, &cmd)) { - fprintf(stderr, "Incorrect command or command line is too long.\n"); - return -1; - } - if (read_marshal(fd, &cmd)) { - fprintf(stderr, "Failed to read the result.\n"); - return -1; - } - cmd.data[cmd.len] = 0; - fprintf(stdout, "%s\n", (cmd.retcode == 0) ? "Succeeded!" : "Failed!"); - if (cmd.len) fprintf(stdout, "\t%s\n", (char*)cmd.data); - close(fd); - return 0; -} - -int server_main(const int argc, const char *argv[]) -{ - struct sockaddr addr; - socklen_t alen; - int lsocket, s; - LPC_MARSHAL cmd, reply; - - if (init_keystore(KEYSTORE_DIR)) { - LOGE("Can not initialize the keystore, the directory exist?\n"); - return -1; - } - - lsocket = android_get_control_socket(SOCKET_PATH); - if (lsocket < 0) { - LOGE("Failed to get socket from environment: %s\n", strerror(errno)); - return -1; - } - if (listen(lsocket, 5)) { - LOGE("Listen on socket failed: %s\n", strerror(errno)); - return -1; - } - fcntl(lsocket, F_SETFD, FD_CLOEXEC); - memset(&reply, 0, sizeof(LPC_MARSHAL)); - - for (;;) { - socklen_t cr_size = sizeof(cr); - alen = sizeof(addr); - s = accept(lsocket, &addr, &alen); - - /* retrieve the caller info here */ - if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { - close(s); - LOGE("Unable to recieve socket options\n"); - continue; - } - - if (s < 0) { - LOGE("Accept failed: %s\n", strerror(errno)); - continue; - } - fcntl(s, F_SETFD, FD_CLOEXEC); - if (set_read_timeout(s)) { - close(s); - continue; - } - - // read the command, execute and send the result back. - if(read_marshal(s, &cmd)) goto err; - execute(&cmd, &reply); - write_marshal(s, &reply); -err: - memset(&reply, 0, sizeof(LPC_MARSHAL)); - close(s); - } - - return 0; -} diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h deleted file mode 100644 index e2ffd8b..0000000 --- a/cmds/keystore/netkeystore.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -** -** Copyright 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 __NETKEYSTORE_H__ -#define __NETKEYSTORE_H__ - -#include <stdio.h> -#include <arpa/inet.h> -#include <cutils/sockets.h> -#include <cutils/log.h> - -#include "common.h" - -// for testing -int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd); -void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply); - -static inline int readx(int s, void *_buf, int count) -{ - char *buf = _buf; - int n = 0, r; - if (count < 0) return -1; - while (n < count) { - r = read(s, buf + n, count - n); - if (r < 0) { - if (errno == EINTR) continue; - LOGE("read error: %s\n", strerror(errno)); - return -1; - } - if (r == 0) { - LOGE("eof\n"); - return -1; /* EOF */ - } - n += r; - } - return 0; -} - -static inline int writex(int s, const void *_buf, int count) -{ - const char *buf = _buf; - int n = 0, r; - if (count < 0) return -1; - while (n < count) { - r = write(s, buf + n, count - n); - if (r < 0) { - if (errno == EINTR) continue; - LOGE("write error: %s\n", strerror(errno)); - return -1; - } - n += r; - } - return 0; -} - -static inline int read_marshal(int s, LPC_MARSHAL *cmd) -{ - if (readx(s, cmd, 2 * sizeof(uint32_t))) { - LOGE("failed to read header\n"); - return -1; - } - cmd->len = ntohl(cmd->len); - cmd->opcode = ntohl(cmd->opcode); - if (cmd->len > BUFFER_MAX) { - LOGE("invalid size %d\n", cmd->len); - return -1; - } - if (readx(s, cmd->data, cmd->len)) { - LOGE("failed to read data\n"); - return -1; - } - cmd->data[cmd->len] = 0; - return 0; -} - -static inline int write_marshal(int s, LPC_MARSHAL *cmd) -{ - int len = cmd->len; - cmd->len = htonl(cmd->len); - cmd->opcode = htonl(cmd->opcode); - if (writex(s, cmd, 2 * sizeof(uint32_t))) { - LOGE("failed to write marshal header\n"); - return -1; - } - if (writex(s, cmd->data, len)) { - LOGE("failed to write marshal data\n"); - return -1; - } - return 0; -} - -#endif diff --git a/cmds/keystore/netkeystore_main.c b/cmds/keystore/netkeystore_main.c deleted file mode 100644 index 606e67a..0000000 --- a/cmds/keystore/netkeystore_main.c +++ /dev/null @@ -1,29 +0,0 @@ -/* -** Copyright 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 "keystore" - -int shell_command(const int argc, const char **argv); -int server_main(const int argc, const char *argv[]); - -int main(const int argc, const char *argv[]) -{ - if (argc > 1) { - return shell_command(argc - 1, argv + 1); - } else { - return server_main(argc, argv); - } -} diff --git a/cmds/keystore/tests/Android.mk b/cmds/keystore/tests/Android.mk deleted file mode 100644 index e0a776a..0000000 --- a/cmds/keystore/tests/Android.mk +++ /dev/null @@ -1,28 +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. -# -# define the KEYSTORE_TESTS environment variable to build the test programs -ifdef KEYSTORE_TESTS -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c ../netkeystore.c -LOCAL_SHARED_LIBRARIES := libcutils libssl -LOCAL_MODULE:= netkeystore_test -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := external/openssl/include \ - frameworks/base/cmds/keystore -EXTRA_CFLAGS := -g -O0 -DGTEST_OS_LINUX -DGTEST_HAS_STD_STRING -include $(BUILD_EXECUTABLE) - -endif #KEYSTORE_TESTS diff --git a/cmds/keystore/tests/netkeystore_test.c b/cmds/keystore/tests/netkeystore_test.c deleted file mode 100644 index ce79503..0000000 --- a/cmds/keystore/tests/netkeystore_test.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <cutils/log.h> - -#include "common.h" -#include "keymgmt.h" -#include "netkeystore.h" - -#define LOG_TAG "keystore_test" - -typedef int FUNC_PTR(); -typedef struct { - const char *name; - FUNC_PTR *func; -} TESTFUNC; - -#define FUNC_NAME(x) { #x, test_##x } -#define FUNC_BODY(x) int test_##x() - -#define TEST_PASSWD "12345678" -#define TEST_NPASSWD "hello world" -#define TEST_DIR "/data/local/tmp/keystore" -#define READONLY_DIR "/proc/keystore" -#define TEST_NAMESPACE "test" -#define TEST_KEYNAME "key" -#define TEST_KEYNAME2 "key2" -#define TEST_KEYVALUE "ANDROID" - -void setup() -{ - if (init_keystore(TEST_DIR) != 0) { - fprintf(stderr, "Can not create the test directory %s\n", TEST_DIR); - exit(-1); - } -} - -void teardown() -{ - if (reset_keystore() != 0) { - fprintf(stderr, "Can not reset the test directory %s\n", TEST_DIR); - } - rmdir(TEST_DIR); -} - -FUNC_BODY(init_keystore) -{ - if (init_keystore(READONLY_DIR) == 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(reset_keystore) -{ - int ret = chdir("/proc"); - if (reset_keystore() == 0) return -1; - chdir(TEST_DIR); - return EXIT_SUCCESS; -} - -FUNC_BODY(get_state) -{ - if (get_state() != UNINITIALIZED) return -1; - new_passwd(TEST_PASSWD); - if (get_state() != UNLOCKED) return -1; - lock(); - if (get_state() != LOCKED) return -1; - - if (reset_keystore() != 0) return -1; - if (get_state() != UNINITIALIZED) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(passwd) -{ - char buf[512]; - - if (new_passwd("2d fsdf") == 0) return -1; - if (new_passwd("dsfsdf") == 0) return -1; - new_passwd(TEST_PASSWD); - lock(); - if (unlock("55555555") == 0) return -1; - if (unlock(TEST_PASSWD) != 0) return -1; - - // change the password - if (change_passwd("klfdjdsklfjg", "abcdefghi") == 0) return -1; - - if (change_passwd(TEST_PASSWD, TEST_NPASSWD) != 0) return -1; - lock(); - - if (unlock(TEST_PASSWD) == 0) return -1; - if (unlock(TEST_NPASSWD) != 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(lock) -{ - if (lock() == 0) return -1; - new_passwd(TEST_PASSWD); - if (lock() != 0) return -1; - if (lock() != 0) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(unlock) -{ - int i = MAX_RETRY_COUNT; - new_passwd(TEST_PASSWD); - lock(); - while (i > 1) { - if (unlock(TEST_NPASSWD) != --i) return -1; - } - if (unlock(TEST_NPASSWD) != -1) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(put_key) -{ - int i = 0; - char keyname[512]; - - if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)) == 0) return -1; - new_passwd(TEST_PASSWD); - if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)) != 0) return -1; - - for(i = 0; i < 500; i++) keyname[i] = 'K'; - keyname[i] = 0; - if (put_key(TEST_NAMESPACE, keyname, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)) == 0) return -1; - if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - MAX_KEY_VALUE_LENGTH + 1) == 0) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(get_key) -{ - int size; - unsigned char data[MAX_KEY_VALUE_LENGTH]; - - if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) == 0) return -1; - - new_passwd(TEST_PASSWD); - put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) != 0) return -1; - if (memcmp(data, TEST_KEYVALUE, size) != 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(remove_key) -{ - if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1; - - new_passwd(TEST_PASSWD); - if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1; - - put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) != 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(list_keys) -{ - int i; - char buf[128]; - char reply[BUFFER_MAX]; - - for(i = 0; i < 100; i++) buf[i] = 'K'; - buf[i] = 0; - - if (list_keys(TEST_NAMESPACE, reply) == 0) return -1; - - new_passwd(TEST_PASSWD); - if (list_keys(buf, reply) == 0) return -1; - - if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; - if (strcmp(reply, "") != 0) return -1; - - put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; - if (strcmp(reply, TEST_KEYNAME) != 0) return -1; - - put_key(TEST_NAMESPACE, TEST_KEYNAME2, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - - if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; - sprintf(buf, "%s %s", TEST_KEYNAME2, TEST_KEYNAME); - if (strcmp(reply, buf) != 0) return -1; - - return EXIT_SUCCESS; -} - -static int execute_cmd(int argc, const char *argv[], LPC_MARSHAL *cmd, - LPC_MARSHAL *reply) -{ - memset(cmd, 0, sizeof(LPC_MARSHAL)); - memset(reply, 0, sizeof(LPC_MARSHAL)); - if (parse_cmd(argc, argv, cmd)) return -1; - execute(cmd, reply); - return (reply->retcode ? -1 : 0); -} - -FUNC_BODY(client_passwd) -{ - LPC_MARSHAL cmd, reply; - const char *set_passwd_cmds[2] = {"passwd", TEST_PASSWD}; - const char *change_passwd_cmds[3] = {"passwd", TEST_PASSWD, TEST_NPASSWD}; - - if (execute_cmd(2, set_passwd_cmds, &cmd, &reply)) return -1; - - lock(); - if (unlock("55555555") == 0) return -1; - if (unlock(TEST_PASSWD) != 0) return -1; - - if (execute_cmd(3, change_passwd_cmds, &cmd, &reply)) return -1; - - lock(); - if (unlock(TEST_PASSWD) == 0) return -1; - if (unlock(TEST_NPASSWD) != 0) return -1; - - return EXIT_SUCCESS; -} - -TESTFUNC all_tests[] = { - FUNC_NAME(init_keystore), - FUNC_NAME(reset_keystore), - FUNC_NAME(get_state), - FUNC_NAME(passwd), - FUNC_NAME(lock), - FUNC_NAME(unlock), - FUNC_NAME(put_key), - FUNC_NAME(get_key), - FUNC_NAME(remove_key), - FUNC_NAME(list_keys), - FUNC_NAME(client_passwd), -}; - -int main(int argc, char **argv) { - int i, ret; - for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) { - LOGD("run %s...\n", all_tests[i].name); - setup(); - if ((ret = all_tests[i].func()) != EXIT_SUCCESS) { - fprintf(stderr, "ERROR in function %s\n", all_tests[i].name); - return ret; - } else { - fprintf(stderr, "function %s PASSED!\n", all_tests[i].name); - } - teardown(); - } - return EXIT_SUCCESS; -} diff --git a/include/ui/SurfaceComposerClient.h b/include/ui/SurfaceComposerClient.h index 269959c..8701928 100644 --- a/include/ui/SurfaceComposerClient.h +++ b/include/ui/SurfaceComposerClient.h @@ -20,6 +20,8 @@ #include <stdint.h> #include <sys/types.h> +#include <binder/IBinder.h> + #include <utils/SortedVector.h> #include <utils/RefBase.h> #include <utils/threads.h> @@ -106,6 +108,8 @@ public: static ssize_t getDisplayHeight(DisplayID dpy); static ssize_t getDisplayOrientation(DisplayID dpy); + status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient, + void* cookie = NULL, uint32_t flags = 0); private: friend class Surface; diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp index 7bdf885..8a7abec 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -160,7 +160,7 @@ void DisplayHardware::init(uint32_t dpy) if (mNativeWindow->isUpdateOnDemand()) { - mFlags |= UPDATE_ON_DEMAND; + mFlags |= PARTIAL_UPDATES; } if (eglGetConfigAttrib(display, config, EGL_CONFIG_CAVEAT, &dummy) == EGL_TRUE) { @@ -174,9 +174,9 @@ void DisplayHardware::init(uint32_t dpy) surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL); - if (mFlags & UPDATE_ON_DEMAND) { - // if we have update on demand, we definitely don't need to - // preserve the backbuffer, which is usually costly. + if (mFlags & PARTIAL_UPDATES) { + // if we have partial updates, we definitely don't need to + // preserve the backbuffer, which may be costly. eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); } @@ -199,9 +199,9 @@ void DisplayHardware::init(uint32_t dpy) mFlags |= SWAP_RECTANGLE; } } - // when we have the choice between UPDATE_ON_DEMAND and SWAP_RECTANGLE - // choose UPDATE_ON_DEMAND, which is more efficient - if (mFlags & UPDATE_ON_DEMAND) + // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE + // choose PARTIAL_UPDATES, which should be more efficient + if (mFlags & PARTIAL_UPDATES) mFlags &= ~SWAP_RECTANGLE; #endif @@ -317,7 +317,7 @@ void DisplayHardware::flip(const Region& dirty) const } #endif - if (mFlags & UPDATE_ON_DEMAND) { + if (mFlags & PARTIAL_UPDATES) { mNativeWindow->setUpdateRectangle(dirty.getBounds()); } diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h index b7f1cdb..cb688b7 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -48,7 +48,7 @@ public: NPOT_EXTENSION = 0x00000100, DRAW_TEXTURE_EXTENSION = 0x00000200, BUFFER_PRESERVED = 0x00010000, - UPDATE_ON_DEMAND = 0x00020000, // video driver feature + PARTIAL_UPDATES = 0x00020000, // video driver feature SLOW_CONFIG = 0x00040000, // software SWAP_RECTANGLE = 0x00080000, }; diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp index 5ff9284..2894bf0 100644 --- a/libs/surfaceflinger/Layer.cpp +++ b/libs/surfaceflinger/Layer.cpp @@ -51,7 +51,8 @@ Layer::Layer(SurfaceFlinger* flinger, DisplayID display, const sp<Client>& c, int32_t i) : LayerBaseClient(flinger, display, c, i), mSecure(false), - mNeedsBlending(true) + mNeedsBlending(true), + mNeedsDithering(false) { // no OpenGL operation is possible here, since we might not be // in the OpenGL thread. @@ -88,6 +89,7 @@ void Layer::destroy() mBuffers[i].clear(); mWidth = mHeight = 0; } + mSurface.clear(); } sp<LayerBaseClient::Surface> Layer::createSurface() const @@ -98,18 +100,23 @@ sp<LayerBaseClient::Surface> Layer::createSurface() const status_t Layer::ditch() { // the layer is not on screen anymore. free as much resources as possible - //destroy(); - mSurface.clear(); + destroy(); return NO_ERROR; } status_t Layer::setBuffers( uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) { + // this surfaces pixel format PixelFormatInfo info; status_t err = getPixelFormatInfo(format, &info); if (err) return err; + // the display's pixel format + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + PixelFormatInfo displayInfo; + getPixelFormatInfo(hw.getFormat(), &displayInfo); + uint32_t bufferFlags = 0; if (flags & ISurfaceComposer::eSecure) bufferFlags |= Buffer::SECURE; @@ -119,6 +126,12 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h, mHeight = h; mSecure = (bufferFlags & Buffer::SECURE) ? true : false; mNeedsBlending = (info.h_alpha - info.l_alpha) > 0; + + // we use the red index + int displayRedSize = displayInfo.getSize(PixelFormatInfo::INDEX_RED); + int layerRedsize = info.getSize(PixelFormatInfo::INDEX_RED); + mNeedsDithering = layerRedsize > displayRedSize; + mBufferFlags = bufferFlags; for (size_t i=0 ; i<NUM_BUFFERS ; i++) { mBuffers[i] = new Buffer(); @@ -210,14 +223,12 @@ void Layer::onDraw(const Region& clip) const mFrontBufferIndex : 0; GLuint textureName = mTextures[index].name; if (UNLIKELY(textureName == -1LU)) { - //LOGW("Layer %p doesn't have a texture", this); // the texture has not been created yet, this Layer has // in fact never been drawn into. this happens frequently with // SurfaceView. clearWithOpenGL(clip); return; } - drawWithOpenGL(clip, mTextures[index]); } diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h index 2e8173d..6c7b27b 100644 --- a/libs/surfaceflinger/Layer.h +++ b/libs/surfaceflinger/Layer.h @@ -68,6 +68,7 @@ public: virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion); virtual void finishPageFlip(); virtual bool needsBlending() const { return mNeedsBlending; } + virtual bool needsDithering() const { return mNeedsDithering; } virtual bool isSecure() const { return mSecure; } virtual sp<Surface> createSurface() const; virtual status_t ditch(); @@ -109,6 +110,7 @@ private: bool mSecure; int32_t mFrontBufferIndex; bool mNeedsBlending; + bool mNeedsDithering; Region mPostedDirtyRegion; sp<FreezeLock> mFreezeLock; PixelFormat mFormat; diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp index e08861d..a351253 100644 --- a/libs/surfaceflinger/LayerBase.cpp +++ b/libs/surfaceflinger/LayerBase.cpp @@ -56,6 +56,7 @@ LayerBase::LayerBase(SurfaceFlinger* flinger, DisplayID display) : dpy(display), contentDirty(false), mFlinger(flinger), mTransformed(false), + mUseLinearFiltering(false), mOrientation(0), mTransactionFlags(0), mPremultipliedAlpha(true), @@ -208,7 +209,19 @@ uint32_t LayerBase::doTransaction(uint32_t flags) flags |= eVisibleRegion; this->contentDirty = true; } - + + if (temp.sequence != front.sequence) { + const bool linearFiltering = mUseLinearFiltering; + mUseLinearFiltering = false; + if (!(mFlags & DisplayHardware::SLOW_CONFIG)) { + // we may use linear filtering, if the matrix scales us + const uint8_t type = temp.transform.getType(); + if (!temp.transform.preserveRects() || (type >= Transform::SCALE)) { + mUseLinearFiltering = true; + } + } + } + // Commit the transaction commitTransaction(flags & eRestartTransaction); return flags; @@ -332,13 +345,8 @@ GLuint LayerBase::createTexture() const glBindTexture(GL_TEXTURE_2D, textureName); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (mFlags & DisplayHardware::SLOW_CONFIG) { - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } else { - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); return textureName; } @@ -355,15 +363,13 @@ void LayerBase::clearWithOpenGL(const Region& clip, GLclampx red, Region::const_iterator it = clip.begin(); Region::const_iterator const end = clip.end(); - if (it != end) { - glEnable(GL_SCISSOR_TEST); - glVertexPointer(2, GL_FIXED, 0, mVertices); - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } + glEnable(GL_SCISSOR_TEST); + glVertexPointer(2, GL_FIXED, 0, mVertices); + while (it != end) { + const Rect& r = *it++; + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } } @@ -385,14 +391,6 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const glEnable(GL_TEXTURE_2D); - // Dithering... - bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG); - if (fast || s.flags & ISurfaceComposer::eLayerDither) { - glEnable(GL_DITHER); - } else { - glDisable(GL_DITHER); - } - if (UNLIKELY(s.alpha < 0xFF)) { // We have an alpha-modulation. We need to modulate all // texture components by alpha because we're always using @@ -427,82 +425,63 @@ void LayerBase::drawWithOpenGL(const Region& clip, const Texture& texture) const } } + Region::const_iterator it = clip.begin(); + Region::const_iterator const end = clip.end(); if (UNLIKELY(transformed() || !(mFlags & DisplayHardware::DRAW_TEXTURE_EXTENSION) )) { //StopWatch watch("GL transformed"); - Region::const_iterator it = clip.begin(); - Region::const_iterator const end = clip.end(); - if (it != end) { - // always use high-quality filtering with fast configurations - bool fast = !(mFlags & DisplayHardware::SLOW_CONFIG); - if (!fast && s.flags & ISurfaceComposer::eLayerFilter) { - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } - const GLfixed texCoords[4][2] = { - { 0, 0 }, - { 0, 0x10000 }, - { 0x10000, 0x10000 }, - { 0x10000, 0 } - }; - - glMatrixMode(GL_TEXTURE); - glLoadIdentity(); - - // the texture's source is rotated - if (texture.transform == HAL_TRANSFORM_ROT_90) { - // TODO: handle the other orientations - glTranslatef(0, 1, 0); - glRotatef(-90, 0, 0, 1); - } - - if (!(mFlags & (DisplayHardware::NPOT_EXTENSION | - DisplayHardware::DIRECT_TEXTURE))) { - // find the smallest power-of-two that will accommodate our surface - GLuint tw = 1 << (31 - clz(width)); - GLuint th = 1 << (31 - clz(height)); - if (tw < width) tw <<= 1; - if (th < height) th <<= 1; - // this divide should be relatively fast because it's - // a power-of-two (optimized path in libgcc) - GLfloat ws = GLfloat(width) /tw; - GLfloat hs = GLfloat(height)/th; - glScalef(ws, hs, 1.0f); - } + const GLfixed texCoords[4][2] = { + { 0, 0 }, + { 0, 0x10000 }, + { 0x10000, 0x10000 }, + { 0x10000, 0 } + }; + + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + + // the texture's source is rotated + if (texture.transform == HAL_TRANSFORM_ROT_90) { + // TODO: handle the other orientations + glTranslatef(0, 1, 0); + glRotatef(-90, 0, 0, 1); + } - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glVertexPointer(2, GL_FIXED, 0, mVertices); - glTexCoordPointer(2, GL_FIXED, 0, texCoords); + if (!(mFlags & (DisplayHardware::NPOT_EXTENSION | + DisplayHardware::DIRECT_TEXTURE))) { + // find the smallest power-of-two that will accommodate our surface + GLuint tw = 1 << (31 - clz(width)); + GLuint th = 1 << (31 - clz(height)); + if (tw < width) tw <<= 1; + if (th < height) th <<= 1; + GLfloat ws = GLfloat(width) /tw; + GLfloat hs = GLfloat(height)/th; + glScalef(ws, hs, 1.0f); + } - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FIXED, 0, mVertices); + glTexCoordPointer(2, GL_FIXED, 0, texCoords); - if (!fast && s.flags & ISurfaceComposer::eLayerFilter) { - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + while (it != end) { + const Rect& r = *it++; + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } + glDisableClientState(GL_TEXTURE_COORD_ARRAY); } else { - Region::const_iterator it = clip.begin(); - Region::const_iterator const end = clip.end(); - if (it != end) { - GLint crop[4] = { 0, height, width, -height }; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); - int x = tx(); - int y = ty(); - y = fbHeight - (y + height); - while (it != end) { - const Rect& r = *it++; - const GLint sy = fbHeight - (r.top + r.height()); - glScissor(r.left, sy, r.width(), r.height()); - glDrawTexiOES(x, y, 0, width, height); - } + GLint crop[4] = { 0, height, width, -height }; + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); + int x = tx(); + int y = ty(); + y = fbHeight - (y + height); + while (it != end) { + const Rect& r = *it++; + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawTexiOES(x, y, 0, width, height); } } } @@ -512,6 +491,19 @@ void LayerBase::validateTexture(GLint textureName) const glBindTexture(GL_TEXTURE_2D, textureName); // TODO: reload the texture if needed // this is currently done in loadTexture() below + if (mUseLinearFiltering) { + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + if (needsDithering()) { + glEnable(GL_DITHER); + } else { + glDisable(GL_DITHER); + } } void LayerBase::loadTexture(Texture* texture, GLint textureName, diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h index 3a52240..233737d 100644 --- a/libs/surfaceflinger/LayerBase.h +++ b/libs/surfaceflinger/LayerBase.h @@ -188,6 +188,11 @@ public: virtual bool needsBlending() const { return false; } /** + * needsDithering - true if this surface needs dithering + */ + virtual bool needsDithering() const { return false; } + + /** * transformed -- true is this surface needs a to be transformed */ virtual bool transformed() const { return mTransformed; } @@ -254,6 +259,7 @@ protected: // cached during validateVisibility() bool mTransformed; + bool mUseLinearFiltering; int32_t mOrientation; GLfixed mVertices[4][2]; Rect mTransformedBounds; diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index 831c446..065425d 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -859,10 +859,10 @@ void SurfaceFlinger::handleRepaint() // is costly and usually involves copying the whole update back. } } else { - if (flags & DisplayHardware::UPDATE_ON_DEMAND) { + if (flags & DisplayHardware::PARTIAL_UPDATES) { // We need to redraw the rectangle that will be updated // (pushed to the framebuffer). - // This is needed because UPDATE_ON_DEMAND only takes one + // This is needed because PARTIAL_UPDATES only takes one // rectangle instead of a region (see DisplayHardware::flip()) mDirtyRegion.set(mInvalidRegion.bounds()); } else { @@ -920,7 +920,7 @@ void SurfaceFlinger::debugFlashRegions() if (!((flags & DisplayHardware::SWAP_RECTANGLE) || (flags & DisplayHardware::BUFFER_PRESERVED))) { - const Region repaint((flags & DisplayHardware::UPDATE_ON_DEMAND) ? + const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ? mDirtyRegion.bounds() : hw.bounds()); composeSurfaces(repaint); } @@ -1084,12 +1084,9 @@ status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) { - // First add the layer to the purgatory list, which makes sure it won't - // go away, then remove it from the main list (through a transaction). + // remove the layer from the main list (through a transaction). ssize_t err = removeLayer_l(layerBase); - if (err >= 0) { - mLayerPurgatory.add(layerBase); - } + // it's possible that we don't find a layer, because it might // have been destroyed already -- this is not technically an error // from the user because there is a race between BClient::destroySurface(), @@ -1362,18 +1359,8 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) * to use the purgatory. */ status_t err = flinger->removeLayer_l(l); - if (err == NAME_NOT_FOUND) { - // The surface wasn't in the current list, which means it was - // removed already, which means it is in the purgatory, - // and need to be removed from there. - // This needs to happen from the main thread since its dtor - // must run from there (b/c of OpenGL ES). Additionally, we - // can't really acquire our internal lock from - // destroySurface() -- see postMessage() below. - ssize_t idx = flinger->mLayerPurgatory.remove(l); - LOGE_IF(idx < 0, - "layer=%p is not in the purgatory list", l.get()); - } + LOGE_IF(err<0 && err != NAME_NOT_FOUND, + "error removing layer=%p (%s)", l.get(), strerror(-err)); return true; } }; @@ -1510,11 +1497,12 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) "+ %s %p\n" " " "z=%9d, pos=(%4d,%4d), size=(%4d,%4d), " - "needsBlending=%1d, invalidate=%1d, " + "needsBlending=%1d, needsDithering=%1d, invalidate=%1d, " "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n", layer->getTypeID(), layer.get(), s.z, layer->tx(), layer->ty(), s.w, s.h, - layer->needsBlending(), layer->contentDirty, + layer->needsBlending(), layer->needsDithering(), + layer->contentDirty, s.alpha, s.flags, s.transform[0], s.transform[1], s.transform[2], s.transform[3]); diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index 493e777..e446070 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -314,7 +314,6 @@ private: volatile int32_t mTransactionCount; Condition mTransactionCV; bool mResizeTransationPending; - SortedVector< sp<LayerBase> > mLayerPurgatory; // protected by mStateLock (but we could use another lock) Tokenizer mTokens; diff --git a/libs/surfaceflinger/Transform.h b/libs/surfaceflinger/Transform.h index 4c4528e..78f5c19 100644 --- a/libs/surfaceflinger/Transform.h +++ b/libs/surfaceflinger/Transform.h @@ -50,6 +50,14 @@ public: ROT_INVALID = 0x80000000 }; + enum type_mask { + IDENTITY = 0, + TRANSLATE = 0x1, + SCALE = 0x2, + AFFINE = 0x4, + PERSPECTIVE = 0x8 + }; + bool transformed() const; int32_t getOrientation() const; bool preserveRects() const; diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp index fc2e2f6..c5e22e5 100644 --- a/libs/ui/FramebufferNativeWindow.cpp +++ b/libs/ui/FramebufferNativeWindow.cpp @@ -117,15 +117,17 @@ FramebufferNativeWindow::FramebufferNativeWindow() LOGE_IF(err, "fb buffer 1 allocation failed w=%d, h=%d, err=%s", fbDev->width, fbDev->height, strerror(-err)); - } - const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags; - const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi; - const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi; - const_cast<int&>(android_native_window_t::minSwapInterval) = - fbDev->minSwapInterval; - const_cast<int&>(android_native_window_t::maxSwapInterval) = - fbDev->maxSwapInterval; + const_cast<uint32_t&>(android_native_window_t::flags) = fbDev->flags; + const_cast<float&>(android_native_window_t::xdpi) = fbDev->xdpi; + const_cast<float&>(android_native_window_t::ydpi) = fbDev->ydpi; + const_cast<int&>(android_native_window_t::minSwapInterval) = + fbDev->minSwapInterval; + const_cast<int&>(android_native_window_t::maxSwapInterval) = + fbDev->maxSwapInterval; + } else { + LOGE("Couldn't get gralloc module"); + } android_native_window_t::setSwapInterval = setSwapInterval; android_native_window_t::dequeueBuffer = dequeueBuffer; diff --git a/libs/ui/SurfaceComposerClient.cpp b/libs/ui/SurfaceComposerClient.cpp index 8401cb6..3baa281 100644 --- a/libs/ui/SurfaceComposerClient.cpp +++ b/libs/ui/SurfaceComposerClient.cpp @@ -62,34 +62,42 @@ static SortedVector<sp<SurfaceComposerClient> > gOpenTransactions; static sp<IMemoryHeap> gServerCblkMemory; static volatile surface_flinger_cblk_t* gServerCblk; -const sp<ISurfaceComposer>& _get_surface_manager() +static sp<ISurfaceComposer> getComposerService() { + sp<ISurfaceComposer> sc; + Mutex::Autolock _l(gLock); if (gSurfaceManager != 0) { - return gSurfaceManager; - } + sc = gSurfaceManager; + } else { + // release the lock while we're waiting... + gLock.unlock(); + + sp<IBinder> binder; + sp<IServiceManager> sm = defaultServiceManager(); + do { + binder = sm->getService(String16("SurfaceFlinger")); + if (binder == 0) { + LOGW("SurfaceFlinger not published, waiting..."); + usleep(500000); // 0.5 s + } + } while(binder == 0); - sp<IBinder> binder; - sp<IServiceManager> sm = defaultServiceManager(); - do { - binder = sm->getService(String16("SurfaceFlinger")); - if (binder == 0) { - LOGW("SurfaceFlinger not published, waiting..."); - usleep(500000); // 0.5 s + // grab the lock again for updating gSurfaceManager + gLock.lock(); + if (gSurfaceManager == 0) { + sc = interface_cast<ISurfaceComposer>(binder); + gSurfaceManager = sc; + } else { + sc = gSurfaceManager; } - } while(binder == 0); - sp<ISurfaceComposer> sc(interface_cast<ISurfaceComposer>(binder)); - - Mutex::Autolock _l(gLock); - if (gSurfaceManager == 0) { - gSurfaceManager = sc; } - return gSurfaceManager; + return sc; } static volatile surface_flinger_cblk_t const * get_cblk() { if (gServerCblk == 0) { - const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sp<ISurfaceComposer> sm(getComposerService()); Mutex::Autolock _l(gLock); if (gServerCblk == 0) { gServerCblkMemory = sm->getCblk(); @@ -112,7 +120,7 @@ static inline int compare_type( const layer_state_t& lhs, SurfaceComposerClient::SurfaceComposerClient() { - const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sp<ISurfaceComposer> sm(getComposerService()); if (sm == 0) { _init(0, 0); return; @@ -133,6 +141,15 @@ SurfaceComposerClient::SurfaceComposerClient( _init(sm, interface_cast<ISurfaceFlingerClient>(conn)); } + +status_t SurfaceComposerClient::linkToComposerDeath( + const sp<IBinder::DeathRecipient>& recipient, + void* cookie, uint32_t flags) +{ + sp<ISurfaceComposer> sm(getComposerService()); + return sm->asBinder()->linkToDeath(recipient, cookie, flags); +} + void SurfaceComposerClient::_init( const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn) { @@ -183,7 +200,7 @@ SurfaceComposerClient::clientForConnection(const sp<IBinder>& conn) if (client == 0) { // Need to make a new client. - const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sp<ISurfaceComposer> sm(getComposerService()); client = new SurfaceComposerClient(sm, conn); if (client != 0 && client->initCheck() == NO_ERROR) { Mutex::Autolock _l(gLock); @@ -377,7 +394,7 @@ void SurfaceComposerClient::closeGlobalTransaction() const size_t N = clients.size(); VERBOSE("closeGlobalTransaction (%ld clients)", N); - const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sp<ISurfaceComposer> sm(getComposerService()); sm->openGlobalTransaction(); for (size_t i=0; i<N; i++) { clients[i]->closeTransaction(); @@ -389,20 +406,20 @@ void SurfaceComposerClient::closeGlobalTransaction() status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags) { - const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sp<ISurfaceComposer> sm(getComposerService()); return sm->freezeDisplay(dpy, flags); } status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags) { - const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sp<ISurfaceComposer> sm(getComposerService()); return sm->unfreezeDisplay(dpy, flags); } int SurfaceComposerClient::setOrientation(DisplayID dpy, int orientation, uint32_t flags) { - const sp<ISurfaceComposer>& sm(_get_surface_manager()); + sp<ISurfaceComposer> sm(getComposerService()); return sm->setOrientation(dpy, orientation, flags); } diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp index 0cef35a..2535094 100644 --- a/libs/utils/BackupData.cpp +++ b/libs/utils/BackupData.cpp @@ -196,8 +196,9 @@ BackupDataReader::Status() m_done = true; \ } else { \ m_status = errno; \ + LOGD("CHECK_SIZE(a=%ld e=%ld) failed at line %d m_status='%s'", \ + long(actual), long(expected), __LINE__, strerror(m_status)); \ } \ - LOGD("CHECK_SIZE failed with at line %d m_status='%s'", __LINE__, strerror(m_status)); \ return m_status; \ } \ } while(0) diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp index f414ee5..4878722 100644 --- a/opengl/libagl/array.cpp +++ b/opengl/libagl/array.cpp @@ -1266,9 +1266,7 @@ void glColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid *pointer) { ogles_context_t* c = ogles_context_t::get(); - // in theory ogles doesn't allow color arrays of size 3 - // but it is very useful to 'visualize' the normal array. - if (size<3 || size>4 || stride<0) { + if (size!=4 || stride<0) { ogles_error(c, GL_INVALID_VALUE); return; } diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp index f97d347..ba9a717 100644 --- a/opengl/tests/gl2_basic/gl2_basic.cpp +++ b/opengl/tests/gl2_basic/gl2_basic.cpp @@ -291,6 +291,7 @@ int main(int argc, char** argv) { for (;;) { renderFrame(); eglSwapBuffers(dpy, surface); + checkEglError("eglSwapBuffers"); } return 0; diff --git a/opengl/tests/gl2_jni/Android.mk b/opengl/tests/gl2_jni/Android.mk new file mode 100644 index 0000000..ff15814 --- /dev/null +++ b/opengl/tests/gl2_jni/Android.mk @@ -0,0 +1,53 @@ +######################################################################### +# OpenGL ES JNI sample +# This makefile builds both an activity and a shared library. +######################################################################### +ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean + +TOP_LOCAL_PATH:= $(call my-dir) + +# Build activity + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := user + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := GL2JNI + +LOCAL_JNI_SHARED_LIBRARIES := libgl2jni + +include $(BUILD_PACKAGE) + +######################################################################### +# Build JNI Shared Library +######################################################################### + +LOCAL_PATH:= $(LOCAL_PATH)/jni + +include $(CLEAR_VARS) + +# Optional tag would mean it doesn't get installed by default +LOCAL_MODULE_TAGS := optional + +LOCAL_CFLAGS := -Werror + +LOCAL_SRC_FILES:= \ + gl_code.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libEGL \ + libGLESv2 + +LOCAL_MODULE := libgl2jni + +LOCAL_ARM_MODE := arm + +LOCAL_PRELINK_MODULE := false + +include $(BUILD_SHARED_LIBRARY) + +endif # TARGET_SIMULATOR diff --git a/opengl/tests/gl2_jni/AndroidManifest.xml b/opengl/tests/gl2_jni/AndroidManifest.xml new file mode 100644 index 0000000..a72a6a5 --- /dev/null +++ b/opengl/tests/gl2_jni/AndroidManifest.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 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. +*/ +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.gl2jni"> + <application + android:label="@string/gl2jni_activity"> + <activity android:name="GL2JNIActivity" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen" + android:launchMode="singleTask" + android:configChanges="orientation|keyboardHidden"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/opengl/tests/gl2_jni/jni/gl_code.cpp b/opengl/tests/gl2_jni/jni/gl_code.cpp new file mode 100644 index 0000000..146d52a --- /dev/null +++ b/opengl/tests/gl2_jni/jni/gl_code.cpp @@ -0,0 +1,165 @@ +// OpenGL ES 2.0 code + +#include <nativehelper/jni.h> +#define LOG_TAG "GL2JNI gl_code.cpp" +#include <utils/Log.h> +
+#include <EGL/egl.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <stdio.h>
+#include <stdlib.h> +#include <math.h> + +static void printGLString(const char *name, GLenum s) { + const char *v = (const char *) glGetString(s); + LOGI("GL %s = %s\n", name, v); +} + +static void checkGlError(const char* op) { + for (GLint error = glGetError(); error; error + = glGetError()) { + LOGI("after %s() glError (0x%x)\n", op, error); + } +} +
+static const char gVertexShader[] = "attribute vec4 vPosition;\n" + "void main() {\n" + " gl_Position = vPosition;\n" + "}\n"; + +static const char gFragmentShader[] = "precision mediump float;\n" + "void main() {\n" + " gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n" + "}\n"; + +GLuint loadShader(GLenum shaderType, const char* pSource) { + GLuint shader = glCreateShader(shaderType); + if (shader) { + glShaderSource(shader, 1, &pSource, NULL); + glCompileShader(shader); + GLint compiled = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); + if (!compiled) { + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (infoLen) { + char* buf = (char*) malloc(infoLen); + if (buf) { + glGetShaderInfoLog(shader, infoLen, NULL, buf); + LOGE("Could not compile shader %d:\n%s\n", + shaderType, buf); + free(buf); + } + glDeleteShader(shader); + shader = 0; + } + } + } + return shader; +} + +GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) { + GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource); + if (!vertexShader) { + return 0; + } + + GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource); + if (!pixelShader) { + return 0; + } + + GLuint program = glCreateProgram(); + if (program) { + glAttachShader(program, vertexShader); + checkGlError("glAttachShader"); + glAttachShader(program, pixelShader); + checkGlError("glAttachShader"); + glLinkProgram(program); + GLint linkStatus = GL_FALSE; + glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) { + GLint bufLength = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); + if (bufLength) { + char* buf = (char*) malloc(bufLength); + if (buf) { + glGetProgramInfoLog(program, bufLength, NULL, buf); + LOGE("Could not link program:\n%s\n", buf); + free(buf); + } + } + glDeleteProgram(program); + program = 0; + } + } + return program; +} + +GLuint gProgram; +GLuint gvPositionHandle; + +bool setupGraphics(int w, int h) { + printGLString("Version", GL_VERSION); + printGLString("Vendor", GL_VENDOR); + printGLString("Renderer", GL_RENDERER); + printGLString("Extensions", GL_EXTENSIONS); + + LOGI("setupGraphics(%d, %d)", w, h); + gProgram = createProgram(gVertexShader, gFragmentShader); + if (!gProgram) { + LOGE("Could not create program."); + return false; + } + gvPositionHandle = glGetAttribLocation(gProgram, "vPosition"); + checkGlError("glGetAttribLocation"); + LOGI("glGetAttribLocation(\"vPosition\") = %d\n", + gvPositionHandle); + + glViewport(0, 0, w, h); + checkGlError("glViewport"); + return true; +} + +const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f, + 0.5f, -0.5f }; + +void renderFrame() { + static float grey; + grey += 0.01f; + if (grey > 1.0f) { + grey = 0.0f; + } + glClearColor(grey, grey, grey, 1.0f); + checkGlError("glClearColor"); + glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + checkGlError("glClear"); + + glUseProgram(gProgram); + checkGlError("glUseProgram"); + + glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices); + checkGlError("glVertexAttribPointer"); + glEnableVertexAttribArray(gvPositionHandle); + checkGlError("glEnableVertexAttribArray"); + glDrawArrays(GL_TRIANGLES, 0, 3); + checkGlError("glDrawArrays"); +} + +extern "C" { + JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height); + JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj); +};
+
+JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+ setupGraphics(width, height);
+}
+ +JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj)
+{
+ renderFrame();
+}
+ diff --git a/opengl/tests/gl2_jni/res/values/strings.xml b/opengl/tests/gl2_jni/res/values/strings.xml new file mode 100644 index 0000000..e3f7331 --- /dev/null +++ b/opengl/tests/gl2_jni/res/values/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 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. +*/ +--> + +<!-- This file contains resource definitions for displayed strings, allowing + them to be changed based on the locale and options. --> + +<resources> + <!-- Simple strings. --> + <string name="gl2jni_activity">GL2JNI</string> + +</resources> + diff --git a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java new file mode 100644 index 0000000..c366a2c --- /dev/null +++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIActivity.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package com.android.gl2jni; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.WindowManager; + +import java.io.File; + + +public class GL2JNIActivity extends Activity { + + GL2JNIView mView; + + @Override protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + mView = new GL2JNIView(getApplication()); + setContentView(mView); + } + + @Override protected void onPause() { + super.onPause(); + mView.onPause(); + } + + @Override protected void onResume() { + super.onResume(); + mView.onResume(); + } +} diff --git a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNILib.java b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNILib.java new file mode 100644 index 0000000..040a984 --- /dev/null +++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNILib.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package com.android.gl2jni; + +// Wrapper for native library + +public class GL2JNILib { + + static { + System.loadLibrary("gl2jni"); + } + + /** + * @param width the current view width + * @param height the current view height + */ + public static native void init(int width, int height); + public static native void step(); +} diff --git a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java new file mode 100644 index 0000000..baa10af --- /dev/null +++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java @@ -0,0 +1,134 @@ +/* + * 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. + */ + +package com.android.gl2jni; +/* + * Copyright (C) 2008 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. + */ + + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.opengles.GL10; +/** + * An implementation of SurfaceView that uses the dedicated surface for + * displaying an OpenGL animation. This allows the animation to run in a + * separate thread, without requiring that it be driven by the update mechanism + * of the view hierarchy. + * + * The application-specific rendering code is delegated to a GLView.Renderer + * instance. + */ +class GL2JNIView extends GLSurfaceView { + private static String TAG = "GL2JNIView"; + GL2JNIView(Context context) { + super(context); + init(); + } + + public GL2JNIView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + setEGLContextFactory(new ContextFactory()); + // setEGLConfigChooser(new ConfigChooser()); + setRenderer(new Renderer()); + } + + private static class ContextFactory implements GLSurfaceView.EGLContextFactory { + private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { + checkEglError("Before eglCreateContext", egl); + int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; + EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list); + checkEglError("After eglCreateContext", egl); + return context; + } + + public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) { + egl.eglDestroyContext(display, context); + } + } + + private static void checkEglError(String prompt, EGL10 egl) { + int error; + while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) { + Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error)); + } + } + + private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser { + private static int EGL_OPENGL_ES2_BIT = 4; + private static int[] s_configAttribs2 = + { + EGL10.EGL_DEPTH_SIZE, 16, + // EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_NONE + }; + public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { + + int[] num_config = new int[1]; + egl.eglChooseConfig(display, s_configAttribs2, null, 0, num_config); + + int numConfigs = num_config[0]; + + if (numConfigs <= 0) { + throw new IllegalArgumentException("No configs match configSpec"); + } + EGLConfig[] configs = new EGLConfig[numConfigs]; + egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config); + return configs[0]; + } + } + + private static class Renderer implements GLSurfaceView.Renderer { + public void onDrawFrame(GL10 gl) { + GL2JNILib.step(); + } + + public void onSurfaceChanged(GL10 gl, int width, int height) { + GL2JNILib.init(width, height); + } + + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + // Do nothing. + } + } +} + diff --git a/opengl/tests/gl_jni/Android.mk b/opengl/tests/gl_jni/Android.mk new file mode 100644 index 0000000..4029fa1 --- /dev/null +++ b/opengl/tests/gl_jni/Android.mk @@ -0,0 +1,53 @@ +######################################################################### +# OpenGL ES JNI sample +# This makefile builds both an activity and a shared library. +######################################################################### +ifneq ($(TARGET_SIMULATOR),true) # not 64 bit clean + +TOP_LOCAL_PATH:= $(call my-dir) + +# Build activity + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := user + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := GLJNI + +LOCAL_JNI_SHARED_LIBRARIES := libgljni + +include $(BUILD_PACKAGE) + +######################################################################### +# Build JNI Shared Library +######################################################################### + +LOCAL_PATH:= $(LOCAL_PATH)/jni + +include $(CLEAR_VARS) + +# Optional tag would mean it doesn't get installed by default +LOCAL_MODULE_TAGS := optional + +LOCAL_CFLAGS := -Werror + +LOCAL_SRC_FILES:= \ + gl_code.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libEGL \ + libGLESv1_CM + +LOCAL_MODULE := libgljni + +LOCAL_ARM_MODE := arm + +LOCAL_PRELINK_MODULE := false + +include $(BUILD_SHARED_LIBRARY) + +endif # TARGET_SIMULATOR diff --git a/opengl/tests/gl_jni/AndroidManifest.xml b/opengl/tests/gl_jni/AndroidManifest.xml new file mode 100644 index 0000000..64bd6bf --- /dev/null +++ b/opengl/tests/gl_jni/AndroidManifest.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 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. +*/ +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.gljni"> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + <application + android:label="@string/gljni_activity"> + <activity android:name="GLJNIActivity" + android:theme="@android:style/Theme.NoTitleBar.Fullscreen" + android:launchMode="singleTask" + android:screenOrientation="landscape" + android:configChanges="orientation|keyboardHidden"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp new file mode 100644 index 0000000..b85a433 --- /dev/null +++ b/opengl/tests/gl_jni/jni/gl_code.cpp @@ -0,0 +1,177 @@ +// OpenGL ES 1.0 code + +#include <nativehelper/jni.h> +#define LOG_TAG "GLJNI gl_code.cpp" +#include <utils/Log.h>
+#include <GLES/gl.h> + +#include <stdio.h>
+#include <stdlib.h> +#include <math.h> +
+GLuint texture;
+
+#define FIXED_ONE 0x10000
+ +static void printGLString(const char *name, GLenum s) { + const char *v = (const char *) glGetString(s); + LOGI("GL %s = %s\n", name, v); +} + +static void gluLookAt(float eyeX, float eyeY, float eyeZ, + float centerX, float centerY, float centerZ, float upX, float upY, + float upZ) +{ + // See the OpenGL GLUT documentation for gluLookAt for a description + // of the algorithm. We implement it in a straightforward way: + + float fx = centerX - eyeX; + float fy = centerY - eyeY; + float fz = centerZ - eyeZ; + + // Normalize f + float rlf = 1.0f / sqrtf(fx*fx + fy*fy + fz*fz); + fx *= rlf; + fy *= rlf; + fz *= rlf; + + // Normalize up + float rlup = 1.0f / sqrtf(upX*upX + upY*upY + upZ*upZ); + upX *= rlup; + upY *= rlup; + upZ *= rlup; + + // compute s = f x up (x means "cross product") + + float sx = fy * upZ - fz * upY; + float sy = fz * upX - fx * upZ; + float sz = fx * upY - fy * upX; + + // compute u = s x f + float ux = sy * fz - sz * fy; + float uy = sz * fx - sx * fz; + float uz = sx * fy - sy * fx; + + float m[16] ; + m[0] = sx; + m[1] = ux; + m[2] = -fx; + m[3] = 0.0f; + + m[4] = sy; + m[5] = uy; + m[6] = -fy; + m[7] = 0.0f; + + m[8] = sz; + m[9] = uz; + m[10] = -fz; + m[11] = 0.0f; + + m[12] = 0.0f; + m[13] = 0.0f; + m[14] = 0.0f; + m[15] = 1.0f; + + glMultMatrixf(m); + glTranslatef(-eyeX, -eyeY, -eyeZ); +} + +void init_scene(int width, int height)
+{ + printGLString("Version", GL_VERSION); + printGLString("Vendor", GL_VENDOR); + printGLString("Renderer", GL_RENDERER); + printGLString("Extensions", GL_EXTENSIONS);
+ glDisable(GL_DITHER); + glEnable(GL_CULL_FACE); + + + float ratio = width / height; + glViewport(0, 0, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+ + + glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity(); + gluLookAt( + 0, 0, 3, // eye + 0, 0, 0, // center + 0, 1, 0); // up +
+ glEnable(GL_TEXTURE_2D);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY); +}
+
+void create_texture()
+{
+ const unsigned int on = 0xff0000ff; + const unsigned int off = 0xffffffff; + const unsigned int pixels[] = + { + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + on, off, on, off, on, off, on, off, + off, on, off, on, off, on, off, on, + };
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+} + +extern "C" { + JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height); + JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj); +}; +
+
+JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_init(JNIEnv * env, jobject obj, jint width, jint height)
+{
+ init_scene(width, height);
+ create_texture();
+}
+ +JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_step(JNIEnv * env, jobject obj)
+{
+ const GLfloat vertices[] = {
+ -1, -1, 0,
+ 1, -1, 0,
+ 1, 1, 0,
+ -1, 1, 0
+ };
+
+ const GLfixed texCoords[] = {
+ 0, 0,
+ FIXED_ONE, 0,
+ FIXED_ONE, FIXED_ONE,
+ 0, FIXED_ONE
+ };
+
+ const GLushort quadIndices[] = { 0, 1, 2, 0, 2, 3 }; + + glVertexPointer(3, GL_FLOAT, 0, vertices);
+ glTexCoordPointer(2, GL_FIXED, 0, texCoords); + + + int nelem = sizeof(quadIndices)/sizeof(quadIndices[0]); + static float grey; + grey += 0.01f; + if (grey > 1.0f) { + grey = 0.0f; + } + glClearColor(grey, grey, grey, 1.0f); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + glDrawElements(GL_TRIANGLES, nelem, GL_UNSIGNED_SHORT, quadIndices);
+}
+ diff --git a/opengl/tests/gl_jni/res/values/strings.xml b/opengl/tests/gl_jni/res/values/strings.xml new file mode 100644 index 0000000..880f5c9 --- /dev/null +++ b/opengl/tests/gl_jni/res/values/strings.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright 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. +*/ +--> + +<!-- This file contains resource definitions for displayed strings, allowing + them to be changed based on the locale and options. --> + +<resources> + <!-- Simple strings. --> + <string name="gljni_activity">GLJNI</string> + +</resources> + diff --git a/opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java new file mode 100644 index 0000000..df1f957 --- /dev/null +++ b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIActivity.java @@ -0,0 +1,46 @@ +/* + * 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. + */ + +package com.android.gljni; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.WindowManager; + +import java.io.File; + + +public class GLJNIActivity extends Activity { + + GLJNIView mView; + + @Override protected void onCreate(Bundle icicle) { + super.onCreate(icicle); + mView = new GLJNIView(getApplication()); + setContentView(mView); + } + + @Override protected void onPause() { + super.onPause(); + mView.onPause(); + } + + @Override protected void onResume() { + super.onResume(); + mView.onResume(); + } +} diff --git a/opengl/tests/gl_jni/src/com/android/gljni/GLJNILib.java b/opengl/tests/gl_jni/src/com/android/gljni/GLJNILib.java new file mode 100644 index 0000000..8662725 --- /dev/null +++ b/opengl/tests/gl_jni/src/com/android/gljni/GLJNILib.java @@ -0,0 +1,33 @@ +/* + * 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. + */ + +package com.android.gljni; + +// Wrapper for native library + +public class GLJNILib { + + static { + System.loadLibrary("gljni"); + } + + /** + * @param width the current view width + * @param height the current view height + */ + public static native void init(int width, int height); + public static native void step(); +} diff --git a/opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.java b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.java new file mode 100644 index 0000000..9ea1059 --- /dev/null +++ b/opengl/tests/gl_jni/src/com/android/gljni/GLJNIView.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package com.android.gljni; +/* + * Copyright (C) 2008 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. + */ + + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.util.AttributeSet; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; +/** + * An implementation of SurfaceView that uses the dedicated surface for + * displaying an OpenGL animation. This allows the animation to run in a + * separate thread, without requiring that it be driven by the update mechanism + * of the view hierarchy. + * + * The application-specific rendering code is delegated to a GLView.Renderer + * instance. + */ +class GLJNIView extends GLSurfaceView { + GLJNIView(Context context) { + super(context); + init(); + } + + public GLJNIView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + setRenderer(new Renderer()); + } + + private class Renderer implements GLSurfaceView.Renderer { + private static final String TAG = "Renderer"; + public void onDrawFrame(GL10 gl) { + GLJNILib.step(); + } + + public void onSurfaceChanged(GL10 gl, int width, int height) { + GLJNILib.init(width, height); + } + + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + // Do nothing. + } + } +} + diff --git a/opengl/tests/tritex/Android.mk b/opengl/tests/tritex/Android.mk index 76fd8dd..6db3f49 100644 --- a/opengl/tests/tritex/Android.mk +++ b/opengl/tests/tritex/Android.mk @@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ - tritex.c + tritex.cpp LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/opengl/tests/tritex/tritex.c b/opengl/tests/tritex/tritex.cpp index 60a7feb..629b53c 100644 --- a/opengl/tests/tritex/tritex.c +++ b/opengl/tests/tritex/tritex.cpp @@ -6,10 +6,16 @@ #include <EGL/egl.h>
#include <GLES/gl.h> +#include <GLES/glext.h> + +#include <ui/FramebufferNativeWindow.h> +#include <ui/EGLUtils.h> #include <stdio.h>
#include <stdlib.h> #include <math.h> + +using namespace android; EGLDisplay eglDisplay;
EGLSurface eglSurface;
@@ -117,6 +123,7 @@ int init_gl_surface(void) EGLConfig myConfig = {0};
EGLint attrib[] =
{
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT|EGL_WINDOW_BIT, EGL_DEPTH_SIZE, 16,
EGL_NONE
};
@@ -132,15 +139,12 @@ int init_gl_surface(void) printf("eglInitialize failed\n");
return 0;
}
-
- if ( eglChooseConfig(eglDisplay, attrib, &myConfig, 1, &numConfigs) != EGL_TRUE )
- {
- printf("eglChooseConfig failed\n");
- return 0;
- }
+ + EGLNativeWindowType window = android_createDisplaySurface();
+ EGLUtils::selectConfigForNativeWindow(eglDisplay, attrib, window, &myConfig);
if ( (eglSurface = eglCreateWindowSurface(eglDisplay, myConfig, - android_createDisplaySurface(), 0)) == EGL_NO_SURFACE )
+ window, 0)) == EGL_NO_SURFACE )
{
printf("eglCreateWindowSurface failed\n");
return 0;
@@ -239,12 +243,12 @@ void render(int quads) 0, FIXED_ONE
};
- const GLushort template[] = { 0, 1, 2, 0, 2, 3 }; + const GLushort quadIndices[] = { 0, 1, 2, 0, 2, 3 }; - GLushort* indices = (GLushort*)malloc(quads*sizeof(template)); + GLushort* indices = (GLushort*)malloc(quads*sizeof(quadIndices)); for (i=0 ; i<quads ; i++) - memcpy(indices+(sizeof(template)/sizeof(indices[0]))*i, template, sizeof(template)); + memcpy(indices+(sizeof(quadIndices)/sizeof(indices[0]))*i, quadIndices, sizeof(quadIndices)); glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FIXED, 0, texCoords); @@ -262,7 +266,7 @@ void render(int quads) for (j=0 ; j<10 ; j++) { printf("loop %d / 10 (%d quads / loop)\n", j, quads); - int nelem = sizeof(template)/sizeof(template[0]); + int nelem = sizeof(quadIndices)/sizeof(quadIndices[0]); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glDrawElements(GL_TRIANGLES, nelem*quads, GL_UNSIGNED_SHORT, indices); eglSwapBuffers(eglDisplay, eglSurface); |