logd: logcat -L takes longer causing vold to timeout. am: 90a3f81c9e
am: 366513fc3f
Change-Id: Iab79f34aa6655295672fdd53dca7cef58b2574ee
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b3661e4..31e60ca 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -56,3 +56,6 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libsysutils_intermediates/import_includes)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/grep $(PRODUCT_OUT)/system/bin/toolbox)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/hw/gatekeeper.$(TARGET_DEVICE).so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib64/hw/gatekeeper.$(TARGET_DEVICE).so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/vendor)
diff --git a/adb/Android.mk b/adb/Android.mk
index 695cbe0..6a2a6b1 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -58,10 +58,12 @@
LIBADB_TEST_SRCS := \
adb_io_test.cpp \
+ adb_listeners_test.cpp \
adb_utils_test.cpp \
fdevent_test.cpp \
socket_test.cpp \
sysdeps_test.cpp \
+ sysdeps/stat_test.cpp \
transport_test.cpp \
LIBADB_CFLAGS := \
@@ -89,6 +91,7 @@
LIBADB_windows_SRC_FILES := \
sysdeps_win32.cpp \
+ sysdeps/win32/stat.cpp \
usb_windows.cpp \
LIBADB_TEST_windows_SRCS := \
@@ -108,7 +111,7 @@
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
include $(BUILD_STATIC_LIBRARY)
@@ -131,7 +134,7 @@
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the includes to our path.
-LOCAL_STATIC_LIBRARIES := libcrypto_static libbase
+LOCAL_STATIC_LIBRARIES := libcrypto_utils_static libcrypto_static libbase
LOCAL_C_INCLUDES_windows := development/host/windows/usb/api/
LOCAL_MULTILIB := first
@@ -151,7 +154,7 @@
shell_service_test.cpp \
LOCAL_SANITIZE := $(adb_target_sanitize)
-LOCAL_STATIC_LIBRARIES := libadbd
+LOCAL_STATIC_LIBRARIES := libadbd libcrypto_utils_static libcrypto_static
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
include $(BUILD_NATIVE_TEST)
@@ -195,6 +198,7 @@
LOCAL_SHARED_LIBRARIES := libbase
LOCAL_STATIC_LIBRARIES := \
libadb \
+ libcrypto_utils_static \
libcrypto_static \
libcutils \
libdiagnose_usb \
@@ -211,24 +215,6 @@
include $(BUILD_HOST_NATIVE_TEST)
-# adb device tracker (used by ddms) test tool
-# =========================================================
-
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_MODULE := adb_device_tracker_test
-LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
-LOCAL_CFLAGS_windows := $(LIBADB_windows_CFLAGS)
-LOCAL_CFLAGS_linux := $(LIBADB_linux_CFLAGS)
-LOCAL_CFLAGS_darwin := $(LIBADB_darwin_CFLAGS)
-LOCAL_SRC_FILES := test_track_devices.cpp
-LOCAL_SANITIZE := $(adb_host_sanitize)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
-LOCAL_LDLIBS += -lrt -ldl -lpthread
-include $(BUILD_HOST_EXECUTABLE)
-endif
-
# adb host tool
# =========================================================
include $(CLEAR_VARS)
@@ -277,6 +263,7 @@
LOCAL_STATIC_LIBRARIES := \
libadb \
libbase \
+ libcrypto_utils_static \
libcrypto_static \
libdiagnose_usb \
liblog \
@@ -340,6 +327,7 @@
LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_SANITIZE := $(adb_target_sanitize)
+LOCAL_STRIP_MODULE := keep_symbols
LOCAL_STATIC_LIBRARIES := \
libadbd \
libbase \
@@ -348,12 +336,13 @@
libfec_rs \
libselinux \
liblog \
- libmincrypt \
libext4_utils_static \
libsquashfs_utils \
libcutils \
libbase \
+ libcrypto_utils_static \
libcrypto_static \
- libminijail
+ libminijail \
+ libdebuggerd_client \
include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index e0c0503..725aa91 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -46,8 +46,6 @@
#include "adb_utils.h"
#include "transport.h"
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
#if !ADB_HOST
#include <cutils/properties.h>
#include <sys/capability.h>
@@ -65,21 +63,34 @@
void fatal(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
+ char buf[1024];
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+ fprintf(stderr, "error: %s\n", buf);
+#else
+ LOG(ERROR) << "error: " << buf;
+#endif
+
va_end(ap);
- exit(-1);
+ abort();
}
void fatal_errno(const char* fmt, ...) {
+ int err = errno;
va_list ap;
va_start(ap, fmt);
- fprintf(stderr, "error: %s: ", strerror(errno));
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
+ char buf[1024];
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+#if ADB_HOST
+ fprintf(stderr, "error: %s: %s\n", buf, strerror(err));
+#else
+ LOG(ERROR) << "error: " << buf << ": " << strerror(err);
+#endif
+
va_end(ap);
- exit(-1);
+ abort();
}
apacket* get_apacket(void)
@@ -316,8 +327,6 @@
void handle_packet(apacket *p, atransport *t)
{
- asocket *s;
-
D("handle_packet() %c%c%c%c", ((char*) (&(p->msg.command)))[0],
((char*) (&(p->msg.command)))[1],
((char*) (&(p->msg.command)))[2],
@@ -326,7 +335,7 @@
switch(p->msg.command){
case A_SYNC:
- if(p->msg.arg0){
+ if (p->msg.arg0){
send_packet(p, t);
#if ADB_HOST
send_connect(t);
@@ -353,7 +362,8 @@
send_auth_publickey(t);
}
} else if (p->msg.arg0 == ADB_AUTH_SIGNATURE) {
- if (adb_auth_verify(t->token, p->data, p->msg.data_length)) {
+ if (adb_auth_verify(t->token, sizeof(t->token),
+ p->data, p->msg.data_length)) {
adb_auth_verified(t);
t->failed_auth_attempts = 0;
} else {
@@ -370,8 +380,8 @@
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
char *name = (char*) p->data;
name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
- s = create_local_service_socket(name, t);
- if(s == 0) {
+ asocket* s = create_local_service_socket(name, t);
+ if (s == nullptr) {
send_close(0, p->msg.arg0, t);
} else {
s->peer = create_remote_socket(p->msg.arg0, t);
@@ -384,7 +394,8 @@
case A_OKAY: /* READY(local-id, remote-id, "") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, 0))) {
+ asocket* s = find_local_socket(p->msg.arg1, 0);
+ if (s) {
if(s->peer == 0) {
/* On first READY message, create the connection. */
s->peer = create_remote_socket(p->msg.arg0, t);
@@ -408,7 +419,8 @@
case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
if (t->online && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+ asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
+ if (s) {
/* According to protocol.txt, p->msg.arg0 might be 0 to indicate
* a failed OPEN only. However, due to a bug in previous ADB
* versions, CLOSE(0, remote-id, "") was also used for normal
@@ -431,11 +443,12 @@
case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+ asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
+ if (s) {
unsigned rid = p->msg.arg0;
p->len = p->msg.data_length;
- if(s->enqueue(s, p) == 0) {
+ if (s->enqueue(s, p) == 0) {
D("Enqueue the socket");
send_ready(s->id, rid, t);
}
@@ -954,18 +967,25 @@
std::string error;
InstallStatus r;
+ int resolved_tcp_port = 0;
if (kill_forward) {
r = remove_listener(pieces[0].c_str(), transport);
} else {
- r = install_listener(pieces[0], pieces[1].c_str(), transport,
- no_rebind, &error);
+ r = install_listener(pieces[0], pieces[1].c_str(), transport, no_rebind,
+ &resolved_tcp_port, &error);
}
if (r == INSTALL_STATUS_OK) {
#if ADB_HOST
- /* On the host: 1st OKAY is connect, 2nd OKAY is status */
+ // On the host: 1st OKAY is connect, 2nd OKAY is status.
SendOkay(reply_fd);
#endif
SendOkay(reply_fd);
+
+ // If a TCP port was resolved, send the actual port number back.
+ if (resolved_tcp_port != 0) {
+ SendProtocolString(reply_fd, android::base::StringPrintf("%d", resolved_tcp_port));
+ }
+
return 1;
}
diff --git a/adb/adb.h b/adb/adb.h
index 971b8da..cd6b7bd 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -50,7 +50,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 36
+#define ADB_SERVER_VERSION 37
class atransport;
struct usb_handle;
@@ -116,29 +116,6 @@
kCsUnauthorized,
};
-/* A listener is an entity which binds to a local port
-** and, upon receiving a connection on that port, creates
-** an asocket to connect the new local connection to a
-** specific remote service.
-**
-** TODO: some listeners read from the new connection to
-** determine what exact service to connect to on the far
-** side.
-*/
-struct alistener
-{
- alistener *next;
- alistener *prev;
-
- fdevent fde;
- int fd;
-
- char *local_name;
- char *connect_to;
- atransport *transport;
- adisconnect disconnect;
-};
-
void print_packet(const char *label, apacket *p);
@@ -211,7 +188,7 @@
void local_init(int port);
-void local_connect(int port);
+bool local_connect(int port);
int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error);
// USB host/client interface.
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
index 1ffab09..215bbe6 100644
--- a/adb/adb_auth.cpp
+++ b/adb/adb_auth.cpp
@@ -72,19 +72,23 @@
void send_auth_publickey(atransport *t)
{
D("Calling send_auth_publickey");
- apacket *p = get_apacket();
- int ret;
-
- ret = adb_auth_get_userkey(p->data, MAX_PAYLOAD_V1);
- if (!ret) {
+ std::string key = adb_auth_get_userkey();
+ if (key.empty()) {
D("Failed to get user public key");
- put_apacket(p);
return;
}
+ if (key.size() >= MAX_PAYLOAD_V1) {
+ D("User public key too large (%zu B)", key.size());
+ return;
+ }
+
+ apacket* p = get_apacket();
+ memcpy(p->data, key.c_str(), key.size() + 1);
+
p->msg.command = A_AUTH;
p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
- p->msg.data_length = ret;
+ p->msg.data_length = key.size();
send_packet(p, t);
}
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index a13604a..6363bb4 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -41,11 +41,17 @@
int adb_auth_sign(void *key, const unsigned char* token, size_t token_size,
unsigned char* sig);
void *adb_auth_nextkey(void *current);
-int adb_auth_get_userkey(unsigned char *data, size_t len);
+std::string adb_auth_get_userkey();
-static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; }
-static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; }
-static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { }
+static inline int adb_auth_generate_token(void *token, size_t token_size) {
+ return 0;
+}
+static inline int adb_auth_verify(void *token, size_t token_size,
+ void *sig, int siglen) {
+ return 0;
+}
+static inline void adb_auth_confirm_key(unsigned char *data, size_t len,
+ atransport *t) {}
#else // !ADB_HOST
@@ -54,12 +60,13 @@
return 0;
}
static inline void *adb_auth_nextkey(void *current) { return NULL; }
-static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return 0; }
+static inline std::string adb_auth_get_userkey() { return ""; }
void adbd_auth_init(void);
void adbd_cloexec_auth_socket();
int adb_auth_generate_token(void *token, size_t token_size);
-int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen);
+int adb_auth_verify(uint8_t* token, size_t token_size,
+ uint8_t* sig, int siglen);
void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t);
#endif // ADB_HOST
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index 128c3df..415ab8e 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -23,10 +23,14 @@
#include <stdio.h>
#include <string.h>
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+#include <crypto_utils/android_pubkey.h>
+
#include "cutils/list.h"
#include "cutils/sockets.h"
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
#include "adb.h"
#include "fdevent.h"
@@ -34,7 +38,7 @@
struct adb_public_key {
struct listnode node;
- RSAPublicKey key;
+ RSA* key;
};
static const char *key_paths[] = {
@@ -66,9 +70,8 @@
}
while (fgets(buf, sizeof(buf), f)) {
- /* Allocate 4 extra bytes to decode the base64 data in-place */
auto key = reinterpret_cast<adb_public_key*>(
- calloc(1, sizeof(adb_public_key) + 4));
+ calloc(1, sizeof(adb_public_key)));
if (key == nullptr) {
D("Can't malloc key");
break;
@@ -78,15 +81,18 @@
if (sep)
*sep = '\0';
- ret = __b64_pton(buf, (u_char *)&key->key, sizeof(key->key) + 4);
- if (ret != sizeof(key->key)) {
+ // b64_pton requires one additional byte in the target buffer for
+ // decoding to succeed. See http://b/28035006 for details.
+ uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+ ret = __b64_pton(buf, keybuf, sizeof(keybuf));
+ if (ret != ANDROID_PUBKEY_ENCODED_SIZE) {
D("%s: Invalid base64 data ret=%d", file, ret);
free(key);
continue;
}
- if (key->key.len != RSANUMWORDS) {
- D("%s: Invalid key len %d", file, key->key.len);
+ if (!android_pubkey_decode(keybuf, ret, &key->key)) {
+ D("%s: Failed to parse key", file);
free(key);
continue;
}
@@ -104,7 +110,9 @@
while (!list_empty(list)) {
item = list_head(list);
list_remove(item);
- free(node_to_item(item, struct adb_public_key, node));
+ adb_public_key* key = node_to_item(item, struct adb_public_key, node);
+ RSA_free(key->key);
+ free(key);
}
}
@@ -139,20 +147,17 @@
return ret * token_size;
}
-int adb_auth_verify(uint8_t* token, uint8_t* sig, int siglen)
+int adb_auth_verify(uint8_t* token, size_t token_size, uint8_t* sig, int siglen)
{
struct listnode *item;
struct listnode key_list;
int ret = 0;
- if (siglen != RSANUMBYTES)
- return 0;
-
load_keys(&key_list);
list_for_each(item, &key_list) {
adb_public_key* key = node_to_item(item, struct adb_public_key, node);
- ret = RSA_verify(&key->key, sig, siglen, token, SHA_DIGEST_SIZE);
+ ret = RSA_verify(NID_sha1, token, token_size, sig, siglen, key->key);
if (ret)
break;
}
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 7b6671d..dff874f 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -26,27 +26,20 @@
#include "adb.h"
-/* HACK: we need the RSAPublicKey struct
- * but RSA_verify conflits with openssl */
-#define RSA_verify RSA_verify_mincrypt
-#include "mincrypt/rsa.h"
-#undef RSA_verify
-
#include <android-base/errors.h>
+#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
#include <cutils/list.h>
+#include <openssl/base64.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
-#if defined(OPENSSL_IS_BORINGSSL)
-#include <openssl/base64.h>
-#endif
-
#define ANDROID_PATH ".android"
#define ADB_KEY_FILE "adbkey"
@@ -58,154 +51,52 @@
static struct listnode key_list;
-/* Convert OpenSSL RSA private key to android pre-computed RSAPublicKey format */
-static int RSA_to_RSAPublicKey(RSA *rsa, RSAPublicKey *pkey)
-{
- int ret = 1;
- unsigned int i;
-
- BN_CTX* ctx = BN_CTX_new();
- BIGNUM* r32 = BN_new();
- BIGNUM* rr = BN_new();
- BIGNUM* r = BN_new();
- BIGNUM* rem = BN_new();
- BIGNUM* n = BN_new();
- BIGNUM* n0inv = BN_new();
-
- if (RSA_size(rsa) != RSANUMBYTES) {
- ret = 0;
- goto out;
- }
-
- BN_set_bit(r32, 32);
- BN_copy(n, rsa->n);
- BN_set_bit(r, RSANUMWORDS * 32);
- BN_mod_sqr(rr, r, n, ctx);
- BN_div(NULL, rem, n, r32, ctx);
- BN_mod_inverse(n0inv, rem, r32, ctx);
-
- pkey->len = RSANUMWORDS;
- pkey->n0inv = 0 - BN_get_word(n0inv);
- for (i = 0; i < RSANUMWORDS; i++) {
- BN_div(rr, rem, rr, r32, ctx);
- pkey->rr[i] = BN_get_word(rem);
- BN_div(n, rem, n, r32, ctx);
- pkey->n[i] = BN_get_word(rem);
- }
- pkey->exponent = BN_get_word(rsa->e);
-
-out:
- BN_free(n0inv);
- BN_free(n);
- BN_free(rem);
- BN_free(r);
- BN_free(rr);
- BN_free(r32);
- BN_CTX_free(ctx);
-
- return ret;
-}
-
-static void get_user_info(char *buf, size_t len)
-{
- char hostname[1024], username[1024];
- int ret = -1;
-
- if (getenv("HOSTNAME") != NULL) {
- strncpy(hostname, getenv("HOSTNAME"), sizeof(hostname));
- hostname[sizeof(hostname)-1] = '\0';
- ret = 0;
- }
-
-#ifndef _WIN32
- if (ret < 0)
- ret = gethostname(hostname, sizeof(hostname));
+static std::string get_user_info() {
+ std::string hostname;
+ if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
+#if !defined(_WIN32)
+ char buf[64];
+ if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
#endif
- if (ret < 0)
- strcpy(hostname, "unknown");
+ if (hostname.empty()) hostname = "unknown";
- ret = -1;
-
- if (getenv("LOGNAME") != NULL) {
- strncpy(username, getenv("LOGNAME"), sizeof(username));
- username[sizeof(username)-1] = '\0';
- ret = 0;
- }
-
+ std::string username;
+ if (getenv("LOGNAME")) username = getenv("LOGNAME");
#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
- if (ret < 0)
- ret = getlogin_r(username, sizeof(username));
+ if (username.empty() && getlogin()) username = getlogin();
#endif
- if (ret < 0)
- strcpy(username, "unknown");
+ if (username.empty()) hostname = "unknown";
- ret = snprintf(buf, len, " %s@%s", username, hostname);
- if (ret >= (signed)len)
- buf[len - 1] = '\0';
+ return " " + username + "@" + hostname;
}
-static int write_public_keyfile(RSA *private_key, const char *private_key_path)
-{
- RSAPublicKey pkey;
- FILE *outfile = NULL;
- char path[PATH_MAX], info[MAX_PAYLOAD_V1];
- uint8_t* encoded = nullptr;
- size_t encoded_length;
- int ret = 0;
-
- if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
- (int)sizeof(path)) {
- D("Path too long while writing public key");
- return 0;
+static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
+ uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+ if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
+ LOG(ERROR) << "Failed to convert to public key";
+ return false;
}
- if (!RSA_to_RSAPublicKey(private_key, &pkey)) {
- D("Failed to convert to publickey");
- return 0;
+ size_t base64_key_length;
+ if (!EVP_EncodedLength(&base64_key_length, sizeof(binary_key_data))) {
+ LOG(ERROR) << "Public key too large to base64 encode";
+ return false;
}
- outfile = fopen(path, "w");
- if (!outfile) {
- D("Failed to open '%s'", path);
- return 0;
+ std::string content;
+ content.resize(base64_key_length);
+ base64_key_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(&content[0]), binary_key_data,
+ sizeof(binary_key_data));
+
+ content += get_user_info();
+
+ std::string path(private_key_path + ".pub");
+ if (!android::base::WriteStringToFile(content, path)) {
+ PLOG(ERROR) << "Failed to write public key to '" << path << "'";
+ return false;
}
- D("Writing public key to '%s'", path);
-
-#if defined(OPENSSL_IS_BORINGSSL)
- if (!EVP_EncodedLength(&encoded_length, sizeof(pkey))) {
- D("Public key too large to base64 encode");
- goto out;
- }
-#else
- /* While we switch from OpenSSL to BoringSSL we have to implement
- * |EVP_EncodedLength| here. */
- encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
-#endif
-
- encoded = new uint8_t[encoded_length];
- if (encoded == nullptr) {
- D("Allocation failure");
- goto out;
- }
-
- encoded_length = EVP_EncodeBlock(encoded, (uint8_t*) &pkey, sizeof(pkey));
- get_user_info(info, sizeof(info));
-
- if (fwrite(encoded, encoded_length, 1, outfile) != 1 ||
- fwrite(info, strlen(info), 1, outfile) != 1) {
- D("Write error while writing public key");
- goto out;
- }
-
- ret = 1;
-
- out:
- if (outfile != NULL) {
- fclose(outfile);
- }
- delete[] encoded;
- return ret;
+ return true;
}
static int generate_key(const char *file)
@@ -385,39 +276,21 @@
return NULL;
}
-int adb_auth_get_userkey(unsigned char *data, size_t len)
-{
+std::string adb_auth_get_userkey() {
char path[PATH_MAX];
int ret = get_user_keyfilepath(path, sizeof(path) - 4);
if (ret < 0 || ret >= (signed)(sizeof(path) - 4)) {
D("Error getting user key filename");
- return 0;
+ return "";
}
strcat(path, ".pub");
- // TODO(danalbert): ReadFileToString
- // Note that on Windows, load_file() does not do CR/LF translation, but
- // ReadFileToString() uses the C Runtime which uses CR/LF translation by
- // default (by is overridable with _setmode()).
- unsigned size;
- char* file_data = reinterpret_cast<char*>(load_file(path, &size));
- if (file_data == nullptr) {
+ std::string content;
+ if (!android::base::ReadFileToString(path, &content)) {
D("Can't load '%s'", path);
- return 0;
+ return "";
}
-
- if (len < (size_t)(size + 1)) {
- D("%s: Content too large ret=%d", path, size);
- free(file_data);
- return 0;
- }
-
- memcpy(data, file_data, size);
- free(file_data);
- file_data = nullptr;
- data[size] = '\0';
-
- return size + 1;
+ return content;
}
int adb_auth_keygen(const char* filename) {
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 21a82e8..611b239 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -37,7 +37,13 @@
// fds far from the range that open() returns. But all of that might defeat the
// purpose of the tests.
-TEST(io, ReadFdExactly_whole) {
+#if defined(_WIN32)
+#define POSIX_TEST(x,y) TEST(DISABLED_ ## x,y)
+#else
+#define POSIX_TEST TEST
+#endif
+
+POSIX_TEST(io, ReadFdExactly_whole) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -51,7 +57,7 @@
EXPECT_STREQ(expected, buf);
}
-TEST(io, ReadFdExactly_eof) {
+POSIX_TEST(io, ReadFdExactly_eof) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -65,7 +71,7 @@
EXPECT_EQ(0, errno) << strerror(errno);
}
-TEST(io, ReadFdExactly_partial) {
+POSIX_TEST(io, ReadFdExactly_partial) {
const char input[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -82,7 +88,7 @@
EXPECT_STREQ(expected.c_str(), buf);
}
-TEST(io, WriteFdExactly_whole) {
+POSIX_TEST(io, WriteFdExactly_whole) {
const char expected[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -97,7 +103,7 @@
EXPECT_STREQ(expected, s.c_str());
}
-TEST(io, WriteFdExactly_partial) {
+POSIX_TEST(io, WriteFdExactly_partial) {
const char buf[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -114,7 +120,7 @@
EXPECT_EQ(expected, s);
}
-TEST(io, WriteFdExactly_ENOSPC) {
+POSIX_TEST(io, WriteFdExactly_ENOSPC) {
int fd = open("/dev/full", O_WRONLY);
ASSERT_NE(-1, fd);
@@ -123,7 +129,7 @@
ASSERT_EQ(ENOSPC, errno);
}
-TEST(io, WriteFdExactly_string) {
+POSIX_TEST(io, WriteFdExactly_string) {
const char str[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
@@ -137,7 +143,7 @@
EXPECT_STREQ(str, s.c_str());
}
-TEST(io, WriteFdFmt) {
+POSIX_TEST(io, WriteFdFmt) {
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index e8c2338..f54603c 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -20,18 +20,55 @@
#include <stdlib.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/sockets.h>
#include "sysdeps.h"
#include "transport.h"
-int gListenAll = 0; /* Not static because it is used in commandline.c. */
+// Not static because it is used in commandline.c.
+int gListenAll = 0;
-static alistener listener_list = {
- .next = &listener_list,
- .prev = &listener_list,
+// A listener is an entity which binds to a local port and, upon receiving a connection on that
+// port, creates an asocket to connect the new local connection to a specific remote service.
+//
+// TODO: some listeners read from the new connection to determine what exact service to connect to
+// on the far side.
+class alistener {
+ public:
+ alistener(const std::string& _local_name, const std::string& _connect_to);
+ ~alistener();
+
+ fdevent fde;
+ int fd = -1;
+
+ std::string local_name;
+ std::string connect_to;
+ atransport* transport = nullptr;
+ adisconnect disconnect;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(alistener);
};
+alistener::alistener(const std::string& _local_name, const std::string& _connect_to)
+ : local_name(_local_name), connect_to(_connect_to) {
+}
+
+alistener::~alistener() {
+ // Closes the corresponding fd.
+ fdevent_remove(&fde);
+
+ if (transport) {
+ transport->RemoveDisconnect(&disconnect);
+ }
+}
+
+// listener_list retains ownership of all created alistener objects. Removing an alistener from
+// this list will cause it to be deleted.
+typedef std::list<std::unique_ptr<alistener>> ListenerList;
+static ListenerList& listener_list = *new ListenerList();
+
static void ss_listener_event_func(int _fd, unsigned ev, void *_l) {
if (ev & FDE_READ) {
sockaddr_storage ss;
@@ -73,7 +110,7 @@
s = create_local_socket(fd);
if (s) {
s->transport = listener->transport;
- connect_to_remote(s, listener->connect_to);
+ connect_to_remote(s, listener->connect_to.c_str());
return;
}
@@ -81,66 +118,63 @@
}
}
-static void free_listener(alistener* l)
-{
- if (l->next) {
- l->next->prev = l->prev;
- l->prev->next = l->next;
- l->next = l->prev = l;
- }
-
- // closes the corresponding fd
- fdevent_remove(&l->fde);
-
- if (l->local_name)
- free((char*)l->local_name);
-
- if (l->connect_to)
- free((char*)l->connect_to);
-
- if (l->transport) {
- l->transport->RemoveDisconnect(&l->disconnect);
- }
- free(l);
-}
-
+// Called as a transport disconnect function. |arg| is the raw alistener*.
static void listener_disconnect(void* arg, atransport*) {
- alistener* listener = reinterpret_cast<alistener*>(arg);
- listener->transport = nullptr;
- free_listener(listener);
-}
-
-static int local_name_to_fd(const char* name, std::string* error) {
- if (!strncmp("tcp:", name, 4)) {
- int port = atoi(name + 4);
- if (gListenAll > 0) {
- return network_inaddr_any_server(port, SOCK_STREAM, error);
- } else {
- return network_loopback_server(port, SOCK_STREAM, error);
+ for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+ if (iter->get() == arg) {
+ (*iter)->transport = nullptr;
+ listener_list.erase(iter);
+ return;
}
}
+}
+
+int local_name_to_fd(alistener* listener, int* resolved_tcp_port, std::string* error) {
+ if (android::base::StartsWith(listener->local_name, "tcp:")) {
+ int requested_port = atoi(&listener->local_name[4]);
+ int sock = -1;
+ if (gListenAll > 0) {
+ sock = network_inaddr_any_server(requested_port, SOCK_STREAM, error);
+ } else {
+ sock = network_loopback_server(requested_port, SOCK_STREAM, error);
+ }
+
+ // If the caller requested port 0, update the listener name with the resolved port.
+ if (sock >= 0 && requested_port == 0) {
+ int local_port = adb_socket_get_local_port(sock);
+ if (local_port > 0) {
+ listener->local_name = android::base::StringPrintf("tcp:%d", local_port);
+ if (resolved_tcp_port != nullptr) {
+ *resolved_tcp_port = local_port;
+ }
+ }
+ }
+
+ return sock;
+ }
#if !defined(_WIN32) // No Unix-domain sockets on Windows.
- // It's nonsensical to support the "reserved" space on the adb host side
- if (!strncmp(name, "local:", 6)) {
- return network_local_server(name + 6,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
- } else if (!strncmp(name, "localabstract:", 14)) {
- return network_local_server(name + 14,
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM, error);
- } else if (!strncmp(name, "localfilesystem:", 16)) {
- return network_local_server(name + 16,
- ANDROID_SOCKET_NAMESPACE_FILESYSTEM, SOCK_STREAM, error);
+ // It's nonsensical to support the "reserved" space on the adb host side.
+ if (android::base::StartsWith(listener->local_name, "local:")) {
+ return network_local_server(&listener->local_name[6], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+ SOCK_STREAM, error);
+ } else if (android::base::StartsWith(listener->local_name, "localabstract:")) {
+ return network_local_server(&listener->local_name[14], ANDROID_SOCKET_NAMESPACE_ABSTRACT,
+ SOCK_STREAM, error);
+ } else if (android::base::StartsWith(listener->local_name, "localfilesystem:")) {
+ return network_local_server(&listener->local_name[16], ANDROID_SOCKET_NAMESPACE_FILESYSTEM,
+ SOCK_STREAM, error);
}
#endif
- *error = android::base::StringPrintf("unknown local portname '%s'", name);
+ *error = android::base::StringPrintf("unknown local portname '%s'",
+ listener->local_name.c_str());
return -1;
}
// Write the list of current listeners (network redirections) into a string.
std::string format_listeners() {
std::string result;
- for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+ for (auto& l : listener_list) {
// Ignore special listeners like those for *smartsocket*
if (l->connect_to[0] == '*') {
continue;
@@ -149,65 +183,51 @@
// Entries from "adb reverse" have no serial.
android::base::StringAppendF(&result, "%s %s %s\n",
l->transport->serial ? l->transport->serial : "(reverse)",
- l->local_name, l->connect_to);
+ l->local_name.c_str(), l->connect_to.c_str());
}
return result;
}
-InstallStatus remove_listener(const char *local_name, atransport* transport) {
- alistener *l;
-
- for (l = listener_list.next; l != &listener_list; l = l->next) {
- if (!strcmp(local_name, l->local_name)) {
- free_listener(l);
+InstallStatus remove_listener(const char* local_name, atransport* transport) {
+ for (auto iter = listener_list.begin(); iter != listener_list.end(); ++iter) {
+ if (local_name == (*iter)->local_name) {
+ listener_list.erase(iter);
return INSTALL_STATUS_OK;
}
}
return INSTALL_STATUS_LISTENER_NOT_FOUND;
}
-void remove_all_listeners(void)
-{
- alistener *l, *l_next;
- for (l = listener_list.next; l != &listener_list; l = l_next) {
- l_next = l->next;
+void remove_all_listeners() {
+ auto iter = listener_list.begin();
+ while (iter != listener_list.end()) {
// Never remove smart sockets.
- if (l->connect_to[0] == '*')
- continue;
- free_listener(l);
+ if ((*iter)->connect_to[0] == '*') {
+ ++iter;
+ } else {
+ iter = listener_list.erase(iter);
+ }
}
}
-InstallStatus install_listener(const std::string& local_name,
- const char *connect_to,
- atransport* transport,
- int no_rebind,
- std::string* error)
-{
- for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+ atransport* transport, int no_rebind, int* resolved_tcp_port,
+ std::string* error) {
+ for (auto& l : listener_list) {
if (local_name == l->local_name) {
- char* cto;
-
- /* can't repurpose a smartsocket */
+ // Can't repurpose a smartsocket.
if(l->connect_to[0] == '*') {
*error = "cannot repurpose smartsocket";
return INSTALL_STATUS_INTERNAL_ERROR;
}
- /* can't repurpose a listener if 'no_rebind' is true */
+ // Can't repurpose a listener if 'no_rebind' is true.
if (no_rebind) {
*error = "cannot rebind";
return INSTALL_STATUS_CANNOT_REBIND;
}
- cto = strdup(connect_to);
- if(cto == 0) {
- *error = "cannot duplicate string";
- return INSTALL_STATUS_INTERNAL_ERROR;
- }
-
- free((void*) l->connect_to);
- l->connect_to = cto;
+ l->connect_to = connect_to;
if (l->transport != transport) {
l->transport->RemoveDisconnect(&l->disconnect);
l->transport = transport;
@@ -217,54 +237,29 @@
}
}
- alistener* listener = reinterpret_cast<alistener*>(
- calloc(1, sizeof(alistener)));
- if (listener == nullptr) {
- goto nomem;
- }
+ std::unique_ptr<alistener> listener(new alistener(local_name, connect_to));
- listener->local_name = strdup(local_name.c_str());
- if (listener->local_name == nullptr) {
- goto nomem;
- }
-
- listener->connect_to = strdup(connect_to);
- if (listener->connect_to == nullptr) {
- goto nomem;
- }
-
- listener->fd = local_name_to_fd(listener->local_name, error);
+ listener->fd = local_name_to_fd(listener.get(), resolved_tcp_port, error);
if (listener->fd < 0) {
- free(listener->local_name);
- free(listener->connect_to);
- free(listener);
return INSTALL_STATUS_CANNOT_BIND;
}
close_on_exec(listener->fd);
- if (!strcmp(listener->connect_to, "*smartsocket*")) {
- fdevent_install(&listener->fde, listener->fd, ss_listener_event_func,
- listener);
+ if (listener->connect_to == "*smartsocket*") {
+ fdevent_install(&listener->fde, listener->fd, ss_listener_event_func, listener.get());
} else {
- fdevent_install(&listener->fde, listener->fd, listener_event_func,
- listener);
+ fdevent_install(&listener->fde, listener->fd, listener_event_func, listener.get());
}
fdevent_set(&listener->fde, FDE_READ);
- listener->next = &listener_list;
- listener->prev = listener_list.prev;
- listener->next->prev = listener;
- listener->prev->next = listener;
listener->transport = transport;
if (transport) {
- listener->disconnect.opaque = listener;
+ listener->disconnect.opaque = listener.get();
listener->disconnect.func = listener_disconnect;
transport->AddDisconnect(&listener->disconnect);
}
- return INSTALL_STATUS_OK;
-nomem:
- fatal("cannot allocate listener");
- return INSTALL_STATUS_INTERNAL_ERROR;
+ listener_list.push_back(std::move(listener));
+ return INSTALL_STATUS_OK;
}
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index fa98eed..8eba00a 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -21,6 +21,8 @@
#include <string>
+#include <android-base/macros.h>
+
// error/status codes for install_listener.
enum InstallStatus {
INSTALL_STATUS_OK = 0,
@@ -30,10 +32,8 @@
INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
};
-InstallStatus install_listener(const std::string& local_name,
- const char* connect_to,
- atransport* transport,
- int no_rebind,
+InstallStatus install_listener(const std::string& local_name, const char* connect_to,
+ atransport* transport, int no_rebind, int* resolved_tcp_port,
std::string* error);
std::string format_listeners();
diff --git a/adb/adb_listeners_test.cpp b/adb/adb_listeners_test.cpp
new file mode 100644
index 0000000..b697769
--- /dev/null
+++ b/adb/adb_listeners_test.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2016 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 "adb_listeners.h"
+
+#include <gtest/gtest.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "fdevent.h"
+#include "sysdeps.h"
+#include "transport.h"
+
+// Returns true if the given listener is present in format_listeners(). Empty parameters will
+// be ignored.
+static bool listener_is_installed(const std::string& serial, const std::string& source,
+ const std::string& dest) {
+ // format_listeners() gives lines of "<serial> <source> <dest>\n".
+ for (const std::string& line : android::base::Split(format_listeners(), "\n")) {
+ std::vector<std::string> info = android::base::Split(line, " ");
+ if (info.size() == 3 &&
+ (serial.empty() || info[0] == serial) &&
+ (source.empty() || info[1] == source) &&
+ (dest.empty() || info[2] == dest)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+class AdbListenersTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ // We don't need an fdevent loop, but adding/removing listeners must be done from the
+ // fdevent thread if one exists. Since previously run tests may have created an fdevent
+ // thread, we need to reset to prevent the thread check.
+ fdevent_reset();
+ }
+
+ void TearDown() override {
+ // Clean up any listeners that may have been installed.
+ remove_all_listeners();
+
+ // Make sure we didn't leave any dangling events.
+ ASSERT_EQ(0u, fdevent_installed_count());
+ }
+
+ protected:
+ atransport transport_;
+};
+
+TEST_F(AdbListenersTest, test_install_listener) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_rebind) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9001", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9001"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_no_rebind) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, true, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_CANNOT_REBIND,
+ install_listener("tcp:9000", "tcp:9001", &transport_, true, nullptr, &error));
+ ASSERT_FALSE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_install_listener_tcp_port_0) {
+ int port = 0;
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:0", "tcp:9000", &transport_, true, &port, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_TRUE(listener_is_installed("", android::base::StringPrintf("tcp:%d", port), "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_listener) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK, remove_listener("tcp:9000", &transport_));
+ ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_remove_nonexistent_listener) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_LISTENER_NOT_FOUND, remove_listener("tcp:1", &transport_));
+ ASSERT_TRUE(listener_is_installed("", "tcp:9000", "tcp:9000"));
+}
+
+TEST_F(AdbListenersTest, test_remove_all_listeners) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ remove_all_listeners();
+ ASSERT_TRUE(format_listeners().empty());
+}
+
+TEST_F(AdbListenersTest, test_transport_disconnect) {
+ std::string error;
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9000", "tcp:9000", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ ASSERT_EQ(INSTALL_STATUS_OK,
+ install_listener("tcp:9001", "tcp:9001", &transport_, false, nullptr, &error));
+ ASSERT_TRUE(error.empty());
+
+ transport_.RunDisconnects();
+ ASSERT_TRUE(format_listeners().empty());
+}
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index d50f947..5206a99 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -41,7 +41,7 @@
};
#define VLOG_IS_ON(TAG) \
- ((adb_trace_mask & (1 << TAG)) != 0)
+ ((adb_trace_mask & (1 << (TAG))) != 0)
#define VLOG(TAG) \
if (LIKELY(!VLOG_IS_ON(TAG))) \
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 0645122..31ec8af 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -27,6 +27,7 @@
#include <algorithm>
#include <android-base/logging.h>
+#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -239,6 +240,29 @@
}
#endif
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+ std::string* error) {
+ if (android::base::StartsWith(source, "tcp:")) {
+ // The source port may be 0 to allow the system to select an open port.
+ int port;
+ if (!android::base::ParseInt(&source[4], &port) || port < 0) {
+ *error = android::base::StringPrintf("Invalid source port: '%s'", &source[4]);
+ return false;
+ }
+ }
+
+ if (android::base::StartsWith(dest, "tcp:")) {
+ // The destination port must be > 0.
+ int port;
+ if (!android::base::ParseInt(&dest[4], &port) || port <= 0) {
+ *error = android::base::StringPrintf("Invalid destination port: '%s'", &dest[4]);
+ return false;
+ }
+ }
+
+ return true;
+}
+
std::string adb_get_homedir_path(bool check_env_first) {
#ifdef _WIN32
if (check_env_first) {
@@ -265,4 +289,3 @@
return {};
#endif
}
-
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index cd6717d..f6b4b26 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -50,6 +50,13 @@
extern int adb_close(int fd);
+// Given forward/reverse targets, returns true if they look sane. If an error is found, fills
+// |error| and returns false.
+// Currently this only checks "tcp:" targets. Additional checking could be added for other targets
+// if needed.
+bool forward_targets_are_valid(const std::string& source, const std::string& dest,
+ std::string* error);
+
// Helper to automatically close an FD when it goes out of scope.
struct AdbCloser {
static void Close(int fd) {
@@ -59,42 +66,4 @@
using unique_fd = android::base::unique_fd_impl<AdbCloser>;
-class ScopedFd {
- public:
- ScopedFd() {
- }
-
- ~ScopedFd() {
- Reset();
- }
-
- void Reset(int fd = -1) {
- if (fd != fd_) {
- if (valid()) {
- adb_close(fd_);
- }
- fd_ = fd;
- }
- }
-
- int Release() {
- int temp = fd_;
- fd_ = -1;
- return temp;
- }
-
- bool valid() const {
- return fd_ >= 0;
- }
-
- int fd() const {
- return fd_;
- }
-
- private:
- int fd_ = -1;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedFd);
-};
-
#endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index f1ebaa1..4cac485 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -52,18 +52,6 @@
ASSERT_TRUE(directory_exists(profiles_dir));
- // On modern (English?) Windows, this is a directory symbolic link to
- // C:\ProgramData. Symbolic links are rare on Windows and the user requires
- // a special permission (by default granted to Administrative users) to
- // create symbolic links.
- ASSERT_FALSE(directory_exists(subdir(profiles_dir, "All Users")));
-
- // On modern (English?) Windows, this is a directory junction to
- // C:\Users\Default. Junctions are used throughout user profile directories
- // for backwards compatibility and they don't require any special permissions
- // to create.
- ASSERT_FALSE(directory_exists(subdir(profiles_dir, "Default User")));
-
ASSERT_FALSE(directory_exists(subdir(profiles_dir, "does-not-exist")));
#else
ASSERT_TRUE(directory_exists("/proc"));
@@ -72,6 +60,28 @@
#endif
}
+#if defined(_WIN32)
+TEST(adb_utils, directory_exists_win32_symlink_junction) {
+ char profiles_dir[MAX_PATH];
+ DWORD cch = arraysize(profiles_dir);
+
+ // On typical Windows 7, returns C:\Users
+ ASSERT_TRUE(GetProfilesDirectoryA(profiles_dir, &cch));
+
+ // On modern (English?) Windows, this is a directory symbolic link to
+ // C:\ProgramData. Symbolic links are rare on Windows and the user requires
+ // a special permission (by default granted to Administrative users) to
+ // create symbolic links.
+ EXPECT_FALSE(directory_exists(subdir(profiles_dir, "All Users")));
+
+ // On modern (English?) Windows, this is a directory junction to
+ // C:\Users\Default. Junctions are used throughout user profile directories
+ // for backwards compatibility and they don't require any special permissions
+ // to create.
+ EXPECT_FALSE(directory_exists(subdir(profiles_dir, "Default User")));
+}
+#endif
+
TEST(adb_utils, escape_arg) {
ASSERT_EQ(R"('')", escape_arg(""));
@@ -111,16 +121,22 @@
EXPECT_EQ("/system/bin", adb_dirname("/system/bin/sh/"));
}
-void test_mkdirs(const std::string basepath) {
+void test_mkdirs(const std::string& basepath) {
// Test creating a directory hierarchy.
- EXPECT_TRUE(mkdirs(basepath));
+ ASSERT_TRUE(mkdirs(basepath));
// Test finding an existing directory hierarchy.
- EXPECT_TRUE(mkdirs(basepath));
+ ASSERT_TRUE(mkdirs(basepath));
+ // Test mkdirs on an existing hierarchy with a trailing slash.
+ ASSERT_TRUE(mkdirs(basepath + '/'));
+#if defined(_WIN32)
+ ASSERT_TRUE(mkdirs(basepath + '\\'));
+#endif
+
const std::string filepath = basepath + "/file";
// Verify that the hierarchy was created by trying to create a file in it.
- EXPECT_NE(-1, adb_creat(filepath.c_str(), 0600));
+ ASSERT_NE(-1, adb_creat(filepath.c_str(), 0600));
// If a file exists where we want a directory, the operation should fail.
- EXPECT_FALSE(mkdirs(filepath));
+ ASSERT_FALSE(mkdirs(filepath));
}
TEST(adb_utils, mkdirs) {
@@ -149,3 +165,24 @@
ASSERT_EQ(0, adb_close(fd));
}
#endif
+
+TEST(adb_utils, test_forward_targets_are_valid) {
+ std::string error;
+
+ // Source port can be >= 0.
+ EXPECT_FALSE(forward_targets_are_valid("tcp:-1", "tcp:9000", &error));
+ EXPECT_TRUE(forward_targets_are_valid("tcp:0", "tcp:9000", &error));
+ EXPECT_TRUE(forward_targets_are_valid("tcp:8000", "tcp:9000", &error));
+
+ // Destination port must be >0.
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:-1", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:0", &error));
+
+ // Port must be a number.
+ EXPECT_FALSE(forward_targets_are_valid("tcp:", "tcp:9000", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:a", "tcp:9000", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:22x", "tcp:9000", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:a", &error));
+ EXPECT_FALSE(forward_targets_are_valid("tcp:8000", "tcp:22x", &error));
+}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index ba4737f..894ebd1 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -115,7 +115,7 @@
std::string error;
std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
- if (install_listener(local_name, "*smartsocket*", nullptr, 0, &error)) {
+ if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
fatal("could not install *smartsocket* listener: %s", error.c_str());
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 0685b70..74a3451 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -35,6 +35,7 @@
#include <string>
#include <vector>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -129,7 +130,7 @@
" <serial> \" \" <local> \" \" <remote> \"\\n\"\n"
" adb forward <local> <remote> - forward socket connections\n"
" forward specs are one of: \n"
- " tcp:<port>\n"
+ " tcp:<port> (<local> may be \"tcp:0\" to pick any open port)\n"
" localabstract:<unix domain socket name>\n"
" localreserved:<unix domain socket name>\n"
" localfilesystem:<unix domain socket name>\n"
@@ -143,7 +144,7 @@
" adb reverse --list - list all reverse socket connections from device\n"
" adb reverse <remote> <local> - reverse socket connections\n"
" reverse specs are one of:\n"
- " tcp:<port>\n"
+ " tcp:<port> (<remote> may be \"tcp:0\" to pick any open port)\n"
" localabstract:<unix domain socket name>\n"
" localreserved:<unix domain socket name>\n"
" localfilesystem:<unix domain socket name>\n"
@@ -882,47 +883,46 @@
* we hang up.
*/
static int adb_sideload_host(const char* fn) {
- unsigned sz;
- size_t xfer = 0;
- int status;
- int last_percent = -1;
- int opt = SIDELOAD_HOST_BLOCK_SIZE;
+ fprintf(stderr, "loading: '%s'...\n", fn);
- printf("loading: '%s'", fn);
- fflush(stdout);
- uint8_t* data = reinterpret_cast<uint8_t*>(load_file(fn, &sz));
- if (data == 0) {
- printf("\n");
- fprintf(stderr, "* cannot read '%s' *\n", fn);
+ std::string content;
+ if (!android::base::ReadFileToString(fn, &content)) {
+ fprintf(stderr, "failed: %s\n", strerror(errno));
return -1;
}
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(content.data());
+ unsigned sz = content.size();
+
+ fprintf(stderr, "connecting...\n");
std::string service =
android::base::StringPrintf("sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
std::string error;
- int fd = adb_connect(service, &error);
+ unique_fd fd(adb_connect(service, &error));
if (fd < 0) {
// Try falling back to the older sideload method. Maybe this
// is an older device that doesn't support sideload-host.
- printf("\n");
- status = adb_download_buffer("sideload", fn, data, sz, true);
- goto done;
+ fprintf(stderr, "falling back to older sideload method...\n");
+ return adb_download_buffer("sideload", fn, data, sz, true);
}
- opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
+ int opt = SIDELOAD_HOST_BLOCK_SIZE;
+ adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt));
+ size_t xfer = 0;
+ int last_percent = -1;
while (true) {
char buf[9];
if (!ReadFdExactly(fd, buf, 8)) {
fprintf(stderr, "* failed to read command: %s\n", strerror(errno));
- status = -1;
- goto done;
+ return -1;
}
buf[8] = '\0';
if (strcmp("DONEDONE", buf) == 0) {
- status = 0;
- break;
+ printf("\rTotal xfer: %.2fx%*s\n",
+ (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
+ return 0;
}
int block = strtol(buf, NULL, 10);
@@ -930,21 +930,19 @@
size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
if (offset >= sz) {
fprintf(stderr, "* attempt to read block %d past end\n", block);
- status = -1;
- goto done;
+ return -1;
}
- uint8_t* start = data + offset;
+ const uint8_t* start = data + offset;
size_t offset_end = offset + SIDELOAD_HOST_BLOCK_SIZE;
size_t to_write = SIDELOAD_HOST_BLOCK_SIZE;
if (offset_end > sz) {
to_write = sz - offset;
}
- if(!WriteFdExactly(fd, start, to_write)) {
+ if (!WriteFdExactly(fd, start, to_write)) {
adb_status(fd, &error);
fprintf(stderr,"* failed to write data '%s' *\n", error.c_str());
- status = -1;
- goto done;
+ return -1;
}
xfer += to_write;
@@ -961,13 +959,6 @@
last_percent = percent;
}
}
-
- printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, "");
-
- done:
- if (fd >= 0) adb_close(fd);
- free(data);
- return status;
}
/**
@@ -1078,10 +1069,9 @@
static bool adb_root(const char* command) {
std::string error;
- ScopedFd fd;
- fd.Reset(adb_connect(android::base::StringPrintf("%s:", command), &error));
- if (!fd.valid()) {
+ unique_fd fd(adb_connect(android::base::StringPrintf("%s:", command), &error));
+ if (fd < 0) {
fprintf(stderr, "adb: unable to connect for %s: %s\n", command, error.c_str());
return false;
}
@@ -1091,7 +1081,7 @@
char* cur = buf;
ssize_t bytes_left = sizeof(buf);
while (bytes_left > 0) {
- ssize_t bytes_read = adb_read(fd.fd(), cur, bytes_left);
+ ssize_t bytes_read = adb_read(fd, cur, bytes_left);
if (bytes_read == 0) {
break;
} else if (bytes_read < 0) {
@@ -1113,12 +1103,10 @@
return true;
}
- // Give adbd 500ms to kill itself, then wait-for-device for it to come back up.
- adb_sleep_ms(500);
- TransportType type;
- const char* serial;
- adb_get_transport(&type, &serial);
- return wait_for_device("wait-for-any", type, serial);
+ // Give adbd some time to kill itself and come back up.
+ // We can't use wait-for-device because devices (e.g. adb over network) might not come back.
+ adb_sleep_ms(3000);
+ return true;
}
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
@@ -1322,9 +1310,10 @@
return hint;
}
- // If there are any slashes in it, assume it's a relative path;
+ // If any of the OS_PATH_SEPARATORS is found, assume it's a relative path;
// make it absolute.
- if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) {
+ // NOLINT: Do not complain if OS_PATH_SEPARATORS has only one character.
+ if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) { // NOLINT
std::string cwd;
if (!getcwd(&cwd)) {
fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
@@ -1427,6 +1416,16 @@
#endif
}
+static bool _use_legacy_install() {
+ FeatureSet features;
+ std::string error;
+ if (!adb_get_feature_set(&features, &error)) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return true;
+ }
+ return !CanUseFeature(features, kFeatureCmd);
+}
+
int adb_commandline(int argc, const char **argv) {
int no_daemon = 0;
int is_daemon = 0;
@@ -1648,6 +1647,11 @@
else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
int exec_in = !strcmp(argv[0], "exec-in");
+ if (argc < 2) {
+ fprintf(stderr, "Usage: adb %s command\n", argv[0]);
+ return 1;
+ }
+
std::string cmd = "exec:";
cmd += argv[1];
argc -= 2;
@@ -1746,7 +1750,7 @@
}
}
- std::string cmd;
+ std::string cmd, error;
if (strcmp(argv[0], "--list") == 0) {
if (argc != 1) return usage();
return adb_query_command(host_prefix + ":list-forward");
@@ -1760,14 +1764,37 @@
} else if (strcmp(argv[0], "--no-rebind") == 0) {
// forward --no-rebind <local> <remote>
if (argc != 3) return usage();
- cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+ if (forward_targets_are_valid(argv[1], argv[2], &error)) {
+ cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
+ }
} else {
// forward <local> <remote>
if (argc != 2) return usage();
- cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+ if (forward_targets_are_valid(argv[0], argv[1], &error)) {
+ cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
+ }
}
- return adb_command(cmd) ? 0 : 1;
+ if (!error.empty()) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+
+ int fd = adb_connect(cmd, &error);
+ if (fd < 0 || !adb_status(fd, &error)) {
+ adb_close(fd);
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+
+ // Server or device may optionally return a resolved TCP port number.
+ std::string resolved_port;
+ if (ReadProtocolString(fd, &resolved_port, &error) && !resolved_port.empty()) {
+ printf("%s\n", resolved_port.c_str());
+ }
+
+ ReadOrderlyShutdown(fd);
+ return 0;
}
/* do_sync_*() commands */
else if (!strcmp(argv[0], "ls")) {
@@ -1794,17 +1821,10 @@
}
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
- FeatureSet features;
- std::string error;
- if (!adb_get_feature_set(&features, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
+ if (_use_legacy_install()) {
+ return install_app_legacy(transport_type, serial, argc, argv);
}
-
- if (CanUseFeature(features, kFeatureCmd)) {
- return install_app(transport_type, serial, argc, argv);
- }
- return install_app_legacy(transport_type, serial, argc, argv);
+ return install_app(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "install-multiple")) {
if (argc < 2) return usage();
@@ -1812,17 +1832,10 @@
}
else if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) return usage();
- FeatureSet features;
- std::string error;
- if (!adb_get_feature_set(&features, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
+ if (_use_legacy_install()) {
+ return uninstall_app_legacy(transport_type, serial, argc, argv);
}
-
- if (CanUseFeature(features, kFeatureCmd)) {
- return uninstall_app(transport_type, serial, argc, argv);
- }
- return uninstall_app_legacy(transport_type, serial, argc, argv);
+ return uninstall_app(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "sync")) {
std::string src;
@@ -1906,6 +1919,14 @@
else if (!strcmp(argv[0], "jdwp")) {
return adb_connect_command("jdwp");
}
+ else if (!strcmp(argv[0], "track-jdwp")) {
+ return adb_connect_command("track-jdwp");
+ }
+ else if (!strcmp(argv[0], "track-devices")) {
+ return adb_connect_command("host:track-devices");
+ }
+
+
/* "adb /?" is a common idiom under Windows */
else if (!strcmp(argv[0], "help") || !strcmp(argv[0], "/?")) {
help();
@@ -2028,7 +2049,6 @@
int i;
struct stat sb;
uint64_t total_size = 0;
-
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
int first_apk = -1;
@@ -2053,7 +2073,14 @@
return 1;
}
- std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
+ std::string install_cmd;
+ if (_use_legacy_install()) {
+ install_cmd = "exec:pm";
+ } else {
+ install_cmd = "exec:cmd package";
+ }
+
+ std::string cmd = android::base::StringPrintf("%s install-create -S %" PRIu64, install_cmd.c_str(), total_size);
for (i = 1; i < first_apk; i++) {
cmd += " " + escape_arg(argv[i]);
}
@@ -2095,8 +2122,8 @@
}
std::string cmd = android::base::StringPrintf(
- "exec:pm install-write -S %" PRIu64 " %d %d_%s -",
- static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
+ "%s install-write -S %" PRIu64 " %d %d_%s -",
+ install_cmd.c_str(), static_cast<uint64_t>(sb.st_size), session_id, i, adb_basename(file).c_str());
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
@@ -2131,8 +2158,8 @@
finalize_session:
// Commit session if we streamed everything okay; otherwise abandon
std::string service =
- android::base::StringPrintf("exec:pm install-%s %d",
- success ? "commit" : "abandon", session_id);
+ android::base::StringPrintf("%s install-%s %d",
+ install_cmd.c_str(), success ? "commit" : "abandon", session_id);
fd = adb_connect(service, &error);
if (fd < 0) {
fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 4721e2f..b54243e 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -28,10 +28,13 @@
#include <memory>
#include <android-base/logging.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <libminijail.h>
+#include <scoped_minijail.h>
#include "cutils/properties.h"
+#include "debuggerd/client.h"
#include "private/android_filesystem_config.h"
#include "selinux/android.h"
@@ -43,24 +46,15 @@
static const char* root_seclabel = nullptr;
-static void drop_capabilities_bounding_set_if_needed() {
-#ifdef ALLOW_ADBD_ROOT
+static void drop_capabilities_bounding_set_if_needed(struct minijail *j) {
+#if defined(ALLOW_ADBD_ROOT)
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "");
if (strcmp(value, "1") == 0) {
return;
}
#endif
- for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
- if (i == CAP_SETUID || i == CAP_SETGID) {
- // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
- continue;
- }
-
- if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
- PLOG(FATAL) << "Could not drop capabilities";
- }
- }
+ minijail_capbset_drop(j, CAP_TO_MASK(CAP_SETUID) | CAP_TO_MASK(CAP_SETGID));
}
static bool should_drop_privileges() {
@@ -107,8 +101,7 @@
}
static void drop_privileges(int server_port) {
- std::unique_ptr<minijail, void (*)(minijail*)> jail(minijail_new(),
- &minijail_destroy);
+ ScopedMinijail jail(minijail_new());
// Add extra groups:
// AID_ADB to access the USB driver
@@ -124,14 +117,12 @@
AID_INET, AID_NET_BT, AID_NET_BT_ADMIN,
AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
AID_READPROC};
- minijail_set_supplementary_gids(jail.get(),
- sizeof(groups) / sizeof(groups[0]),
- groups);
+ minijail_set_supplementary_gids(jail.get(), arraysize(groups), groups);
// Don't listen on a port (default 5037) if running in secure mode.
// Don't run as root if running in secure mode.
if (should_drop_privileges()) {
- drop_capabilities_bounding_set_if_needed();
+ drop_capabilities_bounding_set_if_needed(jail.get());
minijail_change_gid(jail.get(), AID_SHELL);
minijail_change_uid(jail.get(), AID_SHELL);
@@ -151,10 +142,8 @@
std::string error;
std::string local_name =
android::base::StringPrintf("tcp:%d", server_port);
- if (install_listener(local_name, "*smartsocket*", nullptr, 0,
- &error)) {
- LOG(FATAL) << "Could not install *smartsocket* listener: "
- << error;
+ if (install_listener(local_name, "*smartsocket*", nullptr, 0, nullptr, &error)) {
+ LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
}
}
}
@@ -258,6 +247,7 @@
close_stdin();
+ debuggerd_init(nullptr);
adb_trace_init(argv);
D("Handling main()");
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 902548e..04cd865 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -55,7 +55,7 @@
fdevent* fde;
adb_pollfd pollfd;
- PollNode(fdevent* fde) : fde(fde) {
+ explicit PollNode(fdevent* fde) : fde(fde) {
memset(&pollfd, 0, sizeof(pollfd));
pollfd.fd = fde->fd;
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index c853bce..ef65b74 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -49,6 +49,16 @@
dummy = dummy_fds[0];
}
+ size_t GetAdditionalLocalSocketCount() {
+#if ADB_HOST
+ // dummy socket installed in PrepareThread()
+ return 1;
+#else
+ // dummy socket and one more socket installed in fdevent_subproc_setup()
+ return 2;
+#endif
+ }
+
void TerminateThread(adb_thread_t thread) {
fdevent_terminate_loop();
ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 651e8ca..6302eb7 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -433,7 +433,7 @@
typedef void (sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name);
static bool sync_ls(SyncConnection& sc, const char* path,
- std::function<sync_ls_cb> func) {
+ const std::function<sync_ls_cb>& func) {
if (!sc.SendRequest(ID_LIST, path)) return false;
while (true) {
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 926dbcf..14c26cb 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -21,13 +21,13 @@
#include <dirent.h>
#include <errno.h>
-#include <log/log.h>
-#include <selinux/android.h>
+#include <linux/xattr.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/xattr.h>
#include <unistd.h>
#include <utime.h>
@@ -39,6 +39,8 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <log/log.h>
+#include <selinux/android.h>
static bool should_use_fs_config(const std::string& path) {
// TODO: use fs_config to configure permissions on /data.
@@ -47,11 +49,27 @@
android::base::StartsWith(path, "/oem/");
}
+static bool update_capabilities(const char* path, uint64_t capabilities) {
+ if (capabilities == 0) {
+ // Ensure we clean up in case the capabilities weren't 0 in the past.
+ removexattr(path, XATTR_NAME_CAPS);
+ return true;
+ }
+
+ vfs_cap_data cap_data = {};
+ cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+ cap_data.data[0].permitted = (capabilities & 0xffffffff);
+ cap_data.data[0].inheritable = 0;
+ cap_data.data[1].permitted = (capabilities >> 32);
+ cap_data.data[1].inheritable = 0;
+ return setxattr(path, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) != -1;
+}
+
static bool secure_mkdirs(const std::string& path) {
uid_t uid = -1;
gid_t gid = -1;
unsigned int mode = 0775;
- uint64_t cap = 0;
+ uint64_t capabilities = 0;
if (path[0] != '/') return false;
@@ -62,18 +80,19 @@
partial_path += path_component;
if (should_use_fs_config(partial_path)) {
- fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &cap);
+ fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &capabilities);
}
if (adb_mkdir(partial_path.c_str(), mode) == -1) {
if (errno != EEXIST) {
return false;
}
} else {
- if (chown(partial_path.c_str(), uid, gid) == -1) {
- return false;
- }
+ if (chown(partial_path.c_str(), uid, gid) == -1) return false;
+
// Not all filesystems support setting SELinux labels. http://b/23530370.
selinux_android_restorecon(partial_path.c_str(), 0);
+
+ if (!update_capabilities(partial_path.c_str(), capabilities)) return false;
}
}
return true;
@@ -83,8 +102,7 @@
syncmsg msg;
msg.stat.id = ID_STAT;
- struct stat st;
- memset(&st, 0, sizeof(st));
+ struct stat st = {};
// TODO: add a way to report that the stat failed!
lstat(path, &st);
msg.stat.mode = st.st_mode;
@@ -146,8 +164,8 @@
return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
}
-static bool handle_send_file(int s, const char* path, uid_t uid,
- gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {
+static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint64_t capabilities,
+ mode_t mode, std::vector<char>& buffer, bool do_unlink) {
syncmsg msg;
unsigned int timestamp = 0;
@@ -178,8 +196,13 @@
// fchown clears the setuid bit - restore it if present.
// Ignore the result of calling fchmod. It's not supported
- // by all filesystems. b/12441485
+ // by all filesystems, so we don't check for success. b/12441485
fchmod(fd, mode);
+
+ if (!update_capabilities(path, capabilities)) {
+ SendSyncFailErrno(s, "update_capabilities failed");
+ goto fail;
+ }
}
while (true) {
@@ -338,13 +361,13 @@
uid_t uid = -1;
gid_t gid = -1;
- uint64_t cap = 0;
+ uint64_t capabilities = 0;
if (should_use_fs_config(path)) {
unsigned int broken_api_hack = mode;
- fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &cap);
+ fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &capabilities);
mode = broken_api_hack;
}
- return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink);
+ return handle_send_file(s, path.c_str(), uid, gid, capabilities, mode, buffer, do_unlink);
}
static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 3c812cc..7a44801 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/* implement the "debug-ports" and "track-debug-ports" device services */
+#if !ADB_HOST
#define TRACE_TAG JDWP
@@ -24,22 +24,29 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
+#include <list>
+#include <memory>
+#include <vector>
+
#include "adb.h"
+#include "adb_io.h"
#include "adb_utils.h"
/* here's how these things work.
when adbd starts, it creates a unix server socket
- named @vm-debug-control (@ is a shortcut for "first byte is zero"
+ named @jdwp-control (@ is a shortcut for "first byte is zero"
to use the private namespace instead of the file system)
when a new JDWP daemon thread starts in a new VM process, it creates
- a connection to @vm-debug-control to announce its availability.
+ a connection to @jdwp-control to announce its availability.
- JDWP thread @vm-debug-control
+ JDWP thread @jdwp-control
| |
|-------------------------------> |
| hello I'm in process <pid> |
@@ -72,7 +79,7 @@
to the JDWP process with the help of sendmsg()
- JDWP thread @vm-debug-control
+ JDWP thread @jdwp-control
| |
| <----------------------|
| OK, try this file descriptor |
@@ -116,249 +123,191 @@
** for each JDWP process, we record its pid and its connected socket
**/
-#define MAX_OUT_FDS 4
+// PIDs are transmitted as 4 hex digits in ascii.
+static constexpr size_t PID_LEN = 4;
-#if !ADB_HOST
+static void jdwp_process_event(int socket, unsigned events, void* _proc);
+static void jdwp_process_list_updated(void);
-#include <sys/socket.h>
-#include <sys/un.h>
+struct JdwpProcess;
+static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list;
struct JdwpProcess {
- JdwpProcess* next;
- JdwpProcess* prev;
- int pid;
- int socket;
- fdevent* fde;
+ explicit JdwpProcess(int socket) {
+ this->socket = socket;
+ this->fde = fdevent_create(socket, jdwp_process_event, this);
- char in_buff[4]; /* input character to read PID */
- int in_len; /* number from JDWP process */
+ if (!this->fde) {
+ fatal("could not create fdevent for new JDWP process");
+ }
- int out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
- int out_count; /* to send to the JDWP process */
+ this->fde->state |= FDE_DONT_CLOSE;
+
+ /* start by waiting for the PID */
+ fdevent_add(this->fde, FDE_READ);
+ }
+
+ ~JdwpProcess() {
+ if (this->socket >= 0) {
+ adb_shutdown(this->socket);
+ adb_close(this->socket);
+ this->socket = -1;
+ }
+
+ if (this->fde) {
+ fdevent_destroy(this->fde);
+ this->fde = nullptr;
+ }
+
+ out_fds.clear();
+ }
+
+ void RemoveFromList() {
+ if (this->pid >= 0) {
+ D("removing pid %d from jdwp process list", this->pid);
+ } else {
+ D("removing transient JdwpProcess from list");
+ }
+
+ auto pred = [this](const auto& proc) { return proc.get() == this; };
+ _jdwp_list.remove_if(pred);
+ }
+
+ int pid = -1;
+ int socket = -1;
+ fdevent* fde = nullptr;
+
+ std::vector<unique_fd> out_fds;
+ char in_buf[PID_LEN + 1];
+ ssize_t in_len = 0;
};
-static JdwpProcess _jdwp_list;
+static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
+ std::string temp;
-static int
-jdwp_process_list( char* buffer, int bufferlen )
-{
- char* end = buffer + bufferlen;
- char* p = buffer;
- JdwpProcess* proc = _jdwp_list.next;
-
- for ( ; proc != &_jdwp_list; proc = proc->next ) {
- int len;
-
+ for (auto& proc : _jdwp_list) {
/* skip transient connections */
- if (proc->pid < 0)
+ if (proc->pid < 0) {
continue;
+ }
- len = snprintf(p, end-p, "%d\n", proc->pid);
- if (p + len >= end)
+ std::string next = std::to_string(proc->pid) + "\n";
+ if (temp.length() + next.length() > bufferlen) {
+ D("truncating JDWP process list (max len = %zu)", bufferlen);
break;
- p += len;
- }
- p[0] = 0;
- return (p - buffer);
-}
-
-
-static int
-jdwp_process_list_msg( char* buffer, int bufferlen )
-{
- char head[5];
- int len = jdwp_process_list( buffer+4, bufferlen-4 );
- snprintf(head, sizeof head, "%04x", len);
- memcpy(buffer, head, 4);
- return len + 4;
-}
-
-
-static void jdwp_process_list_updated(void);
-
-static void
-jdwp_process_free( JdwpProcess* proc )
-{
- if (proc) {
- int n;
-
- proc->prev->next = proc->next;
- proc->next->prev = proc->prev;
-
- if (proc->socket >= 0) {
- adb_shutdown(proc->socket);
- adb_close(proc->socket);
- proc->socket = -1;
}
-
- if (proc->fde != NULL) {
- fdevent_destroy(proc->fde);
- proc->fde = NULL;
- }
- proc->pid = -1;
-
- for (n = 0; n < proc->out_count; n++) {
- adb_close(proc->out_fds[n]);
- }
- proc->out_count = 0;
-
- free(proc);
-
- jdwp_process_list_updated();
+ temp.append(next);
}
+
+ memcpy(buffer, temp.data(), temp.length());
+ return temp.length();
}
-
-static void jdwp_process_event(int, unsigned, void*); /* forward */
-
-
-static JdwpProcess*
-jdwp_process_alloc( int socket )
-{
- JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(
- calloc(1, sizeof(*proc)));
-
- if (proc == NULL) {
- D("not enough memory to create new JDWP process");
- return NULL;
+static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
+ // Message is length-prefixed with 4 hex digits in ASCII.
+ static constexpr size_t header_len = 4;
+ if (bufferlen < header_len) {
+ fatal("invalid JDWP process list buffer size: %zu", bufferlen);
}
- proc->socket = socket;
- proc->pid = -1;
- proc->next = proc;
- proc->prev = proc;
-
- proc->fde = fdevent_create( socket, jdwp_process_event, proc );
- if (proc->fde == NULL) {
- D("could not create fdevent for new JDWP process" );
- free(proc);
- return NULL;
- }
-
- proc->fde->state |= FDE_DONT_CLOSE;
- proc->in_len = 0;
- proc->out_count = 0;
-
- /* append to list */
- proc->next = &_jdwp_list;
- proc->prev = proc->next->prev;
-
- proc->prev->next = proc;
- proc->next->prev = proc;
-
- /* start by waiting for the PID */
- fdevent_add(proc->fde, FDE_READ);
-
- return proc;
+ char head[header_len + 1];
+ size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
+ snprintf(head, sizeof head, "%04zx", len);
+ memcpy(buffer, head, header_len);
+ return len + header_len;
}
-
-static void
-jdwp_process_event( int socket, unsigned events, void* _proc )
-{
- JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
+static void jdwp_process_event(int socket, unsigned events, void* _proc) {
+ JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
if (events & FDE_READ) {
if (proc->pid < 0) {
/* read the PID as a 4-hexchar string */
- char* p = proc->in_buff + proc->in_len;
- int size = 4 - proc->in_len;
- char temp[5];
- while (size > 0) {
- int len = recv( socket, p, size, 0 );
- if (len < 0) {
- if (errno == EINTR)
- continue;
- if (errno == EAGAIN)
- return;
- /* this can fail here if the JDWP process crashes very fast */
- D("weird unknown JDWP process failure: %s",
- strerror(errno));
-
- goto CloseProcess;
- }
- if (len == 0) { /* end of stream ? */
- D("weird end-of-stream from unknown JDWP process");
- goto CloseProcess;
- }
- p += len;
- proc->in_len += len;
- size -= len;
+ if (proc->in_len < 0) {
+ fatal("attempting to read JDWP pid again?");
}
- /* we have read 4 characters, now decode the pid */
- memcpy(temp, proc->in_buff, 4);
- temp[4] = 0;
- if (sscanf( temp, "%04x", &proc->pid ) != 1) {
- D("could not decode JDWP %p PID number: '%s'", proc, temp);
+ char* p = proc->in_buf + proc->in_len;
+ size_t size = PID_LEN - proc->in_len;
+
+ ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, p, size, 0));
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ return;
+ }
+
+ D("failed to read jdwp pid: %s", strerror(errno));
+ goto CloseProcess;
+ }
+
+ proc->in_len += rc;
+ if (proc->in_len != PID_LEN) {
+ return;
+ }
+
+ proc->in_buf[PID_LEN] = '\0';
+ proc->in_len = -1;
+
+ if (sscanf(proc->in_buf, "%04x", &proc->pid) != 1) {
+ D("could not decode JDWP %p PID number: '%s'", proc, p);
goto CloseProcess;
}
/* all is well, keep reading to detect connection closure */
D("Adding pid %d to jdwp process list", proc->pid);
jdwp_process_list_updated();
- }
- else
- {
+ } else {
/* the pid was read, if we get there it's probably because the connection
* was closed (e.g. the JDWP process exited or crashed) */
- char buf[32];
+ char buf[32];
- for (;;) {
- int len = recv(socket, buf, sizeof(buf), 0);
+ while (true) {
+ int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0));
- if (len <= 0) {
- if (len < 0 && errno == EINTR)
- continue;
- if (len < 0 && errno == EAGAIN)
+ if (len == 0) {
+ D("terminating JDWP %d connection: EOF", proc->pid);
+ break;
+ } else if (len < 0) {
+ if (len < 0 && errno == EAGAIN) {
return;
- else {
- D("terminating JDWP %d connection: %s", proc->pid,
- strerror(errno));
- break;
}
- }
- else {
- D( "ignoring unexpected JDWP %d control socket activity (%d bytes)",
- proc->pid, len );
+
+ D("terminating JDWP %d connection: EOF", proc->pid);
+ break;
+ } else {
+ D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid,
+ len);
}
}
- CloseProcess:
- if (proc->pid >= 0) {
- D( "remove pid %d to jdwp process list", proc->pid );
- }
- jdwp_process_free(proc);
- return;
+ goto CloseProcess;
}
}
if (events & FDE_WRITE) {
- D("trying to write to JDWP pid controli (count=%d first=%d) %d",
- proc->pid, proc->out_count, proc->out_fds[0]);
- if (proc->out_count > 0) {
- int fd = proc->out_fds[0];
- int n, ret;
- struct cmsghdr* cmsg;
- struct msghdr msg;
- struct iovec iov;
- char dummy = '!';
- char buffer[sizeof(struct cmsghdr) + sizeof(int)];
+ D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
+ if (!proc->out_fds.empty()) {
+ int fd = proc->out_fds.back().get();
+ struct cmsghdr* cmsg;
+ struct msghdr msg;
+ struct iovec iov;
+ char dummy = '!';
+ char buffer[sizeof(struct cmsghdr) + sizeof(int)];
- iov.iov_base = &dummy;
- iov.iov_len = 1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_flags = 0;
- msg.msg_control = buffer;
+ iov.iov_base = &dummy;
+ iov.iov_len = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ msg.msg_control = buffer;
msg.msg_controllen = sizeof(buffer);
cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = msg.msg_controllen;
+ cmsg->cmsg_len = msg.msg_controllen;
cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_type = SCM_RIGHTS;
((int*)CMSG_DATA(cmsg))[0] = fd;
if (!set_file_block_mode(proc->socket, true)) {
@@ -366,74 +315,59 @@
goto CloseProcess;
}
- for (;;) {
- ret = sendmsg(proc->socket, &msg, 0);
- if (ret >= 0) {
- adb_close(fd);
- break;
- }
- if (errno == EINTR)
- continue;
- D("sending new file descriptor to JDWP %d failed: %s",
- proc->pid, strerror(errno));
+ int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0));
+ if (ret < 0) {
+ D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
goto CloseProcess;
}
- D("sent file descriptor %d to JDWP process %d",
- fd, proc->pid);
+ adb_close(fd);
- for (n = 1; n < proc->out_count; n++)
- proc->out_fds[n-1] = proc->out_fds[n];
+ D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+
+ proc->out_fds.pop_back();
if (!set_file_block_mode(proc->socket, false)) {
VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket;
goto CloseProcess;
}
- if (--proc->out_count == 0)
- fdevent_del( proc->fde, FDE_WRITE );
+ if (proc->out_fds.empty()) {
+ fdevent_del(proc->fde, FDE_WRITE);
+ }
}
}
+
+ return;
+
+CloseProcess:
+ proc->RemoveFromList();
+ jdwp_process_list_updated();
}
-
-int
-create_jdwp_connection_fd(int pid)
-{
- JdwpProcess* proc = _jdwp_list.next;
-
+int create_jdwp_connection_fd(int pid) {
D("looking for pid %d in JDWP process list", pid);
- for ( ; proc != &_jdwp_list; proc = proc->next ) {
+
+ for (auto& proc : _jdwp_list) {
if (proc->pid == pid) {
- goto FoundIt;
+ int fds[2];
+
+ if (adb_socketpair(fds) < 0) {
+ D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
+ return -1;
+ }
+ D("socketpair: (%d,%d)", fds[0], fds[1]);
+
+ proc->out_fds.emplace_back(fds[1]);
+ if (proc->out_fds.size() == 1) {
+ fdevent_add(proc->fde, FDE_WRITE);
+ }
+
+ return fds[0];
}
}
D("search failed !!");
return -1;
-
-FoundIt:
- {
- int fds[2];
-
- if (proc->out_count >= MAX_OUT_FDS) {
- D("%s: too many pending JDWP connection for pid %d",
- __FUNCTION__, pid);
- return -1;
- }
-
- if (adb_socketpair(fds) < 0) {
- D("%s: socket pair creation failed: %s",
- __FUNCTION__, strerror(errno));
- return -1;
- }
- D("socketpair: (%d,%d)", fds[0], fds[1]);
-
- proc->out_fds[ proc->out_count ] = fds[1];
- if (++proc->out_count == 1)
- fdevent_add( proc->fde, FDE_WRITE );
-
- return fds[0];
- }
}
/** VM DEBUG CONTROL SOCKET
@@ -442,33 +376,27 @@
**/
/* name of the debug control Unix socket */
-#define JDWP_CONTROL_NAME "\0jdwp-control"
-#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1)
+#define JDWP_CONTROL_NAME "\0jdwp-control"
+#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME) - 1)
struct JdwpControl {
- int listen_socket;
- fdevent* fde;
+ int listen_socket;
+ fdevent* fde;
};
+static JdwpControl _jdwp_control;
-static void
-jdwp_control_event(int s, unsigned events, void* user);
+static void jdwp_control_event(int s, unsigned events, void* user);
-
-static int
-jdwp_control_init( JdwpControl* control,
- const char* sockname,
- int socknamelen )
-{
- sockaddr_un addr;
- socklen_t addrlen;
- int s;
- int maxpath = sizeof(addr.sun_path);
- int pathlen = socknamelen;
+static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) {
+ sockaddr_un addr;
+ socklen_t addrlen;
+ int s;
+ int maxpath = sizeof(addr.sun_path);
+ int pathlen = socknamelen;
if (pathlen >= maxpath) {
- D( "vm debug control socket name too long (%d extra chars)",
- pathlen+1-maxpath );
+ D("vm debug control socket name too long (%d extra chars)", pathlen + 1 - maxpath);
return -1;
}
@@ -476,25 +404,22 @@
addr.sun_family = AF_UNIX;
memcpy(addr.sun_path, sockname, socknamelen);
- s = socket( AF_UNIX, SOCK_STREAM, 0 );
+ s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (s < 0) {
- D( "could not create vm debug control socket. %d: %s",
- errno, strerror(errno));
+ D("could not create vm debug control socket. %d: %s", errno, strerror(errno));
return -1;
}
- addrlen = (pathlen + sizeof(addr.sun_family));
+ addrlen = pathlen + sizeof(addr.sun_family);
if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
- D( "could not bind vm debug control socket: %d: %s",
- errno, strerror(errno) );
+ D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
adb_close(s);
return -1;
}
- if ( listen(s, 4) < 0 ) {
- D("listen failed in jdwp control socket: %d: %s",
- errno, strerror(errno));
+ if (listen(s, 4) < 0) {
+ D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
adb_close(s);
return -1;
}
@@ -503,128 +428,109 @@
control->fde = fdevent_create(s, jdwp_control_event, control);
if (control->fde == NULL) {
- D( "could not create fdevent for jdwp control socket" );
+ D("could not create fdevent for jdwp control socket");
adb_close(s);
return -1;
}
/* only wait for incoming connections */
fdevent_add(control->fde, FDE_READ);
- close_on_exec(s);
D("jdwp control socket started (%d)", control->listen_socket);
return 0;
}
-
-static void
-jdwp_control_event( int s, unsigned events, void* _control )
-{
- JdwpControl* control = (JdwpControl*) _control;
+static void jdwp_control_event(int s, unsigned events, void* _control) {
+ JdwpControl* control = (JdwpControl*)_control;
if (events & FDE_READ) {
- sockaddr_storage ss;
- sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
- socklen_t addrlen = sizeof(ss);
- int s = -1;
- JdwpProcess* proc;
-
- do {
- s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
- if (s < 0) {
- if (errno == EINTR)
- continue;
- if (errno == ECONNABORTED) {
- /* oops, the JDWP process died really quick */
- D("oops, the JDWP process died really quick");
- return;
- }
+ sockaddr_storage ss;
+ sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
+ socklen_t addrlen = sizeof(ss);
+ int s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
+ if (s < 0) {
+ if (errno == ECONNABORTED) {
+ /* oops, the JDWP process died really quick */
+ D("oops, the JDWP process died really quick");
+ return;
+ } else {
/* the socket is probably closed ? */
- D( "weird accept() failed on jdwp control socket: %s",
- strerror(errno) );
+ D("weird accept() failed on jdwp control socket: %s", strerror(errno));
return;
}
}
- while (s < 0);
- proc = jdwp_process_alloc( s );
- if (proc == NULL)
- return;
+ auto proc = std::make_unique<JdwpProcess>(s);
+ if (!proc) {
+ fatal("failed to allocate JdwpProcess");
+ }
+
+ _jdwp_list.emplace_back(std::move(proc));
}
}
-
-static JdwpControl _jdwp_control;
-
/** "jdwp" local service implementation
** this simply returns the list of known JDWP process pids
**/
-struct JdwpSocket {
- asocket socket;
- int pass;
+struct JdwpSocket : public asocket {
+ bool pass;
};
-static void
-jdwp_socket_close( asocket* s )
-{
- asocket* peer = s->peer;
+static void jdwp_socket_close(asocket* s) {
+ D("LS(%d): closing jdwp socket", s->id);
+
+ if (s->peer) {
+ D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
+ s->peer->peer = nullptr;
+ s->peer->close(s->peer);
+ s->peer = nullptr;
+ }
remove_socket(s);
-
- if (peer) {
- peer->peer = NULL;
- peer->close(peer);
- }
free(s);
}
-static int
-jdwp_socket_enqueue( asocket* s, apacket* p )
-{
+static int jdwp_socket_enqueue(asocket* s, apacket* p) {
/* you can't write to this asocket */
+ D("LS(%d): JDWP socket received data?", s->id);
put_apacket(p);
s->peer->close(s->peer);
return -1;
}
+static void jdwp_socket_ready(asocket* s) {
+ JdwpSocket* jdwp = (JdwpSocket*)s;
+ asocket* peer = jdwp->peer;
-static void
-jdwp_socket_ready( asocket* s )
-{
- JdwpSocket* jdwp = (JdwpSocket*)s;
- asocket* peer = jdwp->socket.peer;
-
- /* on the first call, send the list of pids,
- * on the second one, close the connection
- */
- if (jdwp->pass == 0) {
- apacket* p = get_apacket();
+ /* on the first call, send the list of pids,
+ * on the second one, close the connection
+ */
+ if (!jdwp->pass) {
+ apacket* p = get_apacket();
p->len = jdwp_process_list((char*)p->data, s->get_max_payload());
peer->enqueue(peer, p);
- jdwp->pass = 1;
- }
- else {
+ jdwp->pass = true;
+ } else {
peer->close(peer);
}
}
-asocket*
-create_jdwp_service_socket( void )
-{
+asocket* create_jdwp_service_socket(void) {
JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));
- if (s == NULL)
- return NULL;
+ if (!s) {
+ fatal("failed to allocate JdwpSocket");
+ }
- install_local_socket(&s->socket);
+ install_local_socket(s);
- s->socket.ready = jdwp_socket_ready;
- s->socket.enqueue = jdwp_socket_enqueue;
- s->socket.close = jdwp_socket_close;
- s->pass = 0;
+ s->ready = jdwp_socket_ready;
+ s->enqueue = jdwp_socket_enqueue;
+ s->close = jdwp_socket_close;
+ s->pass = false;
- return &s->socket;
+ return s;
}
/** "track-jdwp" local service implementation
@@ -632,113 +538,88 @@
** to the client...
**/
-struct JdwpTracker {
- asocket socket;
- JdwpTracker* next;
- JdwpTracker* prev;
- int need_update;
+struct JdwpTracker : public asocket {
+ bool need_initial;
};
-static JdwpTracker _jdwp_trackers_list;
+static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
+static void jdwp_process_list_updated(void) {
+ char buffer[1024];
+ int len = jdwp_process_list_msg(buffer, sizeof(buffer));
-static void
-jdwp_process_list_updated(void)
-{
- char buffer[1024];
- int len;
- JdwpTracker* t = _jdwp_trackers_list.next;
-
- len = jdwp_process_list_msg(buffer, sizeof(buffer));
-
- for ( ; t != &_jdwp_trackers_list; t = t->next ) {
- apacket* p = get_apacket();
- asocket* peer = t->socket.peer;
+ for (auto& t : _jdwp_trackers) {
+ apacket* p = get_apacket();
memcpy(p->data, buffer, len);
p->len = len;
- peer->enqueue( peer, p );
+
+ if (t->peer) {
+ // The tracker might not have been connected yet.
+ t->peer->enqueue(t->peer, p);
+ }
}
}
-static void
-jdwp_tracker_close( asocket* s )
-{
- JdwpTracker* tracker = (JdwpTracker*) s;
- asocket* peer = s->peer;
+static void jdwp_tracker_close(asocket* s) {
+ D("LS(%d): destroying jdwp tracker service", s->id);
- if (peer) {
- peer->peer = NULL;
- peer->close(peer);
+ if (s->peer) {
+ D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
+ s->peer->peer = nullptr;
+ s->peer->close(s->peer);
+ s->peer = nullptr;
}
remove_socket(s);
- tracker->prev->next = tracker->next;
- tracker->next->prev = tracker->prev;
-
- free(s);
+ auto pred = [s](const auto& tracker) { return tracker.get() == s; };
+ std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred);
}
-static void
-jdwp_tracker_ready( asocket* s )
-{
- JdwpTracker* t = (JdwpTracker*) s;
+static void jdwp_tracker_ready(asocket* s) {
+ JdwpTracker* t = (JdwpTracker*)s;
- if (t->need_update) {
- apacket* p = get_apacket();
- t->need_update = 0;
+ if (t->need_initial) {
+ apacket* p = get_apacket();
+ t->need_initial = false;
p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload());
s->peer->enqueue(s->peer, p);
}
}
-static int
-jdwp_tracker_enqueue( asocket* s, apacket* p )
-{
+static int jdwp_tracker_enqueue(asocket* s, apacket* p) {
/* you can't write to this socket */
+ D("LS(%d): JDWP tracker received data?", s->id);
put_apacket(p);
s->peer->close(s->peer);
return -1;
}
+asocket* create_jdwp_tracker_service_socket(void) {
+ auto t = std::make_unique<JdwpTracker>();
+ if (!t) {
+ fatal("failed to allocate JdwpTracker");
+ }
-asocket*
-create_jdwp_tracker_service_socket( void )
-{
- JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1));
+ memset(t.get(), 0, sizeof(asocket));
- if (t == NULL)
- return NULL;
+ install_local_socket(t.get());
+ D("LS(%d): created new jdwp tracker service", t->id);
- t->next = &_jdwp_trackers_list;
- t->prev = t->next->prev;
+ t->ready = jdwp_tracker_ready;
+ t->enqueue = jdwp_tracker_enqueue;
+ t->close = jdwp_tracker_close;
+ t->need_initial = true;
- t->next->prev = t;
- t->prev->next = t;
+ asocket* result = t.get();
- install_local_socket(&t->socket);
+ _jdwp_trackers.emplace_back(std::move(t));
- t->socket.ready = jdwp_tracker_ready;
- t->socket.enqueue = jdwp_tracker_enqueue;
- t->socket.close = jdwp_tracker_close;
- t->need_update = 1;
-
- return &t->socket;
+ return result;
}
-
-int
-init_jdwp(void)
-{
- _jdwp_list.next = &_jdwp_list;
- _jdwp_list.prev = &_jdwp_list;
-
- _jdwp_trackers_list.next = &_jdwp_trackers_list;
- _jdwp_trackers_list.prev = &_jdwp_trackers_list;
-
- return jdwp_control_init( &_jdwp_control,
- JDWP_CONTROL_NAME,
- JDWP_CONTROL_NAME_LEN );
+int init_jdwp(void) {
+ return jdwp_control_init(&_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN);
}
#endif /* !ADB_HOST */
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 104f399..d83622c 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -136,14 +136,14 @@
}
// Creates a socketpair and saves the endpoints to |fd1| and |fd2|.
-bool CreateSocketpair(ScopedFd* fd1, ScopedFd* fd2) {
+bool CreateSocketpair(unique_fd* fd1, unique_fd* fd2) {
int sockets[2];
if (adb_socketpair(sockets) < 0) {
PLOG(ERROR) << "cannot create socket pair";
return false;
}
- fd1->Reset(sockets[0]);
- fd2->Reset(sockets[1]);
+ fd1->reset(sockets[0]);
+ fd2->reset(sockets[1]);
return true;
}
@@ -155,7 +155,7 @@
const std::string& command() const { return command_; }
- int ReleaseLocalSocket() { return local_socket_sfd_.Release(); }
+ int ReleaseLocalSocket() { return local_socket_sfd_.release(); }
pid_t pid() const { return pid_; }
@@ -170,19 +170,19 @@
private:
// Opens the file at |pts_name|.
- int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd);
+ int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd);
static void ThreadHandler(void* userdata);
void PassDataStreams();
void WaitForExit();
- ScopedFd* SelectLoop(fd_set* master_read_set_ptr,
- fd_set* master_write_set_ptr);
+ unique_fd* SelectLoop(fd_set* master_read_set_ptr,
+ fd_set* master_write_set_ptr);
// Input/output stream handlers. Success returns nullptr, failure returns
// a pointer to the failed FD.
- ScopedFd* PassInput();
- ScopedFd* PassOutput(ScopedFd* sfd, ShellProtocol::Id id);
+ unique_fd* PassInput();
+ unique_fd* PassOutput(unique_fd* sfd, ShellProtocol::Id id);
const std::string command_;
const std::string terminal_type_;
@@ -190,10 +190,10 @@
SubprocessType type_;
SubprocessProtocol protocol_;
pid_t pid_ = -1;
- ScopedFd local_socket_sfd_;
+ unique_fd local_socket_sfd_;
// Shell protocol variables.
- ScopedFd stdinout_sfd_, stderr_sfd_, protocol_sfd_;
+ unique_fd stdinout_sfd_, stderr_sfd_, protocol_sfd_;
std::unique_ptr<ShellProtocol> input_, output_;
size_t input_bytes_left_ = 0;
@@ -225,8 +225,8 @@
}
bool Subprocess::ForkAndExec(std::string* error) {
- ScopedFd child_stdinout_sfd, child_stderr_sfd;
- ScopedFd parent_error_sfd, child_error_sfd;
+ unique_fd child_stdinout_sfd, child_stderr_sfd;
+ unique_fd parent_error_sfd, child_error_sfd;
char pts_name[PATH_MAX];
if (command_.empty()) {
@@ -251,7 +251,7 @@
char** current = environ;
while (char* env_cstr = *current++) {
std::string env_string = env_cstr;
- char* delimiter = strchr(env_string.c_str(), '=');
+ char* delimiter = strchr(&env_string[0], '=');
// Drop any values that don't contain '='.
if (delimiter) {
@@ -290,7 +290,7 @@
int fd;
pid_ = forkpty(&fd, pts_name, nullptr, nullptr);
if (pid_ > 0) {
- stdinout_sfd_.Reset(fd);
+ stdinout_sfd_.reset(fd);
}
} else {
if (!CreateSocketpair(&stdinout_sfd_, &child_stdinout_sfd)) {
@@ -318,40 +318,39 @@
init_subproc_child();
if (type_ == SubprocessType::kPty) {
- child_stdinout_sfd.Reset(OpenPtyChildFd(pts_name, &child_error_sfd));
+ child_stdinout_sfd.reset(OpenPtyChildFd(pts_name, &child_error_sfd));
}
- dup2(child_stdinout_sfd.fd(), STDIN_FILENO);
- dup2(child_stdinout_sfd.fd(), STDOUT_FILENO);
- dup2(child_stderr_sfd.valid() ? child_stderr_sfd.fd() : child_stdinout_sfd.fd(),
- STDERR_FILENO);
+ dup2(child_stdinout_sfd, STDIN_FILENO);
+ dup2(child_stdinout_sfd, STDOUT_FILENO);
+ dup2(child_stderr_sfd != -1 ? child_stderr_sfd : child_stdinout_sfd, STDERR_FILENO);
// exec doesn't trigger destructors, close the FDs manually.
- stdinout_sfd_.Reset();
- stderr_sfd_.Reset();
- child_stdinout_sfd.Reset();
- child_stderr_sfd.Reset();
- parent_error_sfd.Reset();
- close_on_exec(child_error_sfd.fd());
+ stdinout_sfd_.reset(-1);
+ stderr_sfd_.reset(-1);
+ child_stdinout_sfd.reset(-1);
+ child_stderr_sfd.reset(-1);
+ parent_error_sfd.reset(-1);
+ close_on_exec(child_error_sfd);
if (command_.empty()) {
execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
} else {
execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
}
- WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed: ");
- WriteFdExactly(child_error_sfd.fd(), strerror(errno));
- child_error_sfd.Reset();
+ WriteFdExactly(child_error_sfd, "exec '" _PATH_BSHELL "' failed: ");
+ WriteFdExactly(child_error_sfd, strerror(errno));
+ child_error_sfd.reset(-1);
_Exit(1);
}
// Subprocess parent.
D("subprocess parent: stdin/stdout FD = %d, stderr FD = %d",
- stdinout_sfd_.fd(), stderr_sfd_.fd());
+ stdinout_sfd_.get(), stderr_sfd_.get());
// Wait to make sure the subprocess exec'd without error.
- child_error_sfd.Reset();
- std::string error_message = ReadAll(parent_error_sfd.fd());
+ child_error_sfd.reset(-1);
+ std::string error_message = ReadAll(parent_error_sfd);
if (!error_message.empty()) {
*error = error_message;
return false;
@@ -361,7 +360,7 @@
if (protocol_ == SubprocessProtocol::kNone) {
// No protocol: all streams pass through the stdinout FD and hook
// directly into the local socket for raw data transfer.
- local_socket_sfd_.Reset(stdinout_sfd_.Release());
+ local_socket_sfd_.reset(stdinout_sfd_.release());
} else {
// Shell protocol: create another socketpair to intercept data.
if (!CreateSocketpair(&protocol_sfd_, &local_socket_sfd_)) {
@@ -370,10 +369,10 @@
kill(pid_, SIGKILL);
return false;
}
- D("protocol FD = %d", protocol_sfd_.fd());
+ D("protocol FD = %d", protocol_sfd_.get());
- input_.reset(new ShellProtocol(protocol_sfd_.fd()));
- output_.reset(new ShellProtocol(protocol_sfd_.fd()));
+ input_.reset(new ShellProtocol(protocol_sfd_));
+ output_.reset(new ShellProtocol(protocol_sfd_));
if (!input_ || !output_) {
*error = "failed to allocate shell protocol objects";
kill(pid_, SIGKILL);
@@ -384,7 +383,7 @@
// likely but could happen under unusual circumstances, such as if we
// write a ton of data to stdin but the subprocess never reads it and
// the pipe fills up.
- for (int fd : {stdinout_sfd_.fd(), stderr_sfd_.fd()}) {
+ for (int fd : {stdinout_sfd_.get(), stderr_sfd_.get()}) {
if (fd >= 0) {
if (!set_file_block_mode(fd, false)) {
*error = android::base::StringPrintf(
@@ -412,7 +411,7 @@
return true;
}
-int Subprocess::OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd) {
+int Subprocess::OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd) {
int child_fd = adb_open(pts_name, O_RDWR | O_CLOEXEC);
if (child_fd == -1) {
// Don't use WriteFdFmt; since we're in the fork() child we don't want
@@ -420,26 +419,26 @@
const char* messages[] = {"child failed to open pseudo-term slave ",
pts_name, ": ", strerror(errno)};
for (const char* message : messages) {
- WriteFdExactly(error_sfd->fd(), message);
+ WriteFdExactly(*error_sfd, message);
}
- exit(-1);
+ abort();
}
if (make_pty_raw_) {
termios tattr;
if (tcgetattr(child_fd, &tattr) == -1) {
int saved_errno = errno;
- WriteFdExactly(error_sfd->fd(), "tcgetattr failed: ");
- WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
- exit(-1);
+ WriteFdExactly(*error_sfd, "tcgetattr failed: ");
+ WriteFdExactly(*error_sfd, strerror(saved_errno));
+ abort();
}
cfmakeraw(&tattr);
if (tcsetattr(child_fd, TCSADRAIN, &tattr) == -1) {
int saved_errno = errno;
- WriteFdExactly(error_sfd->fd(), "tcsetattr failed: ");
- WriteFdExactly(error_sfd->fd(), strerror(saved_errno));
- exit(-1);
+ WriteFdExactly(*error_sfd, "tcsetattr failed: ");
+ WriteFdExactly(*error_sfd, strerror(saved_errno));
+ abort();
}
}
@@ -460,7 +459,7 @@
}
void Subprocess::PassDataStreams() {
- if (!protocol_sfd_.valid()) {
+ if (protocol_sfd_ == -1) {
return;
}
@@ -468,21 +467,20 @@
fd_set master_read_set, master_write_set;
FD_ZERO(&master_read_set);
FD_ZERO(&master_write_set);
- for (ScopedFd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
- if (sfd->valid()) {
- FD_SET(sfd->fd(), &master_read_set);
+ for (unique_fd* sfd : {&protocol_sfd_, &stdinout_sfd_, &stderr_sfd_}) {
+ if (*sfd != -1) {
+ FD_SET(*sfd, &master_read_set);
}
}
// Pass data until the protocol FD or both the subprocess pipes die, at
// which point we can't pass any more data.
- while (protocol_sfd_.valid() &&
- (stdinout_sfd_.valid() || stderr_sfd_.valid())) {
- ScopedFd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
+ while (protocol_sfd_ != -1 && (stdinout_sfd_ != -1 || stderr_sfd_ != -1)) {
+ unique_fd* dead_sfd = SelectLoop(&master_read_set, &master_write_set);
if (dead_sfd) {
- D("closing FD %d", dead_sfd->fd());
- FD_CLR(dead_sfd->fd(), &master_read_set);
- FD_CLR(dead_sfd->fd(), &master_write_set);
+ D("closing FD %d", dead_sfd->get());
+ FD_CLR(*dead_sfd, &master_read_set);
+ FD_CLR(*dead_sfd, &master_write_set);
if (dead_sfd == &protocol_sfd_) {
// Using SIGHUP is a decent general way to indicate that the
// controlling process is going away. If specific signals are
@@ -494,28 +492,27 @@
// We also need to close the pipes connected to the child process
// so that if it ignores SIGHUP and continues to write data it
// won't fill up the pipe and block.
- stdinout_sfd_.Reset();
- stderr_sfd_.Reset();
+ stdinout_sfd_.clear();
+ stderr_sfd_.clear();
}
- dead_sfd->Reset();
+ dead_sfd->clear();
}
}
}
namespace {
-inline bool ValidAndInSet(const ScopedFd& sfd, fd_set* set) {
- return sfd.valid() && FD_ISSET(sfd.fd(), set);
+inline bool ValidAndInSet(const unique_fd& sfd, fd_set* set) {
+ return sfd != -1 && FD_ISSET(sfd, set);
}
} // namespace
-ScopedFd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
- fd_set* master_write_set_ptr) {
+unique_fd* Subprocess::SelectLoop(fd_set* master_read_set_ptr,
+ fd_set* master_write_set_ptr) {
fd_set read_set, write_set;
- int select_n = std::max(std::max(protocol_sfd_.fd(), stdinout_sfd_.fd()),
- stderr_sfd_.fd()) + 1;
- ScopedFd* dead_sfd = nullptr;
+ int select_n = std::max(std::max(protocol_sfd_, stdinout_sfd_), stderr_sfd_) + 1;
+ unique_fd* dead_sfd = nullptr;
// Keep calling select() and passing data until an FD closes/errors.
while (!dead_sfd) {
@@ -526,8 +523,8 @@
continue;
} else {
PLOG(ERROR) << "select failed, closing subprocess pipes";
- stdinout_sfd_.Reset();
- stderr_sfd_.Reset();
+ stdinout_sfd_.reset(-1);
+ stderr_sfd_.reset(-1);
return nullptr;
}
}
@@ -547,8 +544,8 @@
dead_sfd = PassInput();
// If we didn't finish writing, block on stdin write.
if (input_bytes_left_) {
- FD_CLR(protocol_sfd_.fd(), master_read_set_ptr);
- FD_SET(stdinout_sfd_.fd(), master_write_set_ptr);
+ FD_CLR(protocol_sfd_, master_read_set_ptr);
+ FD_SET(stdinout_sfd_, master_write_set_ptr);
}
}
@@ -557,8 +554,8 @@
dead_sfd = PassInput();
// If we finished writing, go back to blocking on protocol read.
if (!input_bytes_left_) {
- FD_SET(protocol_sfd_.fd(), master_read_set_ptr);
- FD_CLR(stdinout_sfd_.fd(), master_write_set_ptr);
+ FD_SET(protocol_sfd_, master_read_set_ptr);
+ FD_CLR(stdinout_sfd_, master_write_set_ptr);
}
}
} // while (!dead_sfd)
@@ -566,19 +563,18 @@
return dead_sfd;
}
-ScopedFd* Subprocess::PassInput() {
+unique_fd* Subprocess::PassInput() {
// Only read a new packet if we've finished writing the last one.
if (!input_bytes_left_) {
if (!input_->Read()) {
// Read() uses ReadFdExactly() which sets errno to 0 on EOF.
if (errno != 0) {
- PLOG(ERROR) << "error reading protocol FD "
- << protocol_sfd_.fd();
+ PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
}
return &protocol_sfd_;
}
- if (stdinout_sfd_.valid()) {
+ if (stdinout_sfd_ != -1) {
switch (input_->id()) {
case ShellProtocol::kIdWindowSizeChange:
int rows, cols, x_pixels, y_pixels;
@@ -589,7 +585,7 @@
ws.ws_col = cols;
ws.ws_xpixel = x_pixels;
ws.ws_ypixel = y_pixels;
- ioctl(stdinout_sfd_.fd(), TIOCSWINSZ, &ws);
+ ioctl(stdinout_sfd_, TIOCSWINSZ, &ws);
}
break;
case ShellProtocol::kIdStdin:
@@ -597,11 +593,11 @@
break;
case ShellProtocol::kIdCloseStdin:
if (type_ == SubprocessType::kRaw) {
- if (adb_shutdown(stdinout_sfd_.fd(), SHUT_WR) == 0) {
+ if (adb_shutdown(stdinout_sfd_, SHUT_WR) == 0) {
return nullptr;
}
PLOG(ERROR) << "failed to shutdown writes to FD "
- << stdinout_sfd_.fd();
+ << stdinout_sfd_;
return &stdinout_sfd_;
} else {
// PTYs can't close just input, so rather than close the
@@ -610,7 +606,7 @@
// non-interactively which is rare and unsupported.
// If necessary, the client can manually close the shell
// with `exit` or by killing the adb client process.
- D("can't close input for PTY FD %d", stdinout_sfd_.fd());
+ D("can't close input for PTY FD %d", stdinout_sfd_.get());
}
break;
}
@@ -619,11 +615,10 @@
if (input_bytes_left_ > 0) {
int index = input_->data_length() - input_bytes_left_;
- int bytes = adb_write(stdinout_sfd_.fd(), input_->data() + index,
- input_bytes_left_);
+ int bytes = adb_write(stdinout_sfd_, input_->data() + index, input_bytes_left_);
if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
if (bytes < 0) {
- PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_.fd();
+ PLOG(ERROR) << "error reading stdin FD " << stdinout_sfd_;
}
// stdin is done, mark this packet as finished and we'll just start
// dumping any further data received from the protocol FD.
@@ -637,20 +632,20 @@
return nullptr;
}
-ScopedFd* Subprocess::PassOutput(ScopedFd* sfd, ShellProtocol::Id id) {
- int bytes = adb_read(sfd->fd(), output_->data(), output_->data_capacity());
+unique_fd* Subprocess::PassOutput(unique_fd* sfd, ShellProtocol::Id id) {
+ int bytes = adb_read(*sfd, output_->data(), output_->data_capacity());
if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
// read() returns EIO if a PTY closes; don't report this as an error,
// it just means the subprocess completed.
if (bytes < 0 && !(type_ == SubprocessType::kPty && errno == EIO)) {
- PLOG(ERROR) << "error reading output FD " << sfd->fd();
+ PLOG(ERROR) << "error reading output FD " << *sfd;
}
return sfd;
}
if (bytes > 0 && !output_->Write(id, bytes)) {
if (errno != 0) {
- PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_.fd();
+ PLOG(ERROR) << "error reading protocol FD " << protocol_sfd_;
}
return &protocol_sfd_;
}
@@ -682,25 +677,25 @@
}
// If we have an open protocol FD send an exit packet.
- if (protocol_sfd_.valid()) {
+ if (protocol_sfd_ != -1) {
output_->data()[0] = exit_code;
if (output_->Write(ShellProtocol::kIdExit, 1)) {
D("wrote the exit code packet: %d", exit_code);
} else {
PLOG(ERROR) << "failed to write the exit code packet";
}
- protocol_sfd_.Reset();
+ protocol_sfd_.reset(-1);
}
// Pass the local socket FD to the shell cleanup fdevent.
if (SHELL_EXIT_NOTIFY_FD >= 0) {
- int fd = local_socket_sfd_.fd();
+ int fd = local_socket_sfd_;
if (WriteFdExactly(SHELL_EXIT_NOTIFY_FD, &fd, sizeof(fd))) {
D("passed fd %d to SHELL_EXIT_NOTIFY_FD (%d) for pid %d",
fd, SHELL_EXIT_NOTIFY_FD, pid_);
// The shell exit fdevent now owns the FD and will close it once
// the last bit of data flushes through.
- local_socket_sfd_.Release();
+ static_cast<void>(local_socket_sfd_.release());
} else {
PLOG(ERROR) << "failed to write fd " << fd
<< " to SHELL_EXIT_NOTIFY_FD (" << SHELL_EXIT_NOTIFY_FD
@@ -761,13 +756,14 @@
return ReportError(protocol, error);
}
- int local_socket = subprocess->ReleaseLocalSocket();
- D("subprocess creation successful: local_socket_fd=%d, pid=%d", local_socket, subprocess->pid());
+ unique_fd local_socket(subprocess->ReleaseLocalSocket());
+ D("subprocess creation successful: local_socket_fd=%d, pid=%d", local_socket.get(),
+ subprocess->pid());
if (!Subprocess::StartThread(std::move(subprocess), &error)) {
LOG(ERROR) << "failed to start subprocess management thread: " << error;
return ReportError(protocol, error);
}
- return local_socket;
+ return local_socket.release();
}
diff --git a/adb/socket.h b/adb/socket.h
index 9eb1b19..4acdf4a 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -118,7 +118,7 @@
namespace internal {
#if ADB_HOST
-char* skip_host_serial(const char* service);
+char* skip_host_serial(char* service);
#endif
} // namespace internal
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 5cbef6d..d2ce2d8 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -44,6 +44,8 @@
fdevent_loop();
}
+const size_t SLEEP_FOR_FDEVENT_IN_MS = 100;
+
TEST_F(LocalSocketTest, smoke) {
// Join two socketpairs with a chain of intermediate socketpairs.
int first[2];
@@ -99,7 +101,8 @@
ASSERT_EQ(0, adb_close(last[1]));
// Wait until the local sockets are closed.
- adb_sleep_ms(100);
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -151,12 +154,13 @@
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(100);
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- adb_sleep_ms(100);
- EXPECT_EQ(2u, fdevent_installed_count());
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
-
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -175,10 +179,10 @@
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(100);
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
- adb_sleep_ms(100);
- EXPECT_EQ(2u, fdevent_installed_count());
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Verify if we can read successfully.
std::vector<char> buf(arg.bytes_written);
@@ -186,6 +190,8 @@
ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
ASSERT_EQ(0, adb_close(socket_fd[0]));
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -208,10 +214,12 @@
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(100);
- EXPECT_EQ(3u, fdevent_installed_count());
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ EXPECT_EQ(2u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
ASSERT_EQ(0, adb_close(socket_fd[0]));
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -260,12 +268,14 @@
&arg, &thread));
// Wait until the fdevent_loop() starts.
- adb_sleep_ms(100);
- EXPECT_EQ(2u, fdevent_installed_count());
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ EXPECT_EQ(1u + GetAdditionalLocalSocketCount(), fdevent_installed_count());
// Wait until the client closes its socket.
ASSERT_TRUE(adb_thread_join(client_thread));
+ adb_sleep_ms(SLEEP_FOR_FDEVENT_IN_MS);
+ ASSERT_EQ(GetAdditionalLocalSocketCount(), fdevent_installed_count());
TerminateThread(thread);
}
@@ -275,8 +285,8 @@
// Checks that skip_host_serial(serial) returns a pointer to the part of |serial| which matches
// |expected|, otherwise logs the failure to gtest.
-void VerifySkipHostSerial(const std::string& serial, const char* expected) {
- const char* result = internal::skip_host_serial(serial.c_str());
+void VerifySkipHostSerial(std::string serial, const char* expected) {
+ char* result = internal::skip_host_serial(&serial[0]);
if (expected == nullptr) {
EXPECT_EQ(nullptr, result);
} else {
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 63b7df6..4ed1c45 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -410,7 +410,7 @@
#endif
int fd = service_to_fd(name, transport);
if (fd < 0) {
- return 0;
+ return nullptr;
}
asocket* s = create_local_socket(fd);
@@ -608,7 +608,7 @@
// Where <port> must be a base-10 number and <prefix> may be any of {usb,product,model,device}.
//
// The returned pointer will point to the ':' just before <command>, or nullptr if not found.
-char* skip_host_serial(const char* service) {
+char* skip_host_serial(char* service) {
static const std::vector<std::string>& prefixes =
*(new std::vector<std::string>{"usb:", "product:", "model:", "device:"});
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 75dcc86..04df16f 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -34,6 +34,8 @@
#include <android-base/unique_fd.h>
#include <android-base/utf8.h>
+#include "sysdeps/stat.h"
+
/*
* TEMP_FAILURE_RETRY is defined by some, but not all, versions of
* <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
@@ -199,8 +201,6 @@
/* nothing really */
}
-#define lstat stat /* no symlinks on Win32 */
-
#define S_ISLNK(m) 0 /* no symlinks on Win32 */
extern int adb_unlink(const char* path);
@@ -269,9 +269,6 @@
int unix_isatty(int fd);
#define isatty ___xxx_isatty
-/* normally provided by <cutils/misc.h> */
-extern void* load_file(const char* pathname, unsigned* psize);
-
static __inline__ void adb_sleep_ms( int mseconds )
{
Sleep( mseconds );
@@ -288,6 +285,9 @@
#undef accept
#define accept ___xxx_accept
+// Returns the local port number of a bound socket, or -1 on failure.
+int adb_socket_get_local_port(int fd);
+
extern int adb_setsockopt(int fd, int level, int optname, const void* optval, socklen_t optlen);
#undef setsockopt
@@ -307,27 +307,6 @@
return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
}
-// We later define a macro mapping 'stat' to 'adb_stat'. This causes:
-// struct stat s;
-// stat(filename, &s);
-// To turn into the following:
-// struct adb_stat s;
-// adb_stat(filename, &s);
-// To get this to work, we need to make 'struct adb_stat' the same as
-// 'struct stat'. Note that this definition of 'struct adb_stat' uses the
-// *current* macro definition of stat, so it may actually be inheriting from
-// struct _stat32i64 (or some other remapping).
-struct adb_stat : public stat {};
-
-static_assert(sizeof(struct adb_stat) == sizeof(struct stat),
- "structures should be the same");
-
-extern int adb_stat(const char* f, struct adb_stat* s);
-
-// stat is already a macro, undefine it so we can redefine it.
-#undef stat
-#define stat adb_stat
-
// UTF-8 versions of POSIX APIs.
extern DIR* adb_opendir(const char* dirname);
extern struct dirent* adb_readdir(DIR* dir);
@@ -455,7 +434,6 @@
#else /* !_WIN32 a.k.a. Unix */
-#include <cutils/misc.h>
#include <cutils/sockets.h>
#include <cutils/threads.h>
#include <fcntl.h>
@@ -692,6 +670,10 @@
#undef accept
#define accept ___xxx_accept
+inline int adb_socket_get_local_port(int fd) {
+ return socket_get_local_port(fd);
+}
+
// Operate on a file descriptor returned from unix_open() or a well-known file
// descriptor such as STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO.
//
diff --git a/adb/sysdeps/condition_variable.h b/adb/sysdeps/condition_variable.h
new file mode 100644
index 0000000..117cd40
--- /dev/null
+++ b/adb/sysdeps/condition_variable.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <condition_variable>
+
+#include "sysdeps/mutex.h"
+
+#if defined(_WIN32)
+
+#include <windows.h>
+
+#include <android-base/macros.h>
+
+// The prebuilt version of mingw we use doesn't support condition_variable.
+// Therefore, implement our own using the Windows primitives.
+// Put them directly into the std namespace, so that when they're actually available, the build
+// breaks until they're removed.
+
+namespace std {
+
+class condition_variable {
+ public:
+ condition_variable() {
+ InitializeConditionVariable(&cond_);
+ }
+
+ void wait(std::unique_lock<std::mutex>& lock) {
+ std::mutex *m = lock.mutex();
+ m->lock_count_--;
+ SleepConditionVariableCS(&cond_, m->native_handle(), INFINITE);
+ m->lock_count_++;
+ }
+
+ void notify_one() {
+ WakeConditionVariable(&cond_);
+ }
+
+ private:
+ CONDITION_VARIABLE cond_;
+
+ DISALLOW_COPY_AND_ASSIGN(condition_variable);
+};
+
+}
+
+#endif // defined(_WIN32)
diff --git a/adb/sysdeps/mutex.h b/adb/sysdeps/mutex.h
index 73c9e6e..226f7f1 100644
--- a/adb/sysdeps/mutex.h
+++ b/adb/sysdeps/mutex.h
@@ -1,5 +1,3 @@
-#pragma once
-
/*
* Copyright (C) 2016 The Android Open Source Project
*
@@ -16,6 +14,7 @@
* limitations under the License.
*/
+#pragma once
#if defined(_WIN32)
#include <windows.h>
@@ -35,34 +34,42 @@
// CRITICAL_SECTION is recursive, so just wrap it in a Mutex-compatible class.
class recursive_mutex {
public:
+ typedef CRITICAL_SECTION* native_handle_type;
+
recursive_mutex() {
- InitializeCriticalSection(&mutex_);
+ InitializeCriticalSection(&cs_);
}
~recursive_mutex() {
- DeleteCriticalSection(&mutex_);
+ DeleteCriticalSection(&cs_);
}
void lock() {
- EnterCriticalSection(&mutex_);
+ EnterCriticalSection(&cs_);
}
bool try_lock() {
- return TryEnterCriticalSection(&mutex_);
+ return TryEnterCriticalSection(&cs_);
}
void unlock() {
- LeaveCriticalSection(&mutex_);
+ LeaveCriticalSection(&cs_);
+ }
+
+ native_handle_type native_handle() {
+ return &cs_;
}
private:
- CRITICAL_SECTION mutex_;
+ CRITICAL_SECTION cs_;
DISALLOW_COPY_AND_ASSIGN(recursive_mutex);
};
class mutex {
public:
+ typedef CRITICAL_SECTION* native_handle_type;
+
mutex() {
}
@@ -97,11 +104,17 @@
return true;
}
+ native_handle_type native_handle() {
+ return mutex_.native_handle();
+ }
+
private:
recursive_mutex mutex_;
size_t lock_count_ = 0;
+
+ friend class condition_variable;
};
}
-#endif
+#endif // defined(_WIN32)
diff --git a/adb/sysdeps/stat.h b/adb/sysdeps/stat.h
new file mode 100644
index 0000000..5953595
--- /dev/null
+++ b/adb/sysdeps/stat.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if defined(_WIN32)
+// stat is broken on Win32: stat on a path with a trailing slash or backslash will always fail with
+// ENOENT.
+int adb_stat(const char* path, struct adb_stat* buf);
+
+// We later define a macro mapping 'stat' to 'adb_stat'. This causes:
+// struct stat s;
+// stat(filename, &s);
+// To turn into the following:
+// struct adb_stat s;
+// adb_stat(filename, &s);
+// To get this to work, we need to make 'struct adb_stat' the same as
+// 'struct stat'. Note that this definition of 'struct adb_stat' uses the
+// *current* macro definition of stat, so it may actually be inheriting from
+// struct _stat32i64 (or some other remapping).
+struct adb_stat : public stat {};
+
+#undef stat
+#define stat adb_stat
+
+// Windows doesn't have lstat.
+#define lstat adb_stat
+
+#endif
diff --git a/adb/sysdeps/stat_test.cpp b/adb/sysdeps/stat_test.cpp
new file mode 100644
index 0000000..2c2e0ee
--- /dev/null
+++ b/adb/sysdeps/stat_test.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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 <string>
+
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "adb_utils.h"
+#include "sysdeps.h"
+
+TEST(sysdeps, stat) {
+ TemporaryDir td;
+ TemporaryFile tf;
+
+ struct stat st;
+ ASSERT_EQ(0, stat(td.path, &st));
+ ASSERT_FALSE(S_ISREG(st.st_mode));
+ ASSERT_TRUE(S_ISDIR(st.st_mode));
+
+ ASSERT_EQ(0, stat((std::string(td.path) + '/').c_str(), &st));
+ ASSERT_TRUE(S_ISDIR(st.st_mode));
+
+#if defined(_WIN32)
+ ASSERT_EQ(0, stat((std::string(td.path) + '\\').c_str(), &st));
+ ASSERT_TRUE(S_ISDIR(st.st_mode));
+#endif
+
+ std::string nonexistent_path = std::string(td.path) + "/nonexistent";
+ ASSERT_EQ(-1, stat(nonexistent_path.c_str(), &st));
+ ASSERT_EQ(ENOENT, errno);
+
+ ASSERT_EQ(-1, stat((nonexistent_path + "/").c_str(), &st));
+ ASSERT_EQ(ENOENT, errno);
+
+#if defined(_WIN32)
+ ASSERT_EQ(-1, stat((nonexistent_path + "\\").c_str(), &st));
+ ASSERT_EQ(ENOENT, errno);
+#endif
+
+ ASSERT_EQ(0, stat(tf.path, &st));
+ ASSERT_TRUE(S_ISREG(st.st_mode));
+ ASSERT_FALSE(S_ISDIR(st.st_mode));
+
+ ASSERT_EQ(-1, stat((std::string(tf.path) + '/').c_str(), &st));
+ ASSERT_EQ(ENOTDIR, errno);
+
+#if defined(_WIN32)
+ ASSERT_EQ(-1, stat((std::string(tf.path) + '\\').c_str(), &st));
+ ASSERT_EQ(ENOTDIR, errno);
+#endif
+}
diff --git a/adb/sysdeps/win32/stat.cpp b/adb/sysdeps/win32/stat.cpp
new file mode 100644
index 0000000..844c1ce
--- /dev/null
+++ b/adb/sysdeps/win32/stat.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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 "sysdeps/stat.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/utf8.h>
+
+// Version of stat() that takes a UTF-8 path.
+int adb_stat(const char* path, struct adb_stat* s) {
+// This definition of wstat seems to be missing from <sys/stat.h>.
+#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
+#ifdef _USE_32BIT_TIME_T
+#define wstat _wstat32i64
+#else
+#define wstat _wstat64
+#endif
+#else
+// <sys/stat.h> has a function prototype for wstat() that should be available.
+#endif
+
+ std::wstring path_wide;
+ if (!android::base::UTF8ToWide(path, &path_wide)) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ // If the path has a trailing slash, stat will fail with ENOENT regardless of whether the path
+ // is a directory or not.
+ bool expected_directory = false;
+ while (*path_wide.rbegin() == u'/' || *path_wide.rbegin() == u'\\') {
+ path_wide.pop_back();
+ expected_directory = true;
+ }
+
+ struct adb_stat st;
+ int result = wstat(path_wide.c_str(), &st);
+ if (result == 0 && expected_directory) {
+ if (!S_ISDIR(st.st_mode)) {
+ errno = ENOTDIR;
+ return -1;
+ }
+ }
+
+ memcpy(s, &st, sizeof(st));
+ return result;
+}
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 5ac8f82..740f283 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -20,6 +20,8 @@
#include "adb_io.h"
#include "sysdeps.h"
+#include "sysdeps/condition_variable.h"
+#include "sysdeps/mutex.h"
static void increment_atomic_int(void* c) {
sleep(1);
@@ -218,7 +220,7 @@
TEST_F(sysdeps_poll, fd_count) {
// https://code.google.com/p/android/issues/detail?id=12141
- static constexpr int num_sockets = 512;
+ static constexpr int num_sockets = 256;
std::vector<int> sockets;
std::vector<adb_pollfd> pfds;
sockets.resize(num_sockets * 2);
@@ -245,7 +247,6 @@
}
}
-#include "sysdeps/mutex.h"
TEST(sysdeps_mutex, mutex_smoke) {
static std::atomic<bool> finished(false);
static std::mutex &m = *new std::mutex();
@@ -301,3 +302,21 @@
m.lock();
m.unlock();
}
+
+TEST(sysdeps_condition_variable, smoke) {
+ static std::mutex &m = *new std::mutex;
+ static std::condition_variable &cond = *new std::condition_variable;
+ static volatile bool flag = false;
+
+ std::unique_lock<std::mutex> lock(m);
+ adb_thread_create([](void*) {
+ m.lock();
+ flag = true;
+ cond.notify_one();
+ m.unlock();
+ }, nullptr);
+
+ while (!flag) {
+ cond.wait(lock);
+ }
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index bc09fdc..ee27406 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -110,62 +110,6 @@
/**************************************************************************/
/**************************************************************************/
/***** *****/
-/***** replaces libs/cutils/load_file.c *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
-
-void *load_file(const char *fn, unsigned *_sz)
-{
- HANDLE file;
- char *data;
- DWORD file_size;
-
- std::wstring fn_wide;
- if (!android::base::UTF8ToWide(fn, &fn_wide))
- return NULL;
-
- file = CreateFileW( fn_wide.c_str(),
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL );
-
- if (file == INVALID_HANDLE_VALUE)
- return NULL;
-
- file_size = GetFileSize( file, NULL );
- data = NULL;
-
- if (file_size > 0) {
- data = (char*) malloc( file_size + 1 );
- if (data == NULL) {
- D("load_file: could not allocate %ld bytes", file_size );
- file_size = 0;
- } else {
- DWORD out_bytes;
-
- if ( !ReadFile( file, data, file_size, &out_bytes, NULL ) ||
- out_bytes != file_size )
- {
- D("load_file: could not read %ld bytes from '%s'", file_size, fn);
- free(data);
- data = NULL;
- file_size = 0;
- }
- }
- }
- CloseHandle( file );
-
- *_sz = (unsigned) file_size;
- return data;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
/***** common file descriptor handling *****/
/***** *****/
/**************************************************************************/
@@ -1128,6 +1072,24 @@
return result;
}
+int adb_socket_get_local_port(int fd) {
+ sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+
+ if (adb_getsockname(fd, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
+ D("adb_socket_get_local_port: adb_getsockname failed: %s", strerror(errno));
+ return -1;
+ }
+
+ if (!(addr_storage.ss_family == AF_INET || addr_storage.ss_family == AF_INET6)) {
+ D("adb_socket_get_local_port: unknown address family received: %d", addr_storage.ss_family);
+ errno = ECONNABORTED;
+ return -1;
+ }
+
+ return ntohs(reinterpret_cast<sockaddr_in*>(&addr_storage)->sin_port);
+}
+
int adb_shutdown(int fd)
{
FH f = _fh_from_int(fd, __func__);
@@ -1154,9 +1116,7 @@
int server = -1;
int client = -1;
int accepted = -1;
- sockaddr_storage addr_storage;
- socklen_t addr_len = sizeof(addr_storage);
- sockaddr_in* addr = nullptr;
+ int local_port = -1;
std::string error;
server = network_loopback_server(0, SOCK_STREAM, &error);
@@ -1165,20 +1125,14 @@
goto fail;
}
- if (adb_getsockname(server, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
- D("adb_socketpair: adb_getsockname failed: %s", strerror(errno));
+ local_port = adb_socket_get_local_port(server);
+ if (local_port < 0) {
+ D("adb_socketpair: failed to get server port number: %s", error.c_str());
goto fail;
}
+ D("adb_socketpair: bound on port %d", local_port);
- if (addr_storage.ss_family != AF_INET) {
- D("adb_socketpair: unknown address family received: %d", addr_storage.ss_family);
- errno = ECONNABORTED;
- goto fail;
- }
-
- addr = reinterpret_cast<sockaddr_in*>(&addr_storage);
- D("adb_socketpair: bound on port %d", ntohs(addr->sin_port));
- client = network_loopback_client(ntohs(addr->sin_port), SOCK_STREAM, &error);
+ client = network_loopback_client(local_port, SOCK_STREAM, &error);
if (client < 0) {
D("adb_socketpair: failed to connect client: %s", error.c_str());
goto fail;
@@ -2298,30 +2252,6 @@
}
}
-// Version of stat() that takes a UTF-8 path.
-int adb_stat(const char* path, struct adb_stat* s) {
-#pragma push_macro("wstat")
-// This definition of wstat seems to be missing from <sys/stat.h>.
-#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
-#ifdef _USE_32BIT_TIME_T
-#define wstat _wstat32i64
-#else
-#define wstat _wstat64
-#endif
-#else
-// <sys/stat.h> has a function prototype for wstat() that should be available.
-#endif
-
- std::wstring path_wide;
- if (!android::base::UTF8ToWide(path, &path_wide)) {
- return -1;
- }
-
- return wstat(path_wide.c_str(), s);
-
-#pragma pop_macro("wstat")
-}
-
// Version of opendir() that takes a UTF-8 path.
DIR* adb_opendir(const char* path) {
std::wstring path_wide;
diff --git a/adb/test_device.py b/adb/test_device.py
index 9dab3ae..2efac9d 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -31,6 +31,7 @@
import subprocess
import sys
import tempfile
+import time
import unittest
import mock
@@ -191,6 +192,22 @@
msg = self.device.forward_list()
self.assertEqual('', msg.strip())
+ def test_forward_tcp_port_0(self):
+ self.assertEqual('', self.device.forward_list().strip(),
+ 'Forwarding list must be empty to run this test.')
+
+ try:
+ # If resolving TCP port 0 is supported, `adb forward` will print
+ # the actual port number.
+ port = self.device.forward('tcp:0', 'tcp:8888').strip()
+ if not port:
+ raise unittest.SkipTest('Forwarding tcp:0 is not available.')
+
+ self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+ self.device.forward_list()))
+ finally:
+ self.device.forward_remove_all()
+
def test_reverse(self):
msg = self.device.reverse_list()
self.assertEqual('', msg.strip(),
@@ -210,6 +227,22 @@
msg = self.device.reverse_list()
self.assertEqual('', msg.strip())
+ def test_reverse_tcp_port_0(self):
+ self.assertEqual('', self.device.reverse_list().strip(),
+ 'Reverse list must be empty to run this test.')
+
+ try:
+ # If resolving TCP port 0 is supported, `adb reverse` will print
+ # the actual port number.
+ port = self.device.reverse('tcp:0', 'tcp:8888').strip()
+ if not port:
+ raise unittest.SkipTest('Reversing tcp:0 is not available.')
+
+ self.assertTrue(re.search(r'tcp:{}.+tcp:8888'.format(port),
+ self.device.reverse_list()))
+ finally:
+ self.device.reverse_remove_all()
+
# Note: If you run this test when adb connect'd to a physical device over
# TCP, it will fail in adb reverse due to https://code.google.com/p/android/issues/detail?id=189821
def test_forward_reverse_echo(self):
@@ -279,7 +312,7 @@
Raises:
unittest.SkipTest: The device doesn't support exit codes.
"""
- if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+ if not self.device.has_shell_protocol():
raise unittest.SkipTest('exit codes are unavailable on this device')
proc = subprocess.Popen(
@@ -342,7 +375,7 @@
a terminal stdin to test so this test will be skipped if stdin
is not a terminal.
"""
- if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+ if not self.device.has_shell_protocol():
raise unittest.SkipTest('PTY arguments unsupported on this device')
if not os.isatty(sys.stdin.fileno()):
raise unittest.SkipTest('PTY tests require stdin terminal')
@@ -394,7 +427,7 @@
Bug: http://b/19734861
"""
- if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+ if not self.device.has_shell_protocol():
raise unittest.SkipTest('shell protocol unsupported on this device')
# Shell protocol should be used by default.
@@ -424,7 +457,7 @@
Bug: http://b/23825725
"""
- if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+ if not self.device.has_shell_protocol():
raise unittest.SkipTest('shell protocol unsupported on this device')
# Start a long-running process.
@@ -445,7 +478,7 @@
def test_non_interactive_stdin(self):
"""Tests that non-interactive shells send stdin."""
- if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
+ if not self.device.has_shell_protocol():
raise unittest.SkipTest('non-interactive stdin unsupported '
'on this device')
@@ -463,6 +496,36 @@
self.assertEqual(input.splitlines(), stdout.splitlines())
self.assertEqual('', stderr)
+ def test_sighup(self):
+ """Ensure that SIGHUP gets sent upon non-interactive ctrl-c"""
+ log_path = "/data/local/tmp/adb_signal_test.log"
+
+ # Clear the output file.
+ self.device.shell_nocheck(["echo", ">", log_path])
+
+ script = """
+ trap "echo SIGINT > {path}; exit 0" SIGINT
+ trap "echo SIGHUP > {path}; exit 0" SIGHUP
+ echo Waiting
+ while true; do sleep 100; done
+ """.format(path=log_path)
+
+ script = ";".join([x.strip() for x in script.strip().splitlines()])
+
+ process = self.device.shell_popen(
+ ["sh", "-c", "'{}'".format(script)], kill_atexit=False, stdout=subprocess.PIPE)
+
+ self.assertEqual("Waiting\n", process.stdout.readline())
+ process.send_signal(signal.SIGINT)
+ process.wait()
+
+ # Waiting for the local adb to finish is insufficient, since it hangs
+ # up immediately.
+ time.sleep(0.25)
+
+ stdout, _ = self.device.shell(["cat", log_path])
+ self.assertEqual(stdout.strip(), "SIGHUP")
+
class ArgumentEscapingTest(DeviceTest):
def test_shell_escaping(self):
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
deleted file mode 100644
index b10f8ee..0000000
--- a/adb/test_track_devices.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-// TODO: replace this with a shell/python script.
-
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <errno.h>
-#include <memory.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-
-static void
-panic( const char* msg )
-{
- fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
- exit(1);
-}
-
-int main(int argc, char* argv[]) {
- const char* request = "host:track-devices";
-
- if (argv[1] && strcmp(argv[1], "--jdwp") == 0) {
- request = "track-jdwp";
- }
-
- int ret;
- struct sockaddr_in server;
- char buffer[1024];
-
- memset( &server, 0, sizeof(server) );
- server.sin_family = AF_INET;
- server.sin_port = htons(5037);
- server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- int s = socket( PF_INET, SOCK_STREAM, 0 );
- ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
- if (ret < 0) panic( "could not connect to server" );
-
- /* send the request */
- int len = snprintf(buffer, sizeof(buffer), "%04zx%s", strlen(request), request);
- if (!android::base::WriteFully(s, buffer, len))
- panic( "could not send request" );
-
- /* read the OKAY answer */
- if (!android::base::ReadFully(s, buffer, 4))
- panic( "could not read request" );
-
- printf( "server answer: %.*s\n", 4, buffer );
-
- /* now loop */
- while (true) {
- char head[5] = "0000";
-
- if (!android::base::ReadFully(s, head, 4))
- panic("could not read length");
-
- int len;
- if (sscanf(head, "%04x", &len) != 1 )
- panic("could not decode length");
-
- if (!android::base::ReadFully(s, buffer, len))
- panic("could not read data");
-
- printf( "received header %.*s (%d bytes):\n%.*s----\n", 4, head, len, len, buffer );
- }
- close(s);
-}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index c31f655..ad63a6a 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -950,6 +950,8 @@
for (const auto& transport : pending_list) {
if (transport->serial && strcmp(serial, transport->serial) == 0) {
adb_mutex_unlock(&transport_lock);
+ VLOG(TRANSPORT) << "socket transport " << transport->serial
+ << " is already in pending_list and fails to register";
delete t;
return -1;
}
@@ -958,6 +960,8 @@
for (const auto& transport : transport_list) {
if (transport->serial && strcmp(serial, transport->serial) == 0) {
adb_mutex_unlock(&transport_lock);
+ VLOG(TRANSPORT) << "socket transport " << transport->serial
+ << " is already in transport_list and fails to register";
delete t;
return -1;
}
@@ -990,8 +994,7 @@
void kick_all_tcp_devices() {
adb_mutex_lock(&transport_lock);
for (auto& t : transport_list) {
- // TCP/IP devices have adb_port == 0.
- if (t->type == kTransportLocal && t->adb_port == 0) {
+ if (t->IsTcpDevice()) {
// Kicking breaks the read_transport thread of this transport out of any read, then
// the read_transport thread will notify the main thread to make this transport
// offline. Then the main thread will notify the write_transport thread to exit.
diff --git a/adb/transport.h b/adb/transport.h
index 35d7b50..46d472b 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -87,7 +87,22 @@
char* model = nullptr;
char* device = nullptr;
char* devpath = nullptr;
- int adb_port = -1; // Use for emulators (local transport)
+ void SetLocalPortForEmulator(int port) {
+ CHECK_EQ(local_port_for_emulator_, -1);
+ local_port_for_emulator_ = port;
+ }
+
+ bool GetLocalPortForEmulator(int* port) const {
+ if (type == kTransportLocal && local_port_for_emulator_ != -1) {
+ *port = local_port_for_emulator_;
+ return true;
+ }
+ return false;
+ }
+
+ bool IsTcpDevice() const {
+ return type == kTransportLocal && local_port_for_emulator_ == -1;
+ }
void* key = nullptr;
unsigned char token[TOKEN_SIZE] = {};
@@ -128,6 +143,7 @@
bool MatchesTarget(const std::string& target) const;
private:
+ int local_port_for_emulator_ = -1;
bool kicked_ = false;
void (*kick_func_)(atransport*) = nullptr;
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 4f3e1f5..cc19785 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -17,6 +17,8 @@
#define TRACE_TAG TRANSPORT
#include "sysdeps.h"
+#include "sysdeps/condition_variable.h"
+#include "sysdeps/mutex.h"
#include "transport.h"
#include <errno.h>
@@ -25,6 +27,8 @@
#include <string.h>
#include <sys/types.h>
+#include <vector>
+
#include <android-base/stringprintf.h>
#include <cutils/sockets.h>
@@ -90,9 +94,9 @@
return 0;
}
-void local_connect(int port) {
+bool local_connect(int port) {
std::string dummy;
- local_connect_arbitrary_ports(port-1, port, &dummy);
+ return local_connect_arbitrary_ports(port-1, port, &dummy) == 0;
}
int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* error) {
@@ -126,18 +130,71 @@
}
#if ADB_HOST
+
+static void PollAllLocalPortsForEmulator() {
+ int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+ int count = ADB_LOCAL_TRANSPORT_MAX;
+
+ // Try to connect to any number of running emulator instances.
+ for ( ; count > 0; count--, port += 2 ) {
+ local_connect(port);
+ }
+}
+
+// Retry the disconnected local port for 60 times, and sleep 1 second between two retries.
+constexpr uint32_t LOCAL_PORT_RETRY_COUNT = 60;
+constexpr uint32_t LOCAL_PORT_RETRY_INTERVAL_IN_MS = 1000;
+
+struct RetryPort {
+ int port;
+ uint32_t retry_count;
+};
+
+// Retry emulators just kicked.
+static std::vector<RetryPort>& retry_ports = *new std::vector<RetryPort>;
+std::mutex &retry_ports_lock = *new std::mutex;
+std::condition_variable &retry_ports_cond = *new std::condition_variable;
+
static void client_socket_thread(void* x) {
adb_thread_setname("client_socket_thread");
D("transport: client_socket_thread() starting");
+ PollAllLocalPortsForEmulator();
while (true) {
- int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
- int count = ADB_LOCAL_TRANSPORT_MAX;
-
- // Try to connect to any number of running emulator instances.
- for ( ; count > 0; count--, port += 2 ) {
- local_connect(port);
+ std::vector<RetryPort> ports;
+ // Collect retry ports.
+ {
+ std::unique_lock<std::mutex> lock(retry_ports_lock);
+ while (retry_ports.empty()) {
+ retry_ports_cond.wait(lock);
+ }
+ retry_ports.swap(ports);
}
- sleep(1);
+ // Sleep here instead of the end of loop, because if we immediately try to reconnect
+ // the emulator just kicked, the adbd on the emulator may not have time to remove the
+ // just kicked transport.
+ adb_sleep_ms(LOCAL_PORT_RETRY_INTERVAL_IN_MS);
+
+ // Try connecting retry ports.
+ std::vector<RetryPort> next_ports;
+ for (auto& port : ports) {
+ VLOG(TRANSPORT) << "retry port " << port.port << ", last retry_count "
+ << port.retry_count;
+ if (local_connect(port.port)) {
+ VLOG(TRANSPORT) << "retry port " << port.port << " successfully";
+ continue;
+ }
+ if (--port.retry_count > 0) {
+ next_ports.push_back(port);
+ } else {
+ VLOG(TRANSPORT) << "stop retrying port " << port.port;
+ }
+ }
+
+ // Copy back left retry ports.
+ {
+ std::unique_lock<std::mutex> lock(retry_ports_lock);
+ retry_ports.insert(retry_ports.end(), next_ports.begin(), next_ports.end());
+ }
}
}
@@ -172,7 +229,9 @@
D("server: new connection on fd %d", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
- register_socket_transport(fd, "host", port, 1);
+ if (register_socket_transport(fd, "host", port, 1) != 0) {
+ adb_close(fd);
+ }
}
}
D("transport: server_socket_thread() exiting");
@@ -181,16 +240,20 @@
/* This is relevant only for ADB daemon running inside the emulator. */
/*
* Redefine open and write for qemu_pipe.h that contains inlined references
- * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ * to those routines. We will redefine them back after qemu_pipe.h inclusion.
*/
#undef open
+#undef read
#undef write
#define open adb_open
+#define read adb_read
#define write adb_write
-#include <hardware/qemu_pipe.h>
+#include <system/qemu_pipe.h>
#undef open
+#undef read
#undef write
#define open ___xxx_open
+#define read ___xxx_read
#define write ___xxx_write
/* A worker thread that monitors host connections, and registers a transport for
@@ -238,7 +301,7 @@
D("transport: qemu_socket_thread() starting");
/* adb QEMUD service connection request. */
- snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port);
+ snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
/* Connect to the adb QEMUD service. */
fd = qemu_pipe_open(con_name);
@@ -266,8 +329,8 @@
/* Host is connected. Register the transport, and start the
* exchange. */
std::string serial = android::base::StringPrintf("host-%d", fd);
- register_socket_transport(fd, serial.c_str(), port, 1);
- if (!WriteFdExactly(fd, _start_req, strlen(_start_req))) {
+ if (register_socket_transport(fd, serial.c_str(), port, 1) != 0 ||
+ !WriteFdExactly(fd, _start_req, strlen(_start_req))) {
adb_close(fd);
}
}
@@ -344,17 +407,32 @@
t->sfd = -1;
adb_close(fd);
}
+#if ADB_HOST
+ int local_port;
+ if (t->GetLocalPortForEmulator(&local_port)) {
+ VLOG(TRANSPORT) << "remote_close, local_port = " << local_port;
+ std::unique_lock<std::mutex> lock(retry_ports_lock);
+ RetryPort port;
+ port.port = local_port;
+ port.retry_count = LOCAL_PORT_RETRY_COUNT;
+ retry_ports.push_back(port);
+ retry_ports_cond.notify_one();
+ }
+#endif
}
#if ADB_HOST
/* Only call this function if you already hold local_transports_lock. */
-atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
+static atransport* find_emulator_transport_by_adb_port_locked(int adb_port)
{
int i;
for (i = 0; i < ADB_LOCAL_TRANSPORT_MAX; i++) {
- if (local_transports[i] && local_transports[i]->adb_port == adb_port) {
- return local_transports[i];
+ int local_port;
+ if (local_transports[i] && local_transports[i]->GetLocalPortForEmulator(&local_port)) {
+ if (local_port == adb_port) {
+ return local_transports[i];
+ }
}
}
return NULL;
@@ -401,13 +479,12 @@
t->sync_token = 1;
t->connection_state = kCsOffline;
t->type = kTransportLocal;
- t->adb_port = 0;
#if ADB_HOST
if (local) {
adb_mutex_lock( &local_transports_lock );
{
- t->adb_port = adb_port;
+ t->SetLocalPortForEmulator(adb_port);
atransport* existing_transport =
find_emulator_transport_by_adb_port_locked(adb_port);
int index = get_available_local_transport_index_locked();
diff --git a/adf/Android.bp b/adf/Android.bp
new file mode 100644
index 0000000..b44c296
--- /dev/null
+++ b/adf/Android.bp
@@ -0,0 +1 @@
+subdirs = ["*"]
diff --git a/adf/libadf/Android.bp b/adf/libadf/Android.bp
new file mode 100644
index 0000000..2b5461e
--- /dev/null
+++ b/adf/libadf/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+ name: "libadf",
+ srcs: ["adf.c"],
+ cflags: ["-Werror"],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
diff --git a/adf/libadf/tests/Android.bp b/adf/libadf/tests/Android.bp
new file mode 100644
index 0000000..7b33300
--- /dev/null
+++ b/adf/libadf/tests/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "adf-unit-tests",
+ srcs: ["adf_test.cpp"],
+ static_libs: ["libadf"],
+ cflags: ["-Werror"],
+}
diff --git a/adf/libadf/tests/Android.mk b/adf/libadf/tests/Android.mk
deleted file mode 100644
index 68e5817..0000000
--- a/adf/libadf/tests/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH := $(my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adf_test.cpp
-LOCAL_MODULE := adf-unit-tests
-LOCAL_STATIC_LIBRARIES := libadf
-LOCAL_CFLAGS += -Werror
-include $(BUILD_NATIVE_TEST)
diff --git a/adf/libadfhwc/Android.bp b/adf/libadfhwc/Android.bp
new file mode 100644
index 0000000..86f0c9c
--- /dev/null
+++ b/adf/libadfhwc/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+ name: "libadfhwc",
+ srcs: ["adfhwc.cpp"],
+ static_libs: [
+ "libadf",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-DLOG_TAG=\\\"adfhwc\\\"",
+ "-Werror",
+ ],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
diff --git a/base/Android.bp b/base/Android.bp
new file mode 100644
index 0000000..7bf4c79
--- /dev/null
+++ b/base/Android.bp
@@ -0,0 +1,96 @@
+//
+// Copyright (C) 2015 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.
+//
+
+libbase_cppflags = [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+]
+
+cc_library {
+ name: "libbase",
+ clang: true,
+ host_supported: true,
+ srcs: [
+ "file.cpp",
+ "logging.cpp",
+ "parsenetaddress.cpp",
+ "stringprintf.cpp",
+ "strings.cpp",
+ "test_utils.cpp",
+ ],
+ local_include_dirs: ["include"],
+ cppflags: libbase_cppflags,
+ export_include_dirs: ["include"],
+ shared_libs: ["liblog"],
+ target: {
+ android: {
+ srcs: ["errors_unix.cpp"],
+ cppflags: ["-Wexit-time-destructors"],
+ },
+ darwin: {
+ srcs: ["errors_unix.cpp"],
+ cppflags: ["-Wexit-time-destructors"],
+ },
+ linux: {
+ srcs: ["errors_unix.cpp"],
+ cppflags: ["-Wexit-time-destructors"],
+ },
+ windows: {
+ srcs: [
+ "errors_windows.cpp",
+ "utf8.cpp",
+ ],
+ enabled: true,
+ },
+ },
+}
+
+// Tests
+// ------------------------------------------------------------------------------
+cc_test {
+ name: "libbase_test",
+ host_supported: true,
+ clang: true,
+ srcs: [
+ "errors_test.cpp",
+ "file_test.cpp",
+ "logging_test.cpp",
+ "parseint_test.cpp",
+ "parsenetaddress_test.cpp",
+ "stringprintf_test.cpp",
+ "strings_test.cpp",
+ "test_main.cpp",
+ ],
+ target: {
+ windows: {
+ srcs: ["utf8_test.cpp"],
+ enabled: true,
+ },
+ },
+ local_include_dirs: ["."],
+ cppflags: libbase_cppflags,
+ shared_libs: ["libbase"],
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+}
diff --git a/base/Android.mk b/base/Android.mk
deleted file mode 100644
index 1693e74..0000000
--- a/base/Android.mk
+++ /dev/null
@@ -1,140 +0,0 @@
-#
-# Copyright (C) 2015 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-libbase_src_files := \
- file.cpp \
- logging.cpp \
- parsenetaddress.cpp \
- stringprintf.cpp \
- strings.cpp \
- test_utils.cpp \
-
-libbase_linux_src_files := \
- errors_unix.cpp \
-
-libbase_darwin_src_files := \
- errors_unix.cpp \
-
-libbase_windows_src_files := \
- errors_windows.cpp \
- utf8.cpp \
-
-libbase_test_src_files := \
- errors_test.cpp \
- file_test.cpp \
- logging_test.cpp \
- parseint_test.cpp \
- parsenetaddress_test.cpp \
- stringprintf_test.cpp \
- strings_test.cpp \
- test_main.cpp \
-
-libbase_test_windows_src_files := \
- utf8_test.cpp \
-
-libbase_cppflags := \
- -Wall \
- -Wextra \
- -Werror \
-
-libbase_linux_cppflags := \
- -Wexit-time-destructors \
-
-libbase_darwin_cppflags := \
- -Wexit-time-destructors \
-
-# Device
-# ------------------------------------------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(libbase_src_files) $(libbase_linux_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CPPFLAGS := $(libbase_cppflags) $(libbase_linux_cppflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_MULTILIB := both
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_CLANG := true
-LOCAL_WHOLE_STATIC_LIBRARIES := libbase
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_MULTILIB := both
-include $(BUILD_SHARED_LIBRARY)
-
-# Host
-# ------------------------------------------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_SRC_FILES := $(libbase_src_files)
-LOCAL_SRC_FILES_darwin := $(libbase_darwin_src_files)
-LOCAL_SRC_FILES_linux := $(libbase_linux_src_files)
-LOCAL_SRC_FILES_windows := $(libbase_windows_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CPPFLAGS := $(libbase_cppflags)
-LOCAL_CPPFLAGS_darwin := $(libbase_darwin_cppflags)
-LOCAL_CPPFLAGS_linux := $(libbase_linux_cppflags)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase
-LOCAL_WHOLE_STATIC_LIBRARIES := libbase
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Tests
-# ------------------------------------------------------------------------------
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase_test
-LOCAL_CLANG := true
-LOCAL_SRC_FILES := $(libbase_test_src_files)
-LOCAL_SRC_FILES_darwin := $(libbase_test_darwin_src_files)
-LOCAL_SRC_FILES_linux := $(libbase_test_linux_src_files)
-LOCAL_SRC_FILES_windows := $(libbase_test_windows_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_CPPFLAGS := $(libbase_cppflags)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libbase_test
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_SRC_FILES := $(libbase_test_src_files)
-LOCAL_SRC_FILES_darwin := $(libbase_test_darwin_src_files)
-LOCAL_SRC_FILES_linux := $(libbase_test_linux_src_files)
-LOCAL_SRC_FILES_windows := $(libbase_test_windows_src_files)
-LOCAL_C_INCLUDES := $(LOCAL_PATH)
-LOCAL_CPPFLAGS := $(libbase_cppflags)
-LOCAL_SHARED_LIBRARIES := libbase
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/base/file.cpp b/base/file.cpp
index da1adba..4e7ac82 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -24,9 +24,8 @@
#include <string>
#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
+#include "android-base/logging.h"
#include "android-base/utf8.h"
-#define LOG_TAG "base.file"
-#include "cutils/log.h"
#include "utils/Compat.h"
namespace android {
@@ -86,22 +85,22 @@
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
if (fd == -1) {
- ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
+ PLOG(ERROR) << "android::WriteStringToFile open failed";
return false;
}
// We do an explicit fchmod here because we assume that the caller really
// meant what they said and doesn't want the umask-influenced mode.
if (fchmod(fd, mode) == -1) {
- ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno));
+ PLOG(ERROR) << "android::WriteStringToFile fchmod failed";
return CleanUpAfterFailedWrite(path);
}
if (fchown(fd, owner, group) == -1) {
- ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno));
+ PLOG(ERROR) << "android::WriteStringToFile fchown failed";
return CleanUpAfterFailedWrite(path);
}
if (!WriteStringToFd(content, fd)) {
- ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
+ PLOG(ERROR) << "android::WriteStringToFile write failed";
return CleanUpAfterFailedWrite(path);
}
close(fd);
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index d3f9d0c..56e2dde 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -147,6 +147,14 @@
#define UNIMPLEMENTED(level) \
LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
+#ifdef __clang_analyzer__
+// ClangL static analyzer does not see the conditional statement inside
+// LogMessage's destructor that will abort on FATAL severity.
+#define ABORT_AFTER_LOG_FATAL for (;;abort())
+#else
+#define ABORT_AFTER_LOG_FATAL
+#endif
+
// Check whether condition x holds and LOG(FATAL) if not. The value of the
// expression x is only evaluated once. Extra logging can be appended using <<
// after. For example:
@@ -155,6 +163,7 @@
// "Check failed: false == true".
#define CHECK(x) \
LIKELY((x)) || \
+ ABORT_AFTER_LOG_FATAL \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
::android::base::FATAL, -1).stream() \
<< "Check failed: " #x << " "
@@ -164,6 +173,7 @@
for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \
UNLIKELY(!(_values.lhs OP _values.rhs)); \
/* empty */) \
+ ABORT_AFTER_LOG_FATAL \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
::android::base::FATAL, -1).stream() \
<< "Check failed: " << #LHS << " " << #OP << " " << #RHS \
@@ -184,12 +194,13 @@
// Helper for CHECK_STRxx(s1,s2) macros.
#define CHECK_STROP(s1, s2, sense) \
- if (LIKELY((strcmp(s1, s2) == 0) == sense)) \
+ if (LIKELY((strcmp(s1, s2) == 0) == (sense))) \
; \
else \
+ ABORT_AFTER_LOG_FATAL \
LOG(FATAL) << "Check failed: " \
- << "\"" << s1 << "\"" \
- << (sense ? " == " : " != ") << "\"" << s2 << "\""
+ << "\"" << (s1) << "\"" \
+ << ((sense) ? " == " : " != ") << "\"" << (s2) << "\""
// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
@@ -201,7 +212,8 @@
int rc = call args; \
if (rc != 0) { \
errno = rc; \
- PLOG(FATAL) << #call << " failed for " << what; \
+ ABORT_AFTER_LOG_FATAL \
+ PLOG(FATAL) << #call << " failed for " << (what); \
} \
} while (false)
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 913a9a0..299ec35 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -123,8 +123,11 @@
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-#define LIKELY(x) __builtin_expect((x), true)
-#define UNLIKELY(x) __builtin_expect((x), false)
+// Changing this definition will cause you a lot of pain. A majority of
+// vendor code defines LIKELY and UNLIKELY this way, and includes
+// this header through an indirect path.
+#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
+#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false ))
#define WARN_UNUSED __attribute__((warn_unused_result))
diff --git a/base/logging.cpp b/base/logging.cpp
index 1741871..959bb8b 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -21,6 +21,7 @@
#include "android-base/logging.h"
#include <libgen.h>
+#include <time.h>
// For getprogname(3) or program_invocation_short_name.
#if defined(__ANDROID__) || defined(__APPLE__)
@@ -42,12 +43,11 @@
#include "android-base/macros.h"
#include "android-base/strings.h"
-#include "cutils/threads.h"
// Headers for LogMessage::LogLine.
#ifdef __ANDROID__
#include <android/set_abort_message.h>
-#include "cutils/log.h"
+#include "log/log.h"
#else
#include <sys/types.h>
#include <unistd.h>
@@ -186,12 +186,24 @@
void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
unsigned int line, const char* message) {
+ struct tm now;
+ time_t t = time(nullptr);
+
+#if defined(_WIN32)
+ localtime_s(&now, &t);
+#else
+ localtime_r(&t, &now);
+#endif
+
+ char timestamp[32];
+ strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
+
static const char log_characters[] = "VDIWEF";
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
char severity_char = log_characters[severity];
- fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
- severity_char, getpid(), GetThreadId(), file, line, message);
+ fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", ProgramInvocationName(),
+ severity_char, timestamp, getpid(), GetThreadId(), file, line, message);
}
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index 337ba7c..635af6c 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -16,7 +16,6 @@
#include "android-base/logging.h"
#include "android-base/test_utils.h"
-#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
#include <fcntl.h>
#include <stdio.h>
@@ -27,6 +26,9 @@
#if defined(_WIN32)
#include <windows.h>
#include <direct.h>
+#define OS_PATH_SEPARATOR '\\'
+#else
+#define OS_PATH_SEPARATOR '/'
#endif
#include <string>
diff --git a/bootstat/Android.mk b/bootstat/Android.mk
index 6300941..bdd680d 100644
--- a/bootstat/Android.mk
+++ b/bootstat/Android.mk
@@ -16,8 +16,6 @@
LOCAL_PATH := $(call my-dir)
-bootstat_c_includes := external/gtest/include
-
bootstat_lib_src_files := \
boot_event_record_store.cpp \
event_log_list_builder.cpp \
@@ -57,7 +55,7 @@
LOCAL_MODULE := libbootstat
LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
# Clang is required because of C++14
@@ -72,7 +70,7 @@
LOCAL_MODULE := libbootstat_debug
LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
# Clang is required because of C++14
@@ -87,7 +85,7 @@
LOCAL_MODULE := libbootstat_host_debug
LOCAL_CFLAGS := $(bootstat_debug_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_SRC_FILES := $(bootstat_lib_src_files)
# Clang is required because of C++14
@@ -102,7 +100,7 @@
LOCAL_MODULE := bootstat
LOCAL_CFLAGS := $(bootstat_cflags)
-LOCAL_C_INCLUDES := $(bootstat_c_includes)
+LOCAL_WHOLE_STATIC_LIBRARIES := libgtest_prod
LOCAL_SHARED_LIBRARIES := $(bootstat_shared_libs)
LOCAL_STATIC_LIBRARIES := libbootstat
LOCAL_INIT_RC := bootstat.rc
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 26e0ffc..71a5a39 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -49,6 +49,22 @@
}
}
+// Records the named boot |event| to the record store. If |value| is non-empty
+// and is a proper string representation of an integer value, the converted
+// integer value is associated with the boot event.
+void RecordBootEventFromCommandLine(
+ const std::string& event, const std::string& value_str) {
+ BootEventRecordStore boot_event_store;
+ if (!value_str.empty()) {
+ int32_t value = 0;
+ if (android::base::ParseInt(value_str.c_str(), &value)) {
+ boot_event_store.AddBootEventWithValue(event, value);
+ }
+ } else {
+ boot_event_store.AddBootEvent(event);
+ }
+}
+
void PrintBootEvents() {
printf("Boot events:\n");
printf("------------\n");
@@ -68,6 +84,7 @@
" -l, --log Log all metrics to logstorage\n"
" -p, --print Dump the boot event records to the console\n"
" -r, --record Record the timestamp of a named boot event\n"
+ " --value Optional value to associate with the boot event\n"
" --record_boot_reason Record the reason why the device booted\n"
" --record_time_since_factory_reset Record the time since the device was reset\n");
}
@@ -122,6 +139,30 @@
{"Reboot", 18},
{"rtc", 19},
{"edl", 20},
+ {"oem_pon1", 21},
+ {"oem_powerkey", 22},
+ {"oem_unknown_reset", 23},
+ {"srto: HWWDT reset SC", 24},
+ {"srto: HWWDT reset platform", 25},
+ {"srto: bootloader", 26},
+ {"srto: kernel panic", 27},
+ {"srto: kernel watchdog reset", 28},
+ {"srto: normal", 29},
+ {"srto: reboot", 30},
+ {"srto: reboot-bootloader", 31},
+ {"srto: security watchdog reset", 32},
+ {"srto: wakesrc", 33},
+ {"srto: watchdog", 34},
+ {"srto:1-1", 35},
+ {"srto:omap_hsmm", 36},
+ {"srto:phy0", 37},
+ {"srto:rtc0", 38},
+ {"srto:touchpad", 39},
+ {"watchdog", 40},
+ {"watchdogr", 41},
+ {"wdog_bark", 42},
+ {"wdog_bite", 43},
+ {"wdog_reset", 44},
};
// Converts a string value representing the reason the system booted to an
@@ -169,7 +210,19 @@
void RecordBootComplete() {
BootEventRecordStore boot_event_store;
BootEventRecordStore::BootEventRecord record;
+
time_t uptime = bootstat::ParseUptime();
+ time_t current_time_utc = time(nullptr);
+
+ if (boot_event_store.GetBootEvent("last_boot_time_utc", &record)) {
+ time_t last_boot_time_utc = record.second;
+ time_t time_since_last_boot = difftime(current_time_utc,
+ last_boot_time_utc);
+ boot_event_store.AddBootEventWithValue("time_since_last_boot",
+ time_since_last_boot);
+ }
+
+ boot_event_store.AddBootEventWithValue("last_boot_time_utc", current_time_utc);
// The boot_complete metric has two variants: boot_complete and
// ota_boot_complete. The latter signifies that the device is booting after
@@ -274,6 +327,7 @@
LOG(INFO) << "Service started: " << cmd_line;
int option_index = 0;
+ static const char value_str[] = "value";
static const char boot_complete_str[] = "record_boot_complete";
static const char boot_reason_str[] = "record_boot_reason";
static const char factory_reset_str[] = "record_time_since_factory_reset";
@@ -282,19 +336,26 @@
{ "log", no_argument, NULL, 'l' },
{ "print", no_argument, NULL, 'p' },
{ "record", required_argument, NULL, 'r' },
+ { value_str, required_argument, NULL, 0 },
{ boot_complete_str, no_argument, NULL, 0 },
{ boot_reason_str, no_argument, NULL, 0 },
{ factory_reset_str, no_argument, NULL, 0 },
{ NULL, 0, NULL, 0 }
};
+ std::string boot_event;
+ std::string value;
int opt = 0;
while ((opt = getopt_long(argc, argv, "hlpr:", long_options, &option_index)) != -1) {
switch (opt) {
// This case handles long options which have no single-character mapping.
case 0: {
const std::string option_name = long_options[option_index].name;
- if (option_name == boot_complete_str) {
+ if (option_name == value_str) {
+ // |optarg| is an external variable set by getopt representing
+ // the option argument.
+ value = optarg;
+ } else if (option_name == boot_complete_str) {
RecordBootComplete();
} else if (option_name == boot_reason_str) {
RecordBootReason();
@@ -324,10 +385,7 @@
case 'r': {
// |optarg| is an external variable set by getopt representing
// the option argument.
- const char* event = optarg;
-
- BootEventRecordStore boot_event_store;
- boot_event_store.AddBootEvent(event);
+ boot_event = optarg;
break;
}
@@ -343,5 +401,9 @@
}
}
+ if (!boot_event.empty()) {
+ RecordBootEventFromCommandLine(boot_event, value);
+ }
+
return 0;
}
diff --git a/crash_reporter/Android.mk b/crash_reporter/Android.mk
index ce9dc73..4feb72a 100644
--- a/crash_reporter/Android.mk
+++ b/crash_reporter/Android.mk
@@ -135,9 +135,6 @@
include $(CLEAR_VARS)
LOCAL_MODULE := crash_reporter_tests
LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
-ifdef BRILLO
-LOCAL_MODULE_TAGS := eng
-endif
LOCAL_SHARED_LIBRARIES := libchrome \
libbrillo \
libcutils \
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index b3fdcb4..6e81c51 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -36,6 +36,7 @@
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <brillo/key_value_store.h>
+#include <brillo/osrelease_reader.h>
#include <brillo/process.h>
namespace {
@@ -52,6 +53,11 @@
const char kUploadVarPrefix[] = "upload_var_";
const char kUploadFilePrefix[] = "upload_file_";
+// Product information keys in the /etc/os-release.d folder.
+static const char kBdkVersionKey[] = "bdk_version";
+static const char kProductIDKey[] = "product_id";
+static const char kProductVersionKey[] = "product_version";
+
// Normally this path is not used. Unfortunately, there are a few edge cases
// where we need this. Any process that runs as kDefaultUserName that crashes
// is consider a "user crash". That includes the initial Chrome browser that
@@ -183,7 +189,7 @@
return true;
}
-bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
+bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid __unused,
FilePath *crash_directory,
bool *out_of_capacity) {
if (out_of_capacity) *out_of_capacity = false;
@@ -311,7 +317,7 @@
continue;
std::string filename(ent->d_name);
- size_t last_dot = filename.rfind(".");
+ size_t last_dot = filename.rfind('.');
std::string basename;
// If there is a valid looking extension, use the base part of the
// name. If the only dot is the first byte (aka a dot file), treat
@@ -384,14 +390,49 @@
const std::string &payload_path) {
int64_t payload_size = -1;
base::GetFileSize(FilePath(payload_path), &payload_size);
+
+ brillo::OsReleaseReader reader;
+ if (!forced_osreleased_directory_.empty()) {
+ reader.LoadTestingOnly(forced_osreleased_directory_);
+ } else {
+ reader.Load();
+ }
+ std::string bdk_version = "undefined";
+ std::string product_id = "undefined";
+ std::string product_version = "undefined";
+
+ if (!reader.GetString(kBdkVersionKey, &bdk_version)) {
+ LOG(ERROR) << "Could not read " << kBdkVersionKey
+ << " from /etc/os-release.d/";
+ }
+
+ if (!reader.GetString(kProductIDKey, &product_id)) {
+ LOG(ERROR) << "Could not read " << kProductIDKey
+ << " from /etc/os-release.d/";
+ }
+
+ if (!reader.GetString(kProductVersionKey, &product_version)) {
+ LOG(ERROR) << "Could not read " << kProductVersionKey
+ << " from /etc/os-release.d/";
+ }
+
std::string meta_data = StringPrintf("%sexec_name=%s\n"
"payload=%s\n"
"payload_size=%" PRId64 "\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
"done=1\n",
extra_metadata_.c_str(),
exec_name.c_str(),
payload_path.c_str(),
- payload_size);
+ payload_size,
+ kBdkVersionKey,
+ bdk_version.c_str(),
+ kProductIDKey,
+ product_id.c_str(),
+ kProductVersionKey,
+ product_version.c_str());
// We must use WriteNewFile instead of base::WriteFile as we
// do not want to write with root access to a symlink that an attacker
// might have created.
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
index 24cbfb3..21b9198 100644
--- a/crash_reporter/crash_collector.h
+++ b/crash_reporter/crash_collector.h
@@ -84,6 +84,12 @@
forced_crash_directory_ = forced_directory;
}
+ // For testing, set the root directory to read etc/os-release.d properties
+ // from.
+ void ForceOsReleaseDDirectory(const base::FilePath &forced_directory) {
+ forced_osreleased_directory_ = forced_directory;
+ }
+
base::FilePath GetCrashDirectoryInfo(mode_t *mode,
uid_t *directory_owner,
gid_t *directory_group);
@@ -158,6 +164,7 @@
IsFeedbackAllowedFunction is_feedback_allowed_function_;
std::string extra_metadata_;
base::FilePath forced_crash_directory_;
+ base::FilePath forced_osreleased_directory_;
base::FilePath log_config_path_;
private:
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index 11c8c0d..a386cd1 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -74,10 +74,11 @@
TEST_F(CrashCollectorTest, WriteNewFile) {
FilePath test_file = test_dir_.path().Append("test_new");
const char kBuffer[] = "buffer";
- EXPECT_EQ(strlen(kBuffer),
- collector_.WriteNewFile(test_file,
- kBuffer,
- strlen(kBuffer)));
+ unsigned int numBytesWritten = collector_.WriteNewFile(
+ test_file,
+ kBuffer,
+ strlen(kBuffer));
+ EXPECT_EQ(strlen(kBuffer), numBytesWritten);
EXPECT_LT(collector_.WriteNewFile(test_file,
kBuffer,
strlen(kBuffer)), 0);
@@ -94,7 +95,7 @@
}
TEST_F(CrashCollectorTest, FormatDumpBasename) {
- struct tm tm = {0};
+ struct tm tm = {};
tm.tm_sec = 15;
tm.tm_min = 50;
tm.tm_hour = 13;
@@ -182,9 +183,26 @@
const char kMetaFileBasename[] = "generated.meta";
FilePath meta_file = test_dir_.path().Append(kMetaFileBasename);
FilePath payload_file = test_dir_.path().Append("payload-file");
+ FilePath osreleased_directory =
+ test_dir_.path().Append("etc").Append("os-release.d");
+ ASSERT_TRUE(base::CreateDirectory(osreleased_directory));
+ collector_.ForceOsReleaseDDirectory(test_dir_.path());
+
std::string contents;
const char kPayload[] = "foo";
ASSERT_TRUE(base::WriteFile(payload_file, kPayload, strlen(kPayload)));
+ const char kBdkVersion[] = "1";
+ ASSERT_TRUE(base::WriteFile(osreleased_directory.Append("bdk_version"),
+ kBdkVersion,
+ strlen(kBdkVersion)));
+ const char kProductId[] = "baz";
+ ASSERT_TRUE(base::WriteFile(osreleased_directory.Append("product_id"),
+ kProductId,
+ strlen(kProductId)));
+ const char kProductVersion[] = "1.2.3.4";
+ ASSERT_TRUE(base::WriteFile(osreleased_directory.Append("product_version"),
+ kProductVersion,
+ strlen(kProductVersion)));
collector_.AddCrashMetaData("foo", "bar");
collector_.WriteCrashMetaData(meta_file, "kernel", payload_file.value());
EXPECT_TRUE(base::ReadFileToString(meta_file, &contents));
@@ -193,6 +211,9 @@
"exec_name=kernel\n"
"payload=%s\n"
"payload_size=3\n"
+ "bdk_version=1\n"
+ "product_id=baz\n"
+ "product_version=1.2.3.4\n"
"done=1\n",
test_dir_.path().Append("payload-file").value().c_str());
EXPECT_EQ(kExpectedMeta, contents);
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
index 015f624..0f6b930 100644
--- a/crash_reporter/kernel_collector_test.cc
+++ b/crash_reporter/kernel_collector_test.cc
@@ -49,7 +49,9 @@
protected:
void WriteStringToFile(const FilePath &file_path,
const char *data) {
- ASSERT_EQ(strlen(data), base::WriteFile(file_path, data, strlen(data)));
+ unsigned int numBytesWritten =
+ base::WriteFile(file_path, data, strlen(data));
+ ASSERT_EQ(strlen(data), numBytesWritten);
}
void SetUpSuccessfulCollect();
@@ -281,10 +283,10 @@
pos += strlen(kNamePrefix);
std::string filename = log.substr(pos, std::string::npos);
// Take the name up until \n
- size_t end_pos = filename.find_first_of("\n");
+ size_t end_pos = filename.find_first_of('\n');
ASSERT_NE(std::string::npos, end_pos);
filename = filename.substr(0, end_pos);
- ASSERT_EQ(0, filename.find(test_crash_directory().value()));
+ ASSERT_EQ(0U, filename.find(test_crash_directory().value()));
ASSERT_TRUE(base::PathExists(FilePath(filename)));
std::string contents;
ASSERT_TRUE(base::ReadFileToString(FilePath(filename), &contents));
diff --git a/crash_reporter/unclean_shutdown_collector_test.cc b/crash_reporter/unclean_shutdown_collector_test.cc
index 56d2704..36372ae 100644
--- a/crash_reporter/unclean_shutdown_collector_test.cc
+++ b/crash_reporter/unclean_shutdown_collector_test.cc
@@ -73,7 +73,9 @@
protected:
void WriteStringToFile(const FilePath &file_path,
const char *data) {
- ASSERT_EQ(strlen(data), base::WriteFile(file_path, data, strlen(data)));
+ unsigned int numBytesWritten =
+ base::WriteFile(file_path, data, strlen(data));
+ ASSERT_EQ(strlen(data), numBytesWritten);
}
UncleanShutdownCollectorMock collector_;
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index 98d7448..48b64e9 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -37,7 +37,6 @@
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
-#include <brillo/osrelease_reader.h>
#include <brillo/process.h>
#include <brillo/syslog_logging.h>
#include <cutils/properties.h>
@@ -59,11 +58,6 @@
const char *UserCollector::kUserId = "Uid:\t";
const char *UserCollector::kGroupId = "Gid:\t";
-// Product information keys in the /etc/os-release.d folder.
-static const char kBdkVersionKey[] = "bdk_version";
-static const char kProductIDKey[] = "product_id";
-static const char kProductVersionKey[] = "product_version";
-
using base::FilePath;
using base::StringPrintf;
@@ -505,29 +499,6 @@
if (GetLogContents(FilePath(log_config_path_), exec, log_path))
AddCrashMetaData("log", log_path.value());
- brillo::OsReleaseReader reader;
- reader.Load();
- std::string value = "undefined";
- if (!reader.GetString(kBdkVersionKey, &value)) {
- LOG(ERROR) << "Could not read " << kBdkVersionKey
- << " from /etc/os-release.d/";
- }
- AddCrashMetaData(kBdkVersionKey, value);
-
- value = "undefined";
- if (!reader.GetString(kProductIDKey, &value)) {
- LOG(ERROR) << "Could not read " << kProductIDKey
- << " from /etc/os-release.d/";
- }
- AddCrashMetaData(kProductIDKey, value);
-
- value = "undefined";
- if (!reader.GetString(kProductVersionKey, &value)) {
- LOG(ERROR) << "Could not read " << kProductVersionKey
- << " from /etc/os-release.d/";
- }
- AddCrashMetaData(kProductVersionKey, value);
-
ErrorType error_type =
ConvertCoreToMinidump(pid, container_dir, core_path, minidump_path);
if (error_type != kErrorNone) {
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index d9c9a5b..16a5cd5 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -101,15 +101,15 @@
&pid, &signal, &uid, &gid, &exec_name));
EXPECT_EQ(123456, pid);
EXPECT_EQ(11, signal);
- EXPECT_EQ(1000, uid);
- EXPECT_EQ(2000, gid);
+ EXPECT_EQ(1000U, uid);
+ EXPECT_EQ(2000U, gid);
EXPECT_EQ("foobar", exec_name);
EXPECT_TRUE(collector_.ParseCrashAttributes("4321:6:barfoo",
&pid, &signal, &uid, &gid, &exec_name));
EXPECT_EQ(4321, pid);
EXPECT_EQ(6, signal);
- EXPECT_EQ(-1, uid);
- EXPECT_EQ(-1, gid);
+ EXPECT_EQ(-1U, uid);
+ EXPECT_EQ(-1U, gid);
EXPECT_EQ("barfoo", exec_name);
EXPECT_FALSE(collector_.ParseCrashAttributes("123456:11",
@@ -186,10 +186,10 @@
test_dir_.path().Append("test/this_link").value().c_str();
this_link.assign(long_link.c_str(), len);
ASSERT_EQ(len, this_link.size());
- unlink(kLink);
ASSERT_EQ(0, symlink(this_link.c_str(), kLink));
ASSERT_TRUE(collector_.GetSymlinkTarget(FilePath(kLink), &result));
ASSERT_EQ(this_link, result.value());
+ unlink(kLink);
}
}
@@ -333,8 +333,8 @@
gid_t gid = 100;
uid_t uid = 100;
EXPECT_TRUE(collector_.GetUserInfoFromName("root", &uid, &gid));
- EXPECT_EQ(0, uid);
- EXPECT_EQ(0, gid);
+ EXPECT_EQ(0U, uid);
+ EXPECT_EQ(0U, gid);
}
TEST_F(UserCollectorTest, CopyOffProcFilesBadPath) {
@@ -387,7 +387,9 @@
// maps file is not empty
const char data[] = "test data";
- ASSERT_EQ(sizeof(data), base::WriteFile(maps_file, data, sizeof(data)));
+ unsigned int numBytesWritten =
+ base::WriteFile(maps_file, data, sizeof(data));
+ ASSERT_EQ(sizeof(data), numBytesWritten);
ASSERT_TRUE(base::PathExists(maps_file));
EXPECT_TRUE(collector_.ValidateProcFiles(container_dir));
}
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
new file mode 100644
index 0000000..8a63f3f
--- /dev/null
+++ b/debuggerd/Android.bp
@@ -0,0 +1,19 @@
+cc_library_static {
+ name: "libdebuggerd_client",
+ srcs: ["client/debuggerd_client.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Os",
+ ],
+
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+
+ // libdebuggerd_client gets async signal safe logging via libc_logging,
+ // which defines its interface in bionic private headers.
+ include_dirs: ["bionic/libc"],
+ static_libs: ["libc_logging"],
+}
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 6469db4..fdedb76 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -8,6 +8,10 @@
-Wunused \
-Werror \
+ifeq ($(TARGET_IS_64_BIT),true)
+common_cppflags += -DTARGET_IS_64_BIT
+endif
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -26,15 +30,12 @@
LOCAL_SRC_FILES_x86 := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(common_cppflags)
LOCAL_INIT_RC_32 := debuggerd.rc
LOCAL_INIT_RC_64 := debuggerd64.rc
-ifeq ($(TARGET_IS_64_BIT),true)
-LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
-endif
-
LOCAL_SHARED_LIBRARIES := \
libbacktrace \
libbase \
@@ -51,10 +52,10 @@
include $(BUILD_EXECUTABLE)
-
+crasher_cppflags := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := crasher.c
+LOCAL_SRC_FILES := crasher.cpp
LOCAL_SRC_FILES_arm := arm/crashglue.S
LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
LOCAL_SRC_FILES_mips := mips/crashglue.S
@@ -63,9 +64,8 @@
LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object -Wno-date-time
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SHARED_LIBRARIES := libcutils liblog libc
+LOCAL_CPPFLAGS := $(crasher_cppflags)
+LOCAL_SHARED_LIBRARIES := libcutils liblog
# The arm emulator has VFP but not VFPv3-D32.
ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
@@ -79,6 +79,34 @@
include $(BUILD_EXECUTABLE)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := crasher.cpp
+LOCAL_SRC_FILES_arm := arm/crashglue.S
+LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
+LOCAL_SRC_FILES_mips := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
+LOCAL_SRC_FILES_x86 := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
+LOCAL_MODULE := static_crasher
+LOCAL_MODULE_STEM_32 := static_crasher
+LOCAL_MODULE_STEM_64 := static_crasher64
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_LIBRARIES := libdebuggerd_client libcutils liblog
+
+include $(BUILD_EXECUTABLE)
+
debuggerd_test_src_files := \
utility.cpp \
test/dump_memory_test.cpp \
@@ -102,6 +130,9 @@
-Wno-missing-field-initializers \
-fno-rtti \
+# Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
+debuggerd_cpp_flags += -Wno-varargs
+
# Only build the host tests on linux.
ifeq ($(HOST_OS),linux)
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
new file mode 100644
index 0000000..44e92fe
--- /dev/null
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2008 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 "debuggerd/client.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "private/libc_logging.h"
+
+#if defined(TARGET_IS_64_BIT) && !defined(__LP64__)
+#define SOCKET_NAME "android:debuggerd32"
+#else
+#define SOCKET_NAME "android:debuggerd"
+#endif
+
+// see man(2) prctl, specifically the section about PR_GET_NAME
+#define MAX_TASK_NAME_LEN (16)
+
+static debuggerd_callbacks_t g_callbacks;
+
+static int socket_abstract_client(const char* name, int type) {
+ sockaddr_un addr;
+
+ // Test with length +1 for the *initial* '\0'.
+ size_t namelen = strlen(name);
+ if ((namelen + 1) > sizeof(addr.sun_path)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // This is used for abstract socket namespace, we need
+ // an initial '\0' at the start of the Unix socket path.
+ //
+ // Note: The path in this case is *not* supposed to be
+ // '\0'-terminated. ("man 7 unix" for the gory details.)
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_LOCAL;
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, namelen);
+
+ socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
+
+ int s = socket(AF_LOCAL, type, 0);
+ if (s == -1) {
+ return -1;
+ }
+
+ int rc = TEMP_FAILURE_RETRY(connect(s, reinterpret_cast<sockaddr*>(&addr), alen));
+ if (rc == -1) {
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+/*
+ * Writes a summary of the signal to the log file. We do this so that, if
+ * for some reason we're not able to contact debuggerd, there is still some
+ * indication of the failure in the log.
+ *
+ * We could be here as a result of native heap corruption, or while a
+ * mutex is being held, so we don't want to use any libc functions that
+ * could allocate memory or hold a lock.
+ */
+static void log_signal_summary(int signum, const siginfo_t* info) {
+ const char* signal_name = "???";
+ bool has_address = false;
+ switch (signum) {
+ case SIGABRT:
+ signal_name = "SIGABRT";
+ break;
+ case SIGBUS:
+ signal_name = "SIGBUS";
+ has_address = true;
+ break;
+ case SIGFPE:
+ signal_name = "SIGFPE";
+ has_address = true;
+ break;
+ case SIGILL:
+ signal_name = "SIGILL";
+ has_address = true;
+ break;
+ case SIGSEGV:
+ signal_name = "SIGSEGV";
+ has_address = true;
+ break;
+#if defined(SIGSTKFLT)
+ case SIGSTKFLT:
+ signal_name = "SIGSTKFLT";
+ break;
+#endif
+ case SIGTRAP:
+ signal_name = "SIGTRAP";
+ break;
+ }
+
+ char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
+ if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
+ strcpy(thread_name, "<name unknown>");
+ } else {
+ // short names are null terminated by prctl, but the man page
+ // implies that 16 byte names are not.
+ thread_name[MAX_TASK_NAME_LEN] = 0;
+ }
+
+ // "info" will be null if the siginfo_t information was not available.
+ // Many signals don't have an address or a code.
+ char code_desc[32]; // ", code -6"
+ char addr_desc[32]; // ", fault addr 0x1234"
+ addr_desc[0] = code_desc[0] = 0;
+ if (info != nullptr) {
+ // For a rethrown signal, this si_code will be right and the one debuggerd shows will
+ // always be SI_TKILL.
+ __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
+ if (has_address) {
+ __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
+ }
+ }
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)", signum,
+ signal_name, code_desc, addr_desc, gettid(), thread_name);
+}
+
+/*
+ * Returns true if the handler for signal "signum" has SA_SIGINFO set.
+ */
+static bool have_siginfo(int signum) {
+ struct sigaction old_action, new_action;
+
+ memset(&new_action, 0, sizeof(new_action));
+ new_action.sa_handler = SIG_DFL;
+ new_action.sa_flags = SA_RESTART;
+ sigemptyset(&new_action.sa_mask);
+
+ if (sigaction(signum, &new_action, &old_action) < 0) {
+ __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
+ strerror(errno));
+ return false;
+ }
+ bool result = (old_action.sa_flags & SA_SIGINFO) != 0;
+
+ if (sigaction(signum, &old_action, nullptr) == -1) {
+ __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
+ strerror(errno));
+ }
+ return result;
+}
+
+static void send_debuggerd_packet(siginfo_t* info) {
+ // Mutex to prevent multiple crashing threads from trying to talk
+ // to debuggerd at the same time.
+ static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
+ int ret = pthread_mutex_trylock(&crash_mutex);
+ if (ret != 0) {
+ if (ret == EBUSY) {
+ __libc_format_log(ANDROID_LOG_INFO, "libc",
+ "Another thread contacted debuggerd first; not contacting debuggerd.");
+ // This will never complete since the lock is never released.
+ pthread_mutex_lock(&crash_mutex);
+ } else {
+ __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_trylock failed: %s", strerror(ret));
+ }
+ return;
+ }
+
+ int s = socket_abstract_client(SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC);
+ if (s == -1) {
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
+ strerror(errno));
+ return;
+ }
+
+ // debuggerd knows our pid from the credentials on the
+ // local socket but we need to tell it the tid of the crashing thread.
+ // debuggerd will be paranoid and verify that we sent a tid
+ // that's actually in our process.
+ debugger_msg_t msg;
+ msg.action = DEBUGGER_ACTION_CRASH;
+ msg.tid = gettid();
+ msg.abort_msg_address = 0;
+
+ if (g_callbacks.get_abort_message) {
+ msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_callbacks.get_abort_message());
+ }
+
+ msg.original_si_code = (info != nullptr) ? info->si_code : 0;
+ ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
+ if (ret == sizeof(msg)) {
+ char debuggerd_ack;
+ ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
+ int saved_errno = errno;
+ if (g_callbacks.post_dump) {
+ g_callbacks.post_dump();
+ }
+ errno = saved_errno;
+ } else {
+ // read or write failed -- broken connection?
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
+ strerror(errno));
+ }
+
+ close(s);
+}
+
+/*
+ * Catches fatal signals so we can ask debuggerd to ptrace us before
+ * we crash.
+ */
+static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
+ // It's possible somebody cleared the SA_SIGINFO flag, which would mean
+ // our "info" arg holds an undefined value.
+ if (!have_siginfo(signal_number)) {
+ info = nullptr;
+ }
+
+ log_signal_summary(signal_number, info);
+
+ send_debuggerd_packet(info);
+
+ // We need to return from the signal handler so that debuggerd can dump the
+ // thread that crashed, but returning here does not guarantee that the signal
+ // will be thrown again, even for SIGSEGV and friends, since the signal could
+ // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to
+ // preserve the SA_SIGINFO contents.
+ signal(signal_number, SIG_DFL);
+
+ struct siginfo si;
+ if (!info) {
+ memset(&si, 0, sizeof(si));
+ si.si_code = SI_USER;
+ si.si_pid = getpid();
+ si.si_uid = getuid();
+ info = &si;
+ } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
+ // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
+ // that contain commit 66dd34a (3.9+). The manpage claims to only allow
+ // negative si_code values that are not SI_TKILL, but 66dd34a changed the
+ // check to allow all si_code values in calls coming from inside the house.
+ }
+
+ int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
+ if (rc != 0) {
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to resend signal during crash: %s",
+ strerror(errno));
+ _exit(0);
+ }
+}
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks) {
+ if (callbacks) {
+ g_callbacks = *callbacks;
+ }
+
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = debuggerd_signal_handler;
+ action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+ // Use the alternate signal stack if available so we can catch stack overflows.
+ action.sa_flags |= SA_ONSTACK;
+
+ sigaction(SIGABRT, &action, nullptr);
+ sigaction(SIGBUS, &action, nullptr);
+ sigaction(SIGFPE, &action, nullptr);
+ sigaction(SIGILL, &action, nullptr);
+ sigaction(SIGSEGV, &action, nullptr);
+#if defined(SIGSTKFLT)
+ sigaction(SIGSTKFLT, &action, nullptr);
+#endif
+ sigaction(SIGTRAP, &action, nullptr);
+}
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.cpp
similarity index 84%
rename from debuggerd/crasher.c
rename to debuggerd/crasher.cpp
index 75f070b..a37df33 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.cpp
@@ -16,14 +16,19 @@
#include <cutils/sockets.h>
#include <log/log.h>
+#if defined(STATIC_CRASHER)
+#include "debuggerd/client.h"
+#endif
+
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
extern const char* __progname;
-void crash1(void);
-void crashnostack(void);
+extern "C" void crash1(void);
+extern "C" void crashnostack(void);
+
static int do_action(const char* arg);
static void maybe_abort() {
@@ -42,7 +47,7 @@
// Assign local array address to global variable to force stack guards.
// Use another noinline function to corrupt the stack.
__attribute__ ((noinline)) static int smash_stack(volatile int* plen) {
- printf("crasher: deliberately corrupting stack...\n");
+ printf("%s: deliberately corrupting stack...\n", __progname);
char buf[128];
smash_stack_dummy_buf = buf;
@@ -134,7 +139,7 @@
static int do_action(const char* arg)
{
- fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
+ fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
if (!strncmp(arg, "thread-", strlen("thread-"))) {
return do_action_on_thread(arg + strlen("thread-"));
@@ -159,6 +164,10 @@
__assert("some_file.c", 123, "false");
} else if (!strcmp(arg, "assert2")) {
__assert2("some_file.c", 123, "some_function", "false");
+ } else if (!strcmp(arg, "fortify")) {
+ char buf[10];
+ __read_chk(-1, buf, 32, 10);
+ while (true) pause();
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
LOG_ALWAYS_FATAL("hello %s", "world");
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
@@ -172,7 +181,7 @@
} else if (!strcmp(arg, "heap-usage")) {
abuse_heap();
} else if (!strcmp(arg, "SIGSEGV-unmapped")) {
- char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ char* map = reinterpret_cast<char*>(mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0));
munmap(map, sizeof(int));
map[0] = '8';
}
@@ -189,6 +198,7 @@
fprintf(stderr, " abort call abort()\n");
fprintf(stderr, " assert call assert() without a function\n");
fprintf(stderr, " assert2 call assert() with a function\n");
+ fprintf(stderr, " fortify fail a _FORTIFY_SOURCE check\n");
fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n");
fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n");
fprintf(stderr, " SIGFPE cause a SIGFPE\n");
@@ -203,9 +213,26 @@
int main(int argc, char **argv)
{
- fprintf(stderr,"crasher: built at " __TIME__ "!@\n");
+ fprintf(stderr, "%s: built at " __TIME__ "!@\n", __progname);
- if(argc > 1) {
+#if defined(STATIC_CRASHER)
+ debuggerd_callbacks_t callbacks = {
+ .get_abort_message = []() {
+ static struct {
+ size_t size;
+ char msg[32];
+ } msg;
+
+ msg.size = strlen("dummy abort message");
+ memcpy(msg.msg, "dummy abort message", strlen("dummy abort message"));
+ return reinterpret_cast<abort_msg_t*>(&msg);
+ },
+ .post_dump = nullptr
+ };
+ debuggerd_init(&callbacks);
+#endif
+
+ if (argc > 1) {
return do_action(argv[1]);
} else {
crash1();
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 7b57c20..c352aeb 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -46,7 +46,6 @@
#include <cutils/debugger.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
-#include <nativehelper/ScopedFd.h>
#include <linux/input.h>
@@ -592,7 +591,7 @@
// won't necessarily have stopped by the time ptrace() returns. (We
// currently assume it does.) We write to the file descriptor to
// ensure that it can run as soon as we call PTRACE_CONT below.
- // See details in bionic/libc/linker/debugger.c, in function
+ // See details in client/debuggerd_client.cpp, in function
// debugger_signal_handler().
// Attach to the target process.
@@ -801,7 +800,7 @@
static void handle_request(int fd) {
ALOGV("handle_request(%d)\n", fd);
- ScopedFd closer(fd);
+ android::base::unique_fd closer(fd);
debugger_request_t request;
memset(&request, 0, sizeof(request));
int status = read_request(fd, &request);
diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp
index 9959f2e..3d99cab 100644
--- a/debuggerd/elf_utils.cpp
+++ b/debuggerd/elf_utils.cpp
@@ -29,7 +29,7 @@
#include "elf_utils.h"
-#define NOTE_ALIGN(size) ((size + 3) & ~3)
+#define NOTE_ALIGN(size) (((size) + 3) & ~3)
template <typename HdrType, typename PhdrType, typename NhdrType>
static bool get_build_id(
diff --git a/debuggerd/getevent.cpp b/debuggerd/getevent.cpp
index 751c4fb..e5acd17 100644
--- a/debuggerd/getevent.cpp
+++ b/debuggerd/getevent.cpp
@@ -26,6 +26,7 @@
#include <sys/poll.h>
#include <linux/input.h>
#include <errno.h>
+#include <memory>
#include <cutils/log.h>
static struct pollfd* ufds;
@@ -143,22 +144,20 @@
static int scan_dir(const char* dirname) {
char devname[PATH_MAX];
char* filename;
- DIR* dir;
struct dirent* de;
- dir = opendir(dirname);
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(dirname), closedir);
if (dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
- while ((de = readdir(dir))) {
+ while ((de = readdir(dir.get()))) {
if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
(de->d_name[1] == '.' && de->d_name[2] == '\0'))
continue;
strcpy(filename, de->d_name);
open_device(devname);
}
- closedir(dir);
return 0;
}
diff --git a/debuggerd/include/debuggerd/client.h b/debuggerd/include/debuggerd/client.h
new file mode 100644
index 0000000..41b7b3a
--- /dev/null
+++ b/debuggerd/include/debuggerd/client.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+// On 32-bit devices, DEBUGGER_SOCKET_NAME is a 32-bit debuggerd.
+// On 64-bit devices, DEBUGGER_SOCKET_NAME is a 64-bit debuggerd.
+#define DEBUGGER_SOCKET_NAME "android:debuggerd"
+
+// Used only on 64-bit devices for debuggerd32.
+#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
+
+__BEGIN_DECLS
+
+typedef enum {
+ // dump a crash
+ DEBUGGER_ACTION_CRASH,
+ // dump a tombstone file
+ DEBUGGER_ACTION_DUMP_TOMBSTONE,
+ // dump a backtrace only back to the socket
+ DEBUGGER_ACTION_DUMP_BACKTRACE,
+} debugger_action_t;
+
+// Make sure that all values have a fixed size so that this structure
+// is the same for 32 bit and 64 bit processes.
+typedef struct __attribute__((packed)) {
+ int32_t action;
+ pid_t tid;
+ uint64_t abort_msg_address;
+ int32_t original_si_code;
+} debugger_msg_t;
+
+// These callbacks are called in a signal handler, and thus must be async signal safe.
+// If null, the callbacks will not be called.
+typedef struct {
+ struct abort_msg_t* (*get_abort_message)();
+ void (*post_dump)();
+} debuggerd_callbacks_t;
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks);
+
+__END_DECLS
diff --git a/debuggerd/test/BacktraceMock.h b/debuggerd/test/BacktraceMock.h
index f75534e..6104f7e 100644
--- a/debuggerd/test/BacktraceMock.h
+++ b/debuggerd/test/BacktraceMock.h
@@ -41,7 +41,7 @@
class BacktraceMock : public Backtrace {
public:
- BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
+ explicit BacktraceMock(BacktraceMapMock* map) : Backtrace(0, 0, map) {
if (map_ == nullptr) {
abort();
}
diff --git a/debuggerd/test/host_signal_fixup.h b/debuggerd/test/host_signal_fixup.h
index c7796ef..762bae5 100644
--- a/debuggerd/test/host_signal_fixup.h
+++ b/debuggerd/test/host_signal_fixup.h
@@ -57,7 +57,7 @@
#endif
#if !defined(SI_DETHREAD)
-#define SI_DETHREAD -7
+#define SI_DETHREAD (-7)
#endif
#endif
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index fa983fa..dfdf29c 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -368,6 +368,7 @@
ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
}
+ ScopedBacktraceMapIteratorLock lock(map);
_LOG(log, logtype::MAPS, "\n");
if (!print_fault_address_marker) {
_LOG(log, logtype::MAPS, "memory map:\n");
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 47567c0..728dcb8 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -38,8 +38,6 @@
#include <sys/types.h>
#include <unistd.h>
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
#define OP_DOWNLOAD 1
#define OP_COMMAND 2
#define OP_QUERY 3
@@ -351,21 +349,21 @@
}
if (a->op == OP_DOWNLOAD) {
status = fb_download_data(transport, a->data, a->size);
- status = a->func(a, status, status ? fb_get_error() : "");
+ status = a->func(a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_COMMAND) {
status = fb_command(transport, a->cmd);
- status = a->func(a, status, status ? fb_get_error() : "");
+ status = a->func(a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_QUERY) {
status = fb_command_response(transport, a->cmd, resp);
- status = a->func(a, status, status ? fb_get_error() : resp);
+ status = a->func(a, status, status ? fb_get_error().c_str() : resp);
if (status) break;
} else if (a->op == OP_NOTICE) {
fprintf(stderr,"%s\n",(char*)a->data);
} else if (a->op == OP_DOWNLOAD_SPARSE) {
status = fb_download_data_sparse(transport, reinterpret_cast<sparse_file*>(a->data));
- status = a->func(a, status, status ? fb_get_error() : "");
+ status = a->func(a, status, status ? fb_get_error().c_str() : "");
if (status) break;
} else if (a->op == OP_WAIT_FOR_DISCONNECT) {
transport->WaitForDisconnect();
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index c1c3174..314ed42 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -47,6 +47,7 @@
#include <utility>
#include <vector>
+#include <android-base/macros.h>
#include <android-base/parseint.h>
#include <android-base/parsenetaddress.h>
#include <android-base/stringprintf.h>
@@ -67,8 +68,6 @@
#define O_BINARY 0
#endif
-#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
-
char cur_product[FB_RESPONSE_SZ + 1];
static const char* serial = nullptr;
@@ -117,11 +116,11 @@
static std::string find_item_given_name(const char* img_name, const char* product) {
char *dir;
- char path[PATH_MAX + 128];
if(product) {
- get_my_path(path);
- return android::base::StringPrintf("../../../target/product/%s/%s", product, img_name);
+ std::string path = get_my_path();
+ return android::base::StringPrintf("%s/../../../target/product/%s/%s",
+ path.c_str(), product, img_name);
}
dir = getenv("ANDROID_PRODUCT_OUT");
@@ -187,8 +186,8 @@
return 0;
}
-static void* load_file(const char* fn, int64_t* sz) {
- int fd = open(fn, O_RDONLY | O_BINARY);
+static void* load_file(const std::string& path, int64_t* sz) {
+ int fd = open(path.c_str(), O_RDONLY | O_BINARY);
if (fd == -1) return nullptr;
return load_fd(fd, sz);
}
@@ -797,10 +796,10 @@
return partition_type == "ext4";
}
-static int load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
+static bool load_buf_fd(Transport* transport, int fd, struct fastboot_buffer* buf) {
int64_t sz = get_file_size(fd);
if (sz == -1) {
- return -1;
+ return false;
}
lseek64(fd, 0, SEEK_SET);
@@ -808,7 +807,7 @@
if (limit) {
sparse_file** s = load_sparse_files(fd, limit);
if (s == nullptr) {
- return -1;
+ return false;
}
buf->type = FB_BUFFER_SPARSE;
buf->data = s;
@@ -820,18 +819,14 @@
buf->sz = sz;
}
- return 0;
+ return true;
}
-static int load_buf(Transport* transport, const char *fname, struct fastboot_buffer *buf)
-{
- int fd;
-
- fd = open(fname, O_RDONLY | O_BINARY);
- if (fd < 0) {
- return -1;
+static bool load_buf(Transport* transport, const char* fname, struct fastboot_buffer* buf) {
+ int fd = open(fname, O_RDONLY | O_BINARY);
+ if (fd == -1) {
+ return false;
}
-
return load_buf_fd(transport, fd, buf);
}
@@ -974,7 +969,7 @@
}
static void do_for_partition(Transport* transport, const std::string& part, const std::string& slot,
- std::function<void(const std::string&)> func, bool force_slot) {
+ const std::function<void(const std::string&)>& func, bool force_slot) {
std::string has_slot;
std::string current_slot;
@@ -1007,7 +1002,7 @@
* partition does not support slots.
*/
static void do_for_partitions(Transport* transport, const std::string& part, const std::string& slot,
- std::function<void(const std::string&)> func, bool force_slot) {
+ const std::function<void(const std::string&)>& func, bool force_slot) {
std::string has_slot;
if (slot == "all") {
@@ -1029,8 +1024,8 @@
static void do_flash(Transport* transport, const char* pname, const char* fname) {
struct fastboot_buffer buf;
- if (load_buf(transport, fname, &buf)) {
- die("cannot load '%s'", fname);
+ if (!load_buf(transport, fname, &buf)) {
+ die("cannot load '%s': %s", fname, strerror(errno));
}
flash_buf(pname, &buf);
}
@@ -1099,7 +1094,7 @@
skip_secondary = true;
}
}
- for (size_t i = 0; i < ARRAY_SIZE(images); ++i) {
+ for (size_t i = 0; i < arraysize(images); ++i) {
const char* slot = slot_override.c_str();
if (images[i].is_secondary) {
if (!skip_secondary) {
@@ -1118,8 +1113,9 @@
exit(1); // unzip_to_file already explained why.
}
fastboot_buffer buf;
- int rc = load_buf_fd(transport, fd, &buf);
- if (rc) die("cannot load %s from flash", images[i].img_name);
+ if (!load_buf_fd(transport, fd, &buf)) {
+ die("cannot load %s from flash: %s", images[i].img_name, strerror(errno));
+ }
auto update = [&](const std::string &partition) {
do_update_signature(zip, images[i].sig_name);
@@ -1143,15 +1139,19 @@
}
}
-static void do_send_signature(const std::string& fn) {
- std::size_t extension_loc = fn.find(".img");
- if (extension_loc == std::string::npos) return;
+static void do_send_signature(const char* filename) {
+ if (android::base::EndsWith(filename, ".img") == false) {
+ return;
+ }
- std::string fs_sig = fn.substr(0, extension_loc) + ".sig";
+ std::string sig_path = filename;
+ sig_path.erase(sig_path.size() - 4);
+ sig_path += ".sig";
int64_t sz;
- void* data = load_file(fs_sig.c_str(), &sz);
+ void* data = load_file(sig_path, &sz);
if (data == nullptr) return;
+
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
}
@@ -1163,7 +1163,7 @@
fb_queue_query_save("product", cur_product, sizeof(cur_product));
fname = find_item("info", product);
- if (fname == "") die("cannot find android-info.txt");
+ if (fname.empty()) die("cannot find android-info.txt");
int64_t sz;
void* data = load_file(fname.c_str(), &sz);
@@ -1186,7 +1186,7 @@
}
}
- for (size_t i = 0; i < ARRAY_SIZE(images); i++) {
+ for (size_t i = 0; i < arraysize(images); i++) {
const char* slot = NULL;
if (images[i].is_secondary) {
if (!skip_secondary) slot = secondary.c_str();
@@ -1196,13 +1196,13 @@
if (!slot) continue;
fname = find_item_given_name(images[i].img_name, product);
fastboot_buffer buf;
- if (load_buf(transport, fname.c_str(), &buf)) {
+ if (!load_buf(transport, fname.c_str(), &buf)) {
if (images[i].is_optional) continue;
die("could not load %s\n", images[i].img_name);
}
auto flashall = [&](const std::string &partition) {
- do_send_signature(fname);
+ do_send_signature(fname.c_str());
if (erase_first && needs_erase(transport, partition.c_str())) {
fb_queue_erase(partition.c_str());
}
@@ -1372,7 +1372,7 @@
return;
}
- if (load_buf_fd(transport, fd, &buf)) {
+ if (!load_buf_fd(transport, fd, &buf)) {
fprintf(stderr, "Cannot read image: %s\n", strerror(errno));
close(fd);
return;
@@ -1385,7 +1385,7 @@
fprintf(stderr, "Erase successful, but not automatically formatting.\n");
if (errMsg) fprintf(stderr, "%s", errMsg);
}
- fprintf(stderr,"FAILED (%s)\n", fb_get_error());
+ fprintf(stderr, "FAILED (%s)\n", fb_get_error().c_str());
}
int main(int argc, char **argv)
@@ -1670,7 +1670,7 @@
fb_queue_download("boot.img", data, sz);
fb_queue_command("boot", "booting");
} else if(!strcmp(*argv, "flash")) {
- char *pname = argv[1];
+ char* pname = argv[1];
std::string fname;
require(2);
if (argc > 2) {
@@ -1680,7 +1680,7 @@
fname = find_item(pname, product);
skip(2);
}
- if (fname == "") die("cannot determine image filename for '%s'", pname);
+ if (fname.empty()) die("cannot determine image filename for '%s'", pname);
auto flash = [&](const std::string &partition) {
if (erase_first && needs_erase(transport, partition.c_str())) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 1932bab..c2ea551 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -43,7 +43,7 @@
int fb_command_response(Transport* transport, const char* cmd, char* response);
int fb_download_data(Transport* transport, const void* data, uint32_t size);
int fb_download_data_sparse(Transport* transport, struct sparse_file* s);
-char *fb_get_error(void);
+const std::string fb_get_error();
#define FB_COMMAND_SZ 64
#define FB_RESPONSE_SZ 64
@@ -72,7 +72,7 @@
char *mkmsg(const char *fmt, ...);
__attribute__((__noreturn__)) void die(const char *fmt, ...);
-void get_my_path(char *path);
+std::string get_my_path();
/* Current product */
extern char cur_product[FB_RESPONSE_SZ + 1];
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index 4850b4a..bfa83b0 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -36,16 +36,16 @@
#include <algorithm>
+#include <android-base/stringprintf.h>
#include <sparse/sparse.h>
#include "fastboot.h"
#include "transport.h"
-static char ERROR[128];
+static std::string g_error;
-char *fb_get_error(void)
-{
- return ERROR;
+const std::string fb_get_error() {
+ return g_error;
}
static int check_response(Transport* transport, uint32_t size, char* response) {
@@ -54,14 +54,14 @@
while (true) {
int r = transport->Read(status, 64);
if (r < 0) {
- sprintf(ERROR, "status read failed (%s)", strerror(errno));
+ g_error = android::base::StringPrintf("status read failed (%s)", strerror(errno));
transport->Close();
return -1;
}
status[r] = 0;
if (r < 4) {
- sprintf(ERROR, "status malformed (%d bytes)", r);
+ g_error = android::base::StringPrintf("status malformed (%d bytes)", r);
transport->Close();
return -1;
}
@@ -80,9 +80,9 @@
if (!memcmp(status, "FAIL", 4)) {
if (r > 4) {
- sprintf(ERROR, "remote: %s", status + 4);
+ g_error = android::base::StringPrintf("remote: %s", status + 4);
} else {
- strcpy(ERROR, "remote failure");
+ g_error = "remote failure";
}
return -1;
}
@@ -90,14 +90,14 @@
if (!memcmp(status, "DATA", 4) && size > 0){
uint32_t dsize = strtol(status + 4, 0, 16);
if (dsize > size) {
- strcpy(ERROR, "data size too large");
+ g_error = android::base::StringPrintf("data size too large (%d)", dsize);
transport->Close();
return -1;
}
return dsize;
}
- strcpy(ERROR,"unknown status code");
+ g_error = "unknown status code";
transport->Close();
break;
}
@@ -108,7 +108,7 @@
static int _command_start(Transport* transport, const char* cmd, uint32_t size, char* response) {
size_t cmdsize = strlen(cmd);
if (cmdsize > 64) {
- sprintf(ERROR, "command too large");
+ g_error = android::base::StringPrintf("command too large (%zu)", cmdsize);
return -1;
}
@@ -117,7 +117,7 @@
}
if (transport->Write(cmd, cmdsize) != static_cast<int>(cmdsize)) {
- sprintf(ERROR, "command write failed (%s)", strerror(errno));
+ g_error = android::base::StringPrintf("command write failed (%s)", strerror(errno));
transport->Close();
return -1;
}
@@ -128,12 +128,12 @@
static int _command_data(Transport* transport, const void* data, uint32_t size) {
int r = transport->Write(data, size);
if (r < 0) {
- sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
+ g_error = android::base::StringPrintf("data transfer failure (%s)", strerror(errno));
transport->Close();
return -1;
}
if (r != ((int) size)) {
- sprintf(ERROR, "data transfer failure (short transfer)");
+ g_error = "data transfer failure (short transfer)";
transport->Close();
return -1;
}
@@ -182,7 +182,7 @@
int fb_download_data(Transport* transport, const void* data, uint32_t size) {
char cmd[64];
- sprintf(cmd, "download:%08x", size);
+ snprintf(cmd, sizeof(cmd), "download:%08x", size);
return _command_send(transport, cmd, data, size, 0) < 0 ? -1 : 0;
}
@@ -216,7 +216,7 @@
if (len > TRANSPORT_BUF_SIZE) {
if (transport_buf_len > 0) {
- sprintf(ERROR, "internal error: transport_buf not empty\n");
+ g_error = "internal error: transport_buf not empty";
return -1;
}
to_write = round_down(len, TRANSPORT_BUF_SIZE);
@@ -230,7 +230,7 @@
if (len > 0) {
if (len > TRANSPORT_BUF_SIZE) {
- sprintf(ERROR, "internal error: too much left for transport_buf\n");
+ g_error = "internal error: too much left for transport_buf";
return -1;
}
memcpy(transport_buf, ptr, len);
@@ -257,7 +257,7 @@
}
char cmd[64];
- sprintf(cmd, "download:%08x", size);
+ snprintf(cmd, sizeof(cmd), "download:%08x", size);
int r = _command_start(transport, cmd, size, 0);
if (r < 0) {
return -1;
diff --git a/fastboot/socket.cpp b/fastboot/socket.cpp
index 14ecd93..e56ffcf 100644
--- a/fastboot/socket.cpp
+++ b/fastboot/socket.cpp
@@ -167,7 +167,7 @@
// Implements the Socket interface for TCP.
class TcpSocket : public Socket {
public:
- TcpSocket(cutils_socket_t sock) : Socket(sock) {}
+ explicit TcpSocket(cutils_socket_t sock) : Socket(sock) {}
bool Send(const void* data, size_t length) override;
bool Send(std::vector<cutils_socket_buffer_t> buffers) override;
diff --git a/fastboot/socket.h b/fastboot/socket.h
index de543db..7eaa0ab 100644
--- a/fastboot/socket.h
+++ b/fastboot/socket.h
@@ -104,7 +104,7 @@
protected:
// Protected constructor to force factory function use.
- Socket(cutils_socket_t sock);
+ explicit Socket(cutils_socket_t sock);
// Blocks up to |timeout_ms| until a read is possible on |sock_|, and sets |receive_timed_out_|
// as appropriate to help distinguish between normal timeouts and fatal errors. Returns true if
diff --git a/fastboot/socket_test.cpp b/fastboot/socket_test.cpp
index affbdfd..373abc3 100644
--- a/fastboot/socket_test.cpp
+++ b/fastboot/socket_test.cpp
@@ -34,7 +34,7 @@
// Creates connected sockets |server| and |client|. Returns true on success.
bool MakeConnectedSockets(Socket::Protocol protocol, std::unique_ptr<Socket>* server,
std::unique_ptr<Socket>* client,
- const std::string hostname = "localhost") {
+ const std::string& hostname = "localhost") {
*server = Socket::NewServer(protocol, 0);
if (*server == nullptr) {
ADD_FAILURE() << "Failed to create server.";
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
index e42c4e1..dd6fbf8 100644
--- a/fastboot/tcp.cpp
+++ b/fastboot/tcp.cpp
@@ -66,7 +66,7 @@
int Close() override;
private:
- TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
+ explicit TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
// Connects to the device and performs the initial handshake. Returns false and fills |error|
// on failure.
diff --git a/fastboot/udp.cpp b/fastboot/udp.cpp
index b36bd60..53fb347 100644
--- a/fastboot/udp.cpp
+++ b/fastboot/udp.cpp
@@ -111,7 +111,7 @@
int Close() override;
private:
- UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
+ explicit UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
// Performs the UDP initialization procedure. Returns true on success.
bool InitializeProtocol(std::string* error);
diff --git a/fastboot/usb_linux.cpp b/fastboot/usb_linux.cpp
index 02ffcd9..6db1e27 100644
--- a/fastboot/usb_linux.cpp
+++ b/fastboot/usb_linux.cpp
@@ -89,7 +89,7 @@
class LinuxUsbTransport : public Transport {
public:
- LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
+ explicit LinuxUsbTransport(std::unique_ptr<usb_handle> handle) : handle_(std::move(handle)) {}
~LinuxUsbTransport() override = default;
ssize_t Read(void* data, size_t len) override;
@@ -145,7 +145,7 @@
int in, out;
unsigned i;
unsigned e;
-
+
if (check(ptr, len, USB_DT_DEVICE, USB_DT_DEVICE_SIZE))
return -1;
dev = (struct usb_device_descriptor *)ptr;
@@ -333,15 +333,14 @@
char desc[1024];
int n, in, out, ifc;
- DIR *busdir;
struct dirent *de;
int fd;
int writable;
- busdir = opendir(base);
+ std::unique_ptr<DIR, decltype(&closedir)> busdir(opendir(base), closedir);
if (busdir == 0) return 0;
- while ((de = readdir(busdir)) && (usb == nullptr)) {
+ while ((de = readdir(busdir.get())) && (usb == nullptr)) {
if (badname(de->d_name)) continue;
if (!convert_to_devfs_name(de->d_name, devname, sizeof(devname))) {
@@ -377,7 +376,6 @@
}
}
}
- closedir(busdir);
return usb;
}
diff --git a/fastboot/util_linux.cpp b/fastboot/util_linux.cpp
index b788199..2c6aedb 100644
--- a/fastboot/util_linux.cpp
+++ b/fastboot/util_linux.cpp
@@ -28,27 +28,16 @@
#include "fastboot.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
-void get_my_path(char *path)
-{
- char proc[64];
- char *x;
+#include <android-base/stringprintf.h>
- sprintf(proc, "/proc/%d/exe", getpid());
- int err = readlink(proc, path, PATH_MAX - 1);
-
- if(err <= 0) {
- path[0] = 0;
- } else {
- path[err] = 0;
- x = strrchr(path,'/');
- if(x) x[1] = 0;
- }
+std::string get_my_path() {
+ std::string proc = android::base::StringPrintf("/proc/%d/exe", getpid());
+ char path[PATH_MAX + 1];
+ int rc = readlink(proc.c_str(), path, sizeof(path) - 1);
+ if (rc == -1) return "";
+ path[rc] = '\0';
+ return path;
}
diff --git a/fastboot/util_osx.cpp b/fastboot/util_osx.cpp
index ae0b024..4bae7c4 100644
--- a/fastboot/util_osx.cpp
+++ b/fastboot/util_osx.cpp
@@ -31,19 +31,15 @@
#import <Carbon/Carbon.h>
#include <unistd.h>
-void get_my_path(char s[PATH_MAX])
-{
+std::string get_my_path() {
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
CFRelease(executableURL);
- CFStringGetFileSystemRepresentation(executablePathString, s, PATH_MAX-1);
+ char path[PATH_MAX + 1];
+ CFStringGetFileSystemRepresentation(executablePathString, path, sizeof(PATH_MAX)-1);
CFRelease(executablePathString);
- char *x;
- x = strrchr(s, '/');
- if(x) x[1] = 0;
+ return path;
}
-
-
diff --git a/fastboot/util_windows.cpp b/fastboot/util_windows.cpp
index ec52f39..3b22c55 100644
--- a/fastboot/util_windows.cpp
+++ b/fastboot/util_windows.cpp
@@ -38,14 +38,12 @@
#include <windows.h>
-void get_my_path(char exe[PATH_MAX])
-{
- char* r;
+std::string get_my_path() {
+ char path[PATH_MAX + 1];
- GetModuleFileName( NULL, exe, PATH_MAX-1 );
- exe[PATH_MAX-1] = 0;
- r = strrchr( exe, '\\' );
- if (r)
- *r = 0;
+ DWORD result = GetModuleFileName(NULL, path, sizeof(path) - 1);
+ if (result == 0 || result == sizeof(path) - 1) return "";
+ path[PATH_MAX - 1] = 0;
+
+ return path;
}
-
diff --git a/fingerprintd/IFingerprintDaemonCallback.cpp b/fingerprintd/IFingerprintDaemonCallback.cpp
index 19838c9..1d75aa7 100644
--- a/fingerprintd/IFingerprintDaemonCallback.cpp
+++ b/fingerprintd/IFingerprintDaemonCallback.cpp
@@ -27,7 +27,7 @@
class BpFingerprintDaemonCallback : public BpInterface<IFingerprintDaemonCallback>
{
public:
- BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
+ explicit BpFingerprintDaemonCallback(const sp<IBinder>& impl) :
BpInterface<IFingerprintDaemonCallback>(impl) {
}
virtual status_t onEnrollResult(int64_t devId, int32_t fpId, int32_t gpId, int32_t rem) {
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 28fff3f..7da3ca4 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -7,10 +7,11 @@
libfec \
libfec_rs \
libbase \
- libmincrypt \
+ libcrypto_utils_static \
libcrypto_static \
libext4_utils_static \
- libsquashfs_utils
+ libsquashfs_utils \
+ libselinux
include $(CLEAR_VARS)
LOCAL_CLANG := true
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 6de8817..ab52512 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -14,35 +14,32 @@
* limitations under the License.
*/
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
#include <sys/mount.h>
#include <sys/stat.h>
-#include <errno.h>
+#include <sys/swap.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <libgen.h>
#include <time.h>
-#include <sys/swap.h>
-#include <dirent.h>
-#include <ext4.h>
-#include <ext4_sb.h>
-#include <ext4_crypt_init_extensions.h>
+#include <unistd.h>
-#include <linux/loop.h>
-#include <private/android_filesystem_config.h>
+#include <ext4.h>
+#include <ext4_crypt_init_extensions.h>
+#include <ext4_sb.h>
+
#include <cutils/android_reboot.h>
#include <cutils/partition_utils.h>
#include <cutils/properties.h>
+#include <linux/loop.h>
#include <logwrap/logwrap.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
+#include <private/android_filesystem_config.h>
#include "ext4_utils.h"
#include "wipe.h"
@@ -577,6 +574,7 @@
/* mount(2) returned an error, handle the encryptable/formattable case */
bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
+ bool crypt_footer = false;
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) {
/* top_idx and attempted_idx point at the same partition, but sometimes
@@ -588,7 +586,7 @@
fstab->recs[top_idx].fs_type);
if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
- int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644);
+ int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY);
if (fd >= 0) {
INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc);
wipe_block_device(fd, get_file_size(fd));
@@ -597,8 +595,11 @@
ERROR("%s(): %s wouldn't open (%s)\n", __func__,
fstab->recs[top_idx].key_loc, strerror(errno));
}
+ } else if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
+ !strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
+ crypt_footer = true;
}
- if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) {
+ if (fs_mgr_do_format(&fstab->recs[top_idx], crypt_footer) == 0) {
/* Let's replay the mount actions. */
i = top_idx - 1;
continue;
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index f8df081..7ee5832 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -23,41 +23,62 @@
#include <errno.h>
#include <cutils/partition_utils.h>
#include <sys/mount.h>
+
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+
#include "ext4_utils.h"
#include "ext4.h"
#include "make_ext4fs.h"
#include "fs_mgr_priv.h"
+#include "cryptfs.h"
extern struct fs_info info; /* magic global from ext4_utils */
extern void reset_ext4fs_info();
-static int format_ext4(char *fs_blkdev, char *fs_mnt_point)
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
{
- unsigned int nr_sec;
+ uint64_t dev_sz;
int fd, rc = 0;
- if ((fd = open(fs_blkdev, O_WRONLY, 0644)) < 0) {
+ if ((fd = open(fs_blkdev, O_WRONLY)) < 0) {
ERROR("Cannot open block device. %s\n", strerror(errno));
return -1;
}
- if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) {
+ if ((ioctl(fd, BLKGETSIZE64, &dev_sz)) == -1) {
ERROR("Cannot get block device size. %s\n", strerror(errno));
close(fd);
return -1;
}
+ struct selabel_handle *sehandle = selinux_android_file_context_handle();
+ if (!sehandle) {
+ /* libselinux logs specific error */
+ ERROR("Cannot initialize android file_contexts");
+ close(fd);
+ return -1;
+ }
+
/* Format the partition using the calculated length */
reset_ext4fs_info();
- info.len = ((off64_t)nr_sec * 512);
+ info.len = (off64_t)dev_sz;
+ if (crypt_footer) {
+ info.len -= CRYPT_FOOTER_OFFSET;
+ }
/* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
- rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL);
+ rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 0, 0, NULL, NULL, NULL);
if (rc) {
ERROR("make_ext4fs returned %d.\n", rc);
}
close(fd);
+ if (sehandle) {
+ selabel_close(sehandle);
+ }
+
return rc;
}
@@ -101,7 +122,7 @@
return rc;
}
-int fs_mgr_do_format(struct fstab_rec *fstab)
+int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
{
int rc = -EINVAL;
@@ -110,7 +131,7 @@
if (!strncmp(fstab->fs_type, "f2fs", 4)) {
rc = format_f2fs(fstab->blk_device);
} else if (!strncmp(fstab->fs_type, "ext4", 4)) {
- rc = format_ext4(fstab->blk_device, fstab->mount_point);
+ rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
} else {
ERROR("File system type '%s' is not supported\n", fstab->fs_type);
}
diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c
index e5a00d5..b3f131e 100644
--- a/fs_mgr/fs_mgr_main.c
+++ b/fs_mgr/fs_mgr_main.c
@@ -85,7 +85,6 @@
char *fstab_file=NULL;
struct fstab *fstab=NULL;
- klog_init();
klog_set_level(6);
parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev);
@@ -111,4 +110,3 @@
/* Should not get here */
exit(1);
}
-
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h
index cd673f3..d9e17bb 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -16,8 +16,8 @@
#include <sys/cdefs.h>
-#define FS_MGR_SETUP_VERITY_DISABLED -2
-#define FS_MGR_SETUP_VERITY_FAIL -1
+#define FS_MGR_SETUP_VERITY_DISABLED (-2)
+#define FS_MGR_SETUP_VERITY_FAIL (-1)
#define FS_MGR_SETUP_VERITY_SUCCESS 0
__BEGIN_DECLS
diff --git a/fs_mgr/fs_mgr_slotselect.c b/fs_mgr/fs_mgr_slotselect.c
index ca07b18..0f59115 100644
--- a/fs_mgr/fs_mgr_slotselect.c
+++ b/fs_mgr/fs_mgr_slotselect.c
@@ -41,7 +41,7 @@
int n;
int misc_fd;
ssize_t num_read;
- struct bootloader_message msg;
+ struct bootloader_message_ab msg;
misc_fd = -1;
for (n = 0; n < fstab->num_entries; n++) {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 83f42a09..031b042 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -14,29 +14,30 @@
* limitations under the License.
*/
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
+#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <ctype.h>
#include <sys/mount.h>
#include <sys/stat.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <libgen.h>
#include <time.h>
+#include <unistd.h>
#include <android-base/file.h>
#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#include <private/android_filesystem_config.h>
#include "fec/io.h"
@@ -83,48 +84,42 @@
extern struct fs_info info;
-static RSAPublicKey *load_key(const char *path)
+static RSA *load_key(const char *path)
{
- RSAPublicKey* key = static_cast<RSAPublicKey*>(malloc(sizeof(RSAPublicKey)));
- if (!key) {
- ERROR("Can't malloc key\n");
- return NULL;
- }
+ uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
FILE* f = fopen(path, "r");
if (!f) {
ERROR("Can't open '%s'\n", path);
- free(key);
return NULL;
}
- if (!fread(key, sizeof(*key), 1, f)) {
+ if (!fread(key_data, sizeof(key_data), 1, f)) {
ERROR("Could not read key!\n");
fclose(f);
- free(key);
- return NULL;
- }
-
- if (key->len != RSANUMWORDS) {
- ERROR("Invalid key length %d\n", key->len);
- fclose(f);
- free(key);
return NULL;
}
fclose(f);
+
+ RSA* key = NULL;
+ if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
+ ERROR("Could not parse key!\n");
+ return NULL;
+ }
+
return key;
}
-static int verify_table(const uint8_t *signature, const char *table,
- uint32_t table_length)
+static int verify_table(const uint8_t *signature, size_t signature_size,
+ const char *table, uint32_t table_length)
{
- RSAPublicKey *key;
- uint8_t hash_buf[SHA256_DIGEST_SIZE];
+ RSA *key;
+ uint8_t hash_buf[SHA256_DIGEST_LENGTH];
int retval = -1;
// Hash the table
- SHA256_hash((uint8_t*)table, table_length, hash_buf);
+ SHA256((uint8_t*)table, table_length, hash_buf);
// Now get the public key from the keyfile
key = load_key(VERITY_TABLE_RSA_KEY);
@@ -134,11 +129,8 @@
}
// verify the result
- if (!RSA_verify(key,
- signature,
- RSANUMBYTES,
- (uint8_t*) hash_buf,
- SHA256_DIGEST_SIZE)) {
+ if (!RSA_verify(NID_sha256, hash_buf, sizeof(hash_buf), signature,
+ signature_size, key)) {
ERROR("Couldn't verify table\n");
goto out;
}
@@ -146,16 +138,16 @@
retval = 0;
out:
- free(key);
+ RSA_free(key);
return retval;
}
static int verify_verity_signature(const struct fec_verity_metadata& verity)
{
- if (verify_table(verity.signature, verity.table,
- verity.table_length) == 0 ||
- verify_table(verity.ecc_signature, verity.table,
- verity.table_length) == 0) {
+ if (verify_table(verity.signature, sizeof(verity.signature),
+ verity.table, verity.table_length) == 0 ||
+ verify_table(verity.ecc_signature, sizeof(verity.ecc_signature),
+ verity.table, verity.table_length) == 0) {
return 0;
}
@@ -622,8 +614,8 @@
off64_t offset = 0;
struct fec_handle *f = NULL;
struct fec_verity_metadata verity;
- uint8_t curr[SHA256_DIGEST_SIZE];
- uint8_t prev[SHA256_DIGEST_SIZE];
+ uint8_t curr[SHA256_DIGEST_LENGTH];
+ uint8_t prev[SHA256_DIGEST_LENGTH];
*match = 1;
@@ -641,7 +633,7 @@
goto out;
}
- SHA256_hash(verity.signature, RSANUMBYTES, curr);
+ SHA256(verity.signature, sizeof(verity.signature), curr);
if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
basename(fstab->mount_point)) >= (int)sizeof(tag)) {
@@ -649,7 +641,7 @@
goto out;
}
- if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
+ if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_LENGTH,
&offset) < 0) {
goto out;
}
@@ -668,7 +660,7 @@
goto out;
}
- *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);
+ *match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH);
if (!*match) {
/* update current signature hash */
@@ -877,7 +869,7 @@
std::string result, word;
auto tokens = android::base::Split(*table, " ");
- for (const auto token : tokens) {
+ for (const auto& token : tokens) {
if (android::base::StartsWith(token, "/dev/block/") &&
android::base::StartsWith(blk_device, token.c_str())) {
word = blk_device;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 46d8f97..6f2548d 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -18,6 +18,7 @@
#define __CORE_FS_MGR_H
#include <stdint.h>
+#include <stdbool.h>
#include <linux/dm-ioctl.h>
// Magic number at start of verity metadata
@@ -81,11 +82,11 @@
#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 2
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
-#define FS_MGR_MNTALL_FAIL -1
+#define FS_MGR_MNTALL_FAIL (-1)
int fs_mgr_mount_all(struct fstab *fstab);
-#define FS_MGR_DOMNT_FAILED -1
-#define FS_MGR_DOMNT_BUSY -2
+#define FS_MGR_DOMNT_FAILED (-1)
+#define FS_MGR_DOMNT_BUSY (-2)
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
char *tmp_mount_point);
@@ -112,7 +113,7 @@
int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
-int fs_mgr_do_format(struct fstab_rec *fstab);
+int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
#ifdef __cplusplus
}
diff --git a/gatekeeperd/IUserManager.cpp b/gatekeeperd/IUserManager.cpp
index 8645fc2..8167d19 100644
--- a/gatekeeperd/IUserManager.cpp
+++ b/gatekeeperd/IUserManager.cpp
@@ -27,7 +27,7 @@
class BpUserManager : public BpInterface<IUserManager>
{
public:
- BpUserManager(const sp<IBinder>& impl) :
+ explicit BpUserManager(const sp<IBinder>& impl) :
BpInterface<IUserManager>(impl) {
}
virtual int32_t getCredentialOwnerProfile(int32_t user_id) {
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index b4fdab0..7254cf2 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -76,7 +76,7 @@
void store_sid(uint32_t uid, uint64_t sid) {
char filename[21];
- sprintf(filename, "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", uid);
int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) {
ALOGE("could not open file: %s: %s", filename, strerror(errno));
@@ -102,7 +102,7 @@
void maybe_store_sid(uint32_t uid, uint64_t sid) {
char filename[21];
- sprintf(filename, "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", uid);
if (access(filename, F_OK) == -1) {
store_sid(uid, sid);
}
@@ -111,7 +111,7 @@
uint64_t read_sid(uint32_t uid) {
char filename[21];
uint64_t sid;
- sprintf(filename, "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", uid);
int fd = open(filename, O_RDONLY);
if (fd < 0) return 0;
read(fd, &sid, sizeof(sid));
@@ -121,7 +121,7 @@
void clear_sid(uint32_t uid) {
char filename[21];
- sprintf(filename, "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", uid);
if (remove(filename) < 0) {
ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno));
store_sid(uid, 0);
diff --git a/healthd/Android.mk b/healthd/Android.mk
index a4469fc..deebed5 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -8,6 +8,8 @@
LOCAL_CFLAGS := -Werror
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libbinder
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libbinder
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -15,17 +17,27 @@
LOCAL_MODULE := libbatterymonitor
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libutils
+LOCAL_STATIC_LIBRARIES := libutils libbase libbinder
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
+ifeq ($(strip $(BOARD_CHARGER_NO_UI)),true)
+LOCAL_CHARGER_NO_UI := true
+endif
+ifdef BRILLO
+LOCAL_CHARGER_NO_UI := true
+endif
+
LOCAL_SRC_FILES := \
healthd.cpp \
healthd_mode_android.cpp \
- healthd_mode_charger.cpp \
BatteryPropertiesRegistrar.cpp
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_SRC_FILES += healthd_mode_charger.cpp
+endif
+
LOCAL_MODULE := healthd
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
@@ -42,9 +54,19 @@
LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
endif
-LOCAL_C_INCLUDES := bootable/recovery
+ifeq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_CFLAGS += -DCHARGER_NO_UI
+endif
-LOCAL_STATIC_LIBRARIES := libbatterymonitor libbatteryservice libbinder libminui libpng libz libutils libcutils liblog libm libc
+LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := libbatterymonitor libbatteryservice libbinder libbase
+
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
+LOCAL_STATIC_LIBRARIES += libminui libpng libz
+endif
+
+LOCAL_STATIC_LIBRARIES += libutils libcutils liblog libm libc
ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
LOCAL_STATIC_LIBRARIES += libsuspend
@@ -59,6 +81,7 @@
include $(BUILD_EXECUTABLE)
+ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
define _add-charger-image
include $$(CLEAR_VARS)
LOCAL_MODULE := system_core_charger_$(notdir $(1))
@@ -84,3 +107,4 @@
_add-charger-image :=
_img_modules :=
+endif # LOCAL_CHARGER_NO_UI
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 54d45e6..f81e7d9 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -26,7 +26,10 @@
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
+#include <memory>
+#include <android-base/file.h>
+#include <android-base/strings.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <cutils/properties.h>
@@ -124,34 +127,15 @@
return ret;
}
-int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) {
- char *cp = NULL;
-
- if (path.isEmpty())
- return -1;
- int fd = open(path.string(), O_RDONLY, 0);
- if (fd == -1) {
- KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string());
- return -1;
+int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
+ if (android::base::ReadFileToString(String8::std_string(path), buf)) {
+ *buf = android::base::Trim(*buf);
}
-
- ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size));
- if (count > 0)
- cp = (char *)memrchr(buf, '\n', count);
-
- if (cp)
- *cp = '\0';
- else
- buf[0] = '\0';
-
- close(fd);
- return count;
+ return buf->length();
}
BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
- const int SIZE = 128;
- char buf[SIZE];
- int length = readFromFile(path, buf, SIZE);
+ std::string buf;
BatteryMonitor::PowerSupplyType ret;
struct sysfsStringEnumMap supplyTypeMap[] = {
{ "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
@@ -170,12 +154,12 @@
{ NULL, 0 },
};
- if (length <= 0)
+ if (readFromFile(path, &buf) <= 0)
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
- ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf, supplyTypeMap);
+ ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf.c_str(), supplyTypeMap);
if (ret < 0) {
- KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf);
+ KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
}
@@ -183,27 +167,23 @@
}
bool BatteryMonitor::getBooleanField(const String8& path) {
- const int SIZE = 16;
- char buf[SIZE];
-
+ std::string buf;
bool value = false;
- if (readFromFile(path, buf, SIZE) > 0) {
- if (buf[0] != '0') {
+
+ if (readFromFile(path, &buf) > 0)
+ if (buf[0] != '0')
value = true;
- }
- }
return value;
}
int BatteryMonitor::getIntField(const String8& path) {
- const int SIZE = 128;
- char buf[SIZE];
-
+ std::string buf;
int value = 0;
- if (readFromFile(path, buf, SIZE) > 0) {
- value = strtol(buf, NULL, 0);
- }
+
+ if (readFromFile(path, &buf) > 0)
+ value = std::stoi(buf.c_str(), NULL, 0);
+
return value;
}
@@ -247,18 +227,16 @@
props.batteryHealth = BATTERY_HEALTH_GOOD;
}
- const int SIZE = 128;
- char buf[SIZE];
- String8 btech;
+ std::string buf;
- if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
- props.batteryStatus = getBatteryStatus(buf);
+ if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
+ props.batteryStatus = getBatteryStatus(buf.c_str());
- if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
- props.batteryHealth = getBatteryHealth(buf);
+ if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
+ props.batteryHealth = getBatteryHealth(buf.c_str());
- if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
- props.batteryTechnology = String8(buf);
+ if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
+ props.batteryTechnology = String8(buf.c_str());
unsigned int i;
double MaxPower = 0;
@@ -267,47 +245,44 @@
String8 path;
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
-
- if (readFromFile(path, buf, SIZE) > 0) {
- if (buf[0] != '0') {
- path.clear();
- path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- switch(readPowerSupplyType(path)) {
- case ANDROID_POWER_SUPPLY_TYPE_AC:
- props.chargerAcOnline = true;
- break;
- case ANDROID_POWER_SUPPLY_TYPE_USB:
- props.chargerUsbOnline = true;
- break;
- case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
- props.chargerWirelessOnline = true;
- break;
- default:
- KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
- mChargerNames[i].string());
- }
- path.clear();
- path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- int ChargingCurrent =
+ if (getIntField(path)) {
+ path.clear();
+ path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
+ switch(readPowerSupplyType(path)) {
+ case ANDROID_POWER_SUPPLY_TYPE_AC:
+ props.chargerAcOnline = true;
+ break;
+ case ANDROID_POWER_SUPPLY_TYPE_USB:
+ props.chargerUsbOnline = true;
+ break;
+ case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+ props.chargerWirelessOnline = true;
+ break;
+ default:
+ KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
+ mChargerNames[i].string());
+ }
+ path.clear();
+ path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
+ int ChargingCurrent =
(access(path.string(), R_OK) == 0) ? getIntField(path) : 0;
- path.clear();
- path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
+ path.clear();
+ path.appendFormat("%s/%s/voltage_max", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
- int ChargingVoltage =
- (access(path.string(), R_OK) == 0) ? getIntField(path) :
- DEFAULT_VBUS_VOLTAGE;
+ int ChargingVoltage =
+ (access(path.string(), R_OK) == 0) ? getIntField(path) :
+ DEFAULT_VBUS_VOLTAGE;
- double power = ((double)ChargingCurrent / MILLION) *
- ((double)ChargingVoltage / MILLION);
- if (MaxPower < power) {
- props.maxChargingCurrent = ChargingCurrent;
- props.maxChargingVoltage = ChargingVoltage;
- MaxPower = power;
- }
+ double power = ((double)ChargingCurrent / MILLION) *
+ ((double)ChargingVoltage / MILLION);
+ if (MaxPower < power) {
+ props.maxChargingCurrent = ChargingCurrent;
+ props.maxChargingVoltage = ChargingVoltage;
+ MaxPower = power;
}
}
}
@@ -342,11 +317,10 @@
" cc=%d", props.batteryCycleCount);
}
} else {
- snprintf(dmesgline, sizeof(dmesgline),
+ len = snprintf(dmesgline, sizeof(dmesgline),
"battery none");
}
- len = strlen(dmesgline);
snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
props.chargerAcOnline ? "a" : "",
props.chargerUsbOnline ? "u" : "",
@@ -363,10 +337,9 @@
int BatteryMonitor::getChargeStatus() {
int result = BATTERY_STATUS_UNKNOWN;
if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
- char buf[128];
- if (readFromFile(mHealthdConfig->batteryStatusPath, buf, sizeof(buf)) > 0) {
- result = getBatteryStatus(buf);
- }
+ std::string buf;
+ if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
+ result = getBatteryStatus(buf.c_str());
}
return result;
}
@@ -488,13 +461,13 @@
char pval[PROPERTY_VALUE_MAX];
mHealthdConfig = hc;
- DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(POWER_SUPPLY_SYSFS_PATH), closedir);
if (dir == NULL) {
KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH);
} else {
struct dirent* entry;
- while ((entry = readdir(dir))) {
+ while ((entry = readdir(dir.get()))) {
const char* name = entry->d_name;
if (!strcmp(name, ".") || !strcmp(name, ".."))
@@ -632,7 +605,6 @@
break;
}
}
- closedir(dir);
}
// Typically the case for devices which do not have a battery and
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index 5d1fa52..d28ba41 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -35,7 +35,7 @@
defaultServiceManager()->addService(String16("batteryproperties"), service);
}
-void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
+void BatteryPropertiesRegistrar::notifyListeners(const struct BatteryProperties& props) {
Mutex::Autolock _l(mRegistrationLock);
for (size_t i = 0; i < mListeners.size(); i++) {
mListeners[i]->batteryPropertiesChanged(props);
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
index d17e4a3..095f3d3 100644
--- a/healthd/BatteryPropertiesRegistrar.h
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -31,7 +31,7 @@
public IBinder::DeathRecipient {
public:
void publish(const sp<BatteryPropertiesRegistrar>& service);
- void notifyListeners(struct BatteryProperties props);
+ void notifyListeners(const struct BatteryProperties& props);
private:
Mutex mRegistrationLock;
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index d9ac356..20a6bf6 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -109,10 +109,17 @@
};
static struct healthd_mode_ops charger_ops = {
+#ifdef CHARGER_NO_UI
+ .init = healthd_mode_nop_init,
+ .preparetowait = healthd_mode_nop_preparetowait,
+ .heartbeat = healthd_mode_nop_heartbeat,
+ .battery_update = healthd_mode_nop_battery_update,
+#else
.init = healthd_mode_charger_init,
.preparetowait = healthd_mode_charger_preparetowait,
.heartbeat = healthd_mode_charger_heartbeat,
.battery_update = healthd_mode_charger_battery_update,
+#endif
};
static struct healthd_mode_ops recovery_ops = {
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 5846626..612885b 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -58,7 +58,7 @@
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#define MSEC_PER_SEC (1000LL)
#define NSEC_PER_MSEC (1000000LL)
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 440f2e4..8865a7d 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -55,7 +55,7 @@
int getBatteryStatus(const char* status);
int getBatteryHealth(const char* status);
- int readFromFile(const String8& path, char* buf, size_t size);
+ int readFromFile(const String8& path, std::string* buf);
PowerSupplyType readPowerSupplyType(const String8& path);
bool getBooleanField(const String8& path);
int getIntField(const String8& path);
diff --git a/include/android/log.h b/include/android/log.h
index 1c171b7..2956e6e 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -124,7 +124,7 @@
void __android_log_assert(const char *cond, const char *tag,
const char *fmt, ...)
#if defined(__GNUC__)
- __attribute__ ((noreturn))
+ __attribute__ ((__noreturn__))
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
__attribute__ ((format(gnu_printf, 3, 4)))
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index 2373c45..b80045f 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -71,6 +71,12 @@
bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
+ // In order to use the iterators on this object, a caller must
+ // call the LockIterator and UnlockIterator function to guarantee
+ // that the data does not change while it's being used.
+ virtual void LockIterator() {}
+ virtual void UnlockIterator() {}
+
typedef std::deque<backtrace_map_t>::iterator iterator;
iterator begin() { return maps_.begin(); }
iterator end() { return maps_.end(); }
@@ -102,4 +108,18 @@
pid_t pid_;
};
+class ScopedBacktraceMapIteratorLock {
+public:
+ explicit ScopedBacktraceMapIteratorLock(BacktraceMap* map) : map_(map) {
+ map->LockIterator();
+ }
+
+ ~ScopedBacktraceMapIteratorLock() {
+ map_->UnlockIterator();
+ }
+
+private:
+ BacktraceMap* map_;
+};
+
#endif // _BACKTRACE_BACKTRACE_MAP_H
diff --git a/include/binderwrapper/binder_wrapper.h b/include/binderwrapper/binder_wrapper.h
index ccda825..a104bff 100644
--- a/include/binderwrapper/binder_wrapper.h
+++ b/include/binderwrapper/binder_wrapper.h
@@ -70,7 +70,7 @@
// is currently registered for |binder|, it will be replaced.
virtual bool RegisterForDeathNotifications(
const sp<IBinder>& binder,
- const base::Closure& callback) = 0;
+ const ::base::Closure& callback) = 0;
// Unregisters the callback, if any, for |binder|.
virtual bool UnregisterForDeathNotifications(const sp<IBinder>& binder) = 0;
diff --git a/include/binderwrapper/stub_binder_wrapper.h b/include/binderwrapper/stub_binder_wrapper.h
index 01c9648..9d4578e 100644
--- a/include/binderwrapper/stub_binder_wrapper.h
+++ b/include/binderwrapper/stub_binder_wrapper.h
@@ -98,7 +98,7 @@
const sp<IBinder>& binder) override;
sp<BBinder> CreateLocalBinder() override;
bool RegisterForDeathNotifications(const sp<IBinder>& binder,
- const base::Closure& callback) override;
+ const ::base::Closure& callback) override;
bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
uid_t GetCallingUid() override;
pid_t GetCallingPid() override;
@@ -119,7 +119,7 @@
// Map from binder handle to the callback that should be invoked on binder
// death.
- std::map<sp<IBinder>, base::Closure> death_callbacks_;
+ std::map<sp<IBinder>, ::base::Closure> death_callbacks_;
// Values to return from GetCallingUid() and GetCallingPid();
uid_t calling_uid_;
diff --git a/include/cutils/ashmem.h b/include/cutils/ashmem.h
index 25b233e..acedf73 100644
--- a/include/cutils/ashmem.h
+++ b/include/cutils/ashmem.h
@@ -12,6 +12,10 @@
#include <stddef.h>
+#if defined(__BIONIC__)
+#include <linux/ashmem.h>
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -26,20 +30,4 @@
}
#endif
-#ifndef __ASHMEMIOC /* in case someone included <linux/ashmem.h> too */
-
-#define ASHMEM_NAME_LEN 256
-
-#define ASHMEM_NAME_DEF "dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_PURGED 0
-#define ASHMEM_WAS_PURGED 1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_IS_UNPINNED 0
-#define ASHMEM_IS_PINNED 1
-
-#endif /* ! __ASHMEMIOC */
-
#endif /* _CUTILS_ASHMEM_H */
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 285e1af..20e8796 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -20,32 +20,10 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#include "debuggerd/client.h"
+
__BEGIN_DECLS
-#define DEBUGGER_SOCKET_NAME "android:debuggerd"
-#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
-#define DEBUGGER64_SOCKET_NAME DEBUGGER_SOCKET_NAME
-
-typedef enum {
- // dump a crash
- DEBUGGER_ACTION_CRASH,
- // dump a tombstone file
- DEBUGGER_ACTION_DUMP_TOMBSTONE,
- // dump a backtrace only back to the socket
- DEBUGGER_ACTION_DUMP_BACKTRACE,
-} debugger_action_t;
-
-// Make sure that all values have a fixed size so that this structure
-// is the same for 32 bit and 64 bit processes.
-// NOTE: Any changes to this structure must also be reflected in
-// bionic/linker/debugger.cpp.
-typedef struct __attribute__((packed)) {
- int32_t action;
- pid_t tid;
- uint64_t abort_msg_address;
- int32_t original_si_code;
-} debugger_msg_t;
-
/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
* Stores the tombstone path in the provided buffer.
* Returns 0 on success, -1 on error.
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index 295d62b..c837edb 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -23,10 +23,8 @@
__BEGIN_DECLS
-void klog_init(void);
int klog_get_level(void);
void klog_set_level(int level);
-/* TODO: void klog_close(void); - and make klog_fd users thread safe. */
void klog_write(int level, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 24aa224..adf670b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -109,7 +109,7 @@
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
-#if defined(__BIONIC_FORTIFY)
+#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
extern int __property_get_real(const char *, char *, const char *)
__asm__(__USER_LABEL_PREFIX__ "property_get");
diff --git a/include/log/log.h b/include/log/log.h
index e606a84..045feca 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -614,11 +614,11 @@
* The stuff in the rest of this file should not be used directly.
*/
-#define android_printLog(prio, tag, fmt...) \
- __android_log_print(prio, tag, fmt)
+#define android_printLog(prio, tag, ...) \
+ __android_log_print(prio, tag, __VA_ARGS__)
-#define android_vprintLog(prio, cond, tag, fmt...) \
- __android_log_vprint(prio, tag, fmt)
+#define android_vprintLog(prio, cond, tag, ...) \
+ __android_log_vprint(prio, tag, __VA_ARGS__)
/* XXX Macros to work around syntax errors in places where format string
* arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
@@ -635,9 +635,9 @@
*/
#define __android_rest(first, ...) , ## __VA_ARGS__
-#define android_printAssert(cond, tag, fmt...) \
+#define android_printAssert(cond, tag, ...) \
__android_log_assert(cond, tag, \
- __android_second(0, ## fmt, NULL) __android_rest(fmt))
+ __android_second(0, ## __VA_ARGS__, NULL) __android_rest(__VA_ARGS__))
#define android_writeLog(prio, tag, text) \
__android_log_write(prio, tag, text)
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 539d1dc..1bc1f72 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -27,6 +27,7 @@
#endif
typedef enum {
+ /* Verbs */
FORMAT_OFF = 0,
FORMAT_BRIEF,
FORMAT_PROCESS,
@@ -36,7 +37,7 @@
FORMAT_TIME,
FORMAT_THREADTIME,
FORMAT_LONG,
- /* The following are modifiers to above formats */
+ /* Adverbs. The following are modifiers to above format verbs */
FORMAT_MODIFIER_COLOR, /* converts priority to color */
FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
diff --git a/include/mincrypt/dsa_sig.h b/include/mincrypt/dsa_sig.h
deleted file mode 100644
index b0d91cd..0000000
--- a/include/mincrypt/dsa_sig.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_
-
-#include "mincrypt/p256.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Returns 0 if input sig is not a valid ASN.1 sequence
-int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */
diff --git a/include/mincrypt/hash-internal.h b/include/mincrypt/hash-internal.h
deleted file mode 100644
index c813b44..0000000
--- a/include/mincrypt/hash-internal.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2007 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-struct HASH_CTX; // forward decl
-
-typedef struct HASH_VTAB {
- void (* const init)(struct HASH_CTX*);
- void (* const update)(struct HASH_CTX*, const void*, int);
- const uint8_t* (* const final)(struct HASH_CTX*);
- const uint8_t* (* const hash)(const void*, int, uint8_t*);
- int size;
-} HASH_VTAB;
-
-typedef struct HASH_CTX {
- const HASH_VTAB * f;
- uint64_t count;
- uint8_t buf[64];
- uint32_t state[8]; // upto SHA2
-} HASH_CTX;
-
-#define HASH_init(ctx) (ctx)->f->init(ctx)
-#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len)
-#define HASH_final(ctx) (ctx)->f->final(ctx)
-#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest)
-#define HASH_size(ctx) (ctx)->f->size
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_
diff --git a/include/mincrypt/p256.h b/include/mincrypt/p256.h
deleted file mode 100644
index 465a1b9..0000000
--- a/include/mincrypt/p256.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
-
-// Collection of routines manipulating 256 bit unsigned integers.
-// Just enough to implement ecdsa-p256 and related algorithms.
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define P256_BITSPERDIGIT 32
-#define P256_NDIGITS 8
-#define P256_NBYTES 32
-
-typedef int p256_err;
-typedef uint32_t p256_digit;
-typedef int32_t p256_sdigit;
-typedef uint64_t p256_ddigit;
-typedef int64_t p256_sddigit;
-
-// Defining p256_int as struct to leverage struct assigment.
-typedef struct {
- p256_digit a[P256_NDIGITS];
-} p256_int;
-
-extern const p256_int SECP256r1_n; // Curve order
-extern const p256_int SECP256r1_p; // Curve prime
-extern const p256_int SECP256r1_b; // Curve param
-
-// Initialize a p256_int to zero.
-void p256_init(p256_int* a);
-
-// Clear a p256_int to zero.
-void p256_clear(p256_int* a);
-
-// Return bit. Index 0 is least significant.
-int p256_get_bit(const p256_int* a, int index);
-
-// b := a % MOD
-void p256_mod(
- const p256_int* MOD,
- const p256_int* a,
- p256_int* b);
-
-// c := a * (top_b | b) % MOD
-void p256_modmul(
- const p256_int* MOD,
- const p256_int* a,
- const p256_digit top_b,
- const p256_int* b,
- p256_int* c);
-
-// b := 1 / a % MOD
-// MOD best be SECP256r1_n
-void p256_modinv(
- const p256_int* MOD,
- const p256_int* a,
- p256_int* b);
-
-// b := 1 / a % MOD
-// MOD best be SECP256r1_n
-// Faster than p256_modinv()
-void p256_modinv_vartime(
- const p256_int* MOD,
- const p256_int* a,
- p256_int* b);
-
-// b := a << (n % P256_BITSPERDIGIT)
-// Returns the bits shifted out of most significant digit.
-p256_digit p256_shl(const p256_int* a, int n, p256_int* b);
-
-// b := a >> (n % P256_BITSPERDIGIT)
-void p256_shr(const p256_int* a, int n, p256_int* b);
-
-int p256_is_zero(const p256_int* a);
-int p256_is_odd(const p256_int* a);
-int p256_is_even(const p256_int* a);
-
-// Returns -1, 0 or 1.
-int p256_cmp(const p256_int* a, const p256_int *b);
-
-// c: = a - b
-// Returns -1 on borrow.
-int p256_sub(const p256_int* a, const p256_int* b, p256_int* c);
-
-// c := a + b
-// Returns 1 on carry.
-int p256_add(const p256_int* a, const p256_int* b, p256_int* c);
-
-// c := a + (single digit)b
-// Returns carry 1 on carry.
-int p256_add_d(const p256_int* a, p256_digit b, p256_int* c);
-
-// ec routines.
-
-// {out_x,out_y} := nG
-void p256_base_point_mul(const p256_int *n,
- p256_int *out_x,
- p256_int *out_y);
-
-// {out_x,out_y} := n{in_x,in_y}
-void p256_point_mul(const p256_int *n,
- const p256_int *in_x,
- const p256_int *in_y,
- p256_int *out_x,
- p256_int *out_y);
-
-// {out_x,out_y} := n1G + n2{in_x,in_y}
-void p256_points_mul_vartime(
- const p256_int *n1, const p256_int *n2,
- const p256_int *in_x, const p256_int *in_y,
- p256_int *out_x, p256_int *out_y);
-
-// Return whether point {x,y} is on curve.
-int p256_is_valid_point(const p256_int* x, const p256_int* y);
-
-// Outputs big-endian binary form. No leading zero skips.
-void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]);
-
-// Reads from big-endian binary form,
-// thus pre-pad with leading zeros if short.
-void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst);
-
-#define P256_DIGITS(x) ((x)->a)
-#define P256_DIGIT(x,y) ((x)->a[y])
-
-#define P256_ZERO {{0}}
-#define P256_ONE {{1}}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_
diff --git a/include/mincrypt/p256_ecdsa.h b/include/mincrypt/p256_ecdsa.h
deleted file mode 100644
index da339fa..0000000
--- a/include/mincrypt/p256_ecdsa.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
-
-// Using current directory as relative include path here since
-// this code typically gets lifted into a variety of build systems
-// and directory structures.
-#include "p256.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Returns 0 if {r,s} is not a signature on message for
-// public key {key_x,key_y}.
-//
-// Note: message is a p256_int.
-// Convert from a binary string using p256_from_bin().
-int p256_ecdsa_verify(const p256_int* key_x,
- const p256_int* key_y,
- const p256_int* message,
- const p256_int* r, const p256_int* s);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_
diff --git a/include/mincrypt/rsa.h b/include/mincrypt/rsa.h
deleted file mode 100644
index 3d0556b..0000000
--- a/include/mincrypt/rsa.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* rsa.h
-**
-** Copyright 2008, The Android Open Source Project
-**
-** 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.
-** * Neither the name of Google Inc. nor the names of its contributors may
-** be used to endorse or promote products derived from this software
-** without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
-*/
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
-
-#include <inttypes.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define RSANUMBYTES 256 /* 2048 bit key length */
-#define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t))
-
-typedef struct RSAPublicKey {
- int len; /* Length of n[] in number of uint32_t */
- uint32_t n0inv; /* -1 / n[0] mod 2^32 */
- uint32_t n[RSANUMWORDS]; /* modulus as little endian array */
- uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */
- int exponent; /* 3 or 65537 */
-} RSAPublicKey;
-
-int RSA_verify(const RSAPublicKey *key,
- const uint8_t* signature,
- const int len,
- const uint8_t* hash,
- const int hash_len);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_
diff --git a/include/mincrypt/sha.h b/include/mincrypt/sha.h
deleted file mode 100644
index ef60aab..0000000
--- a/include/mincrypt/sha.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2005 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
-
-#include <stdint.h>
-#include "hash-internal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-typedef HASH_CTX SHA_CTX;
-
-void SHA_init(SHA_CTX* ctx);
-void SHA_update(SHA_CTX* ctx, const void* data, int len);
-const uint8_t* SHA_final(SHA_CTX* ctx);
-
-// Convenience method. Returns digest address.
-// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes.
-const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest);
-
-#define SHA_DIGEST_SIZE 20
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_
diff --git a/include/mincrypt/sha256.h b/include/mincrypt/sha256.h
deleted file mode 100644
index 3a87c31..0000000
--- a/include/mincrypt/sha256.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-
-#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
-#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
-
-#include <stdint.h>
-#include "hash-internal.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-typedef HASH_CTX SHA256_CTX;
-
-void SHA256_init(SHA256_CTX* ctx);
-void SHA256_update(SHA256_CTX* ctx, const void* data, int len);
-const uint8_t* SHA256_final(SHA256_CTX* ctx);
-
-// Convenience method. Returns digest address.
-const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest);
-
-#define SHA256_DIGEST_SIZE 32
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 5ccd80e..bc1c0ca 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -94,6 +94,7 @@
#define AID_NVRAM 1050 /* Access-controlled NVRAM */
#define AID_DNS 1051 /* DNS resolution daemon (system: netd) */
#define AID_DNS_TETHER 1052 /* DNS resolution daemon (tether: dnsmasq) */
+#define AID_WEBVIEW_ZYGOTE 1053 /* WebView zygote process */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
@@ -207,6 +208,7 @@
{ "nvram", AID_NVRAM, },
{ "dns", AID_DNS, },
{ "dns_tether", AID_DNS_TETHER, },
+ { "webview_zygote", AID_WEBVIEW_ZYGOTE, },
{ "shell", AID_SHELL, },
{ "cache", AID_CACHE, },
diff --git a/include/system/qemu_pipe.h b/include/system/qemu_pipe.h
new file mode 100644
index 0000000..d403f8d
--- /dev/null
+++ b/include/system/qemu_pipe.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
+#define ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+# define QEMU_PIPE_DEBUG(...) (void)0
+#endif
+
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+//
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL -> unknown/unsupported pipeName
+// ENOSYS -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+static __inline__ int qemu_pipe_open(const char* pipeName) {
+ // Sanity check.
+ if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+ if (fd < 0) {
+ QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
+ strerror(errno));
+ return -1;
+ }
+
+ // Write the pipe name, *including* the trailing zero which is necessary.
+ size_t pipeNameLen = strlen(pipeName);
+ ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U));
+ if (ret != (ssize_t)pipeNameLen + 1) {
+ QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s",
+ __FUNCTION__, pipeName, strerror(errno));
+ if (ret == 0) {
+ errno = ECONNRESET;
+ } else if (ret > 0) {
+ errno = EINVAL;
+ }
+ return -1;
+ }
+ return fd;
+}
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+static int __inline__ qemu_pipe_frame_send(int fd,
+ const void* buff,
+ size_t len) {
+ char header[5];
+ snprintf(header, sizeof(header), "%04x", len);
+ ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4));
+ if (ret != 4) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ ret = TEMP_FAILURE_RETRY(write(fd, buff, len));
+ if (ret != (ssize_t)len) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+static int __inline__ qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+ char header[5];
+ ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4));
+ if (ret != 4) {
+ QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ header[4] = '\0';
+ size_t size;
+ if (sscanf(header, "%04zx", &size) != 1) {
+ QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+ return -1;
+ }
+ if (size > len) {
+ QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
+ len);
+ return -1;
+ }
+ ret = TEMP_FAILURE_RETRY(read(fd, buff, size));
+ if (ret != size) {
+ QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
+ strerror(errno));
+ return -1;
+ }
+ return size;
+}
+
+#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/include/utils/Condition.h b/include/utils/Condition.h
index 5a72519..a420185 100644
--- a/include/utils/Condition.h
+++ b/include/utils/Condition.h
@@ -106,30 +106,40 @@
return -pthread_cond_wait(&mCond, &mutex.mMutex);
}
inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
-#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)
- struct timespec ts;
- ts.tv_sec = reltime/1000000000;
- ts.tv_nsec = reltime%1000000000;
- return -pthread_cond_timedwait_relative_np(&mCond, &mutex.mMutex, &ts);
-#else // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
struct timespec ts;
#if defined(__linux__)
clock_gettime(CLOCK_REALTIME, &ts);
#else // __APPLE__
- // we don't support the clocks here.
+ // Apple doesn't support POSIX clocks.
struct timeval t;
gettimeofday(&t, NULL);
ts.tv_sec = t.tv_sec;
- ts.tv_nsec= t.tv_usec*1000;
+ ts.tv_nsec = t.tv_usec*1000;
#endif
- ts.tv_sec += reltime/1000000000;
- ts.tv_nsec+= reltime%1000000000;
- if (ts.tv_nsec >= 1000000000) {
+
+ // On 32-bit devices, tv_sec is 32-bit, but `reltime` is 64-bit.
+ int64_t reltime_sec = reltime/1000000000;
+
+ ts.tv_nsec += reltime%1000000000;
+ if (reltime_sec < INT64_MAX && ts.tv_nsec >= 1000000000) {
ts.tv_nsec -= 1000000000;
- ts.tv_sec += 1;
+ ++reltime_sec;
}
+
+ int64_t time_sec = ts.tv_sec;
+ if (time_sec > INT64_MAX - reltime_sec) {
+ time_sec = INT64_MAX;
+ } else {
+ time_sec += reltime_sec;
+ }
+
+#if defined(__LP64__)
+ ts.tv_sec = time_sec;
+#else
+ ts.tv_sec = (time_sec > INT32_MAX) ? INT32_MAX : time_sec;
+#endif
+
return -pthread_cond_timedwait(&mCond, &mutex.mMutex, &ts);
-#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
}
inline void Condition::signal() {
/*
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index ed96fe4..f4e225a 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -56,36 +56,55 @@
private:
LruCache(const LruCache& that); // disallow copy constructor
- struct Entry {
+ // Super class so that we can have entries having only a key reference, for searches.
+ class KeyedEntry {
+ public:
+ virtual const TKey& getKey() const = 0;
+ // Make sure the right destructor is executed so that keys and values are deleted.
+ virtual ~KeyedEntry() {}
+ };
+
+ class Entry final : public KeyedEntry {
+ public:
TKey key;
TValue value;
Entry* parent;
Entry* child;
- Entry(TKey key_, TValue value_) : key(key_), value(value_), parent(NULL), child(NULL) {
+ Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(NULL), child(NULL) {
}
- const TKey& getKey() const { return key; }
+ const TKey& getKey() const final { return key; }
};
- struct HashForEntry : public std::unary_function<Entry*, hash_t> {
- size_t operator() (const Entry* entry) const {
- return hash_type(entry->key);
+ class EntryForSearch : public KeyedEntry {
+ public:
+ const TKey& key;
+ EntryForSearch(const TKey& key_) : key(key_) {
+ }
+ const TKey& getKey() const final { return key; }
+ };
+
+ struct HashForEntry : public std::unary_function<KeyedEntry*, hash_t> {
+ size_t operator() (const KeyedEntry* entry) const {
+ return hash_type(entry->getKey());
};
};
- struct EqualityForHashedEntries : public std::unary_function<Entry*, hash_t> {
- bool operator() (const Entry* lhs, const Entry* rhs) const {
- return lhs->key == rhs->key;
+ struct EqualityForHashedEntries : public std::unary_function<KeyedEntry*, hash_t> {
+ bool operator() (const KeyedEntry* lhs, const KeyedEntry* rhs) const {
+ return lhs->getKey() == rhs->getKey();
};
};
- typedef std::unordered_set<Entry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
+ // All entries in the set will be Entry*. Using the weaker KeyedEntry as to allow entries
+ // that have only a key reference, for searching.
+ typedef std::unordered_set<KeyedEntry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
void attachToCache(Entry& entry);
void detachFromCache(Entry& entry);
typename LruCacheSet::iterator findByKey(const TKey& key) {
- Entry entryForSearch(key, mNullValue);
+ EntryForSearch entryForSearch(key);
typename LruCacheSet::iterator result = mSet->find(&entryForSearch);
return result;
}
@@ -124,11 +143,13 @@
}
const TValue& value() const {
- return (*mIterator)->value;
+ // All the elements in the set are of type Entry. See comment in the definition
+ // of LruCacheSet above.
+ return reinterpret_cast<Entry *>(*mIterator)->value;
}
const TKey& key() const {
- return (*mIterator)->key;
+ return (*mIterator)->getKey();
}
private:
const LruCache<TKey, TValue>& mCache;
@@ -171,7 +192,9 @@
if (find_result == mSet->end()) {
return mNullValue;
}
- Entry *entry = *find_result;
+ // All the elements in the set are of type Entry. See comment in the definition
+ // of LruCacheSet above.
+ Entry *entry = reinterpret_cast<Entry*>(*find_result);
detachFromCache(*entry);
attachToCache(*entry);
return entry->value;
@@ -199,7 +222,9 @@
if (find_result == mSet->end()) {
return false;
}
- Entry* entry = *find_result;
+ // All the elements in the set are of type Entry. See comment in the definition
+ // of LruCacheSet above.
+ Entry* entry = reinterpret_cast<Entry*>(*find_result);
mSet->erase(entry);
if (mListener) {
(*mListener)(entry->key, entry->value);
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 14d9cb1..c82e7d9 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -196,9 +196,10 @@
private:
friend class ReferenceMover;
- inline static void renameRefs(size_t n, const ReferenceRenamer& renamer) { }
- inline static void renameRefId(T* ref,
- const void* old_id, const void* new_id) { }
+ inline static void renameRefs(size_t /*n*/,
+ const ReferenceRenamer& /*renamer*/) { }
+ inline static void renameRefId(T* /*ref*/,
+ const void* /*old_id*/ , const void* /*new_id*/) { }
private:
mutable std::atomic<int32_t> mCount;
diff --git a/include/utils/String16.h b/include/utils/String16.h
index 9bb6f0d..07c4de7 100644
--- a/include/utils/String16.h
+++ b/include/utils/String16.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_STRING16_H
#define ANDROID_STRING16_H
+#include <string> // for std::string
+
#include <utils/Errors.h>
-#include <utils/Unicode.h>
+#include <utils/String8.h>
#include <utils/TypeHelpers.h>
// ---------------------------------------------------------------------------
@@ -62,9 +64,10 @@
explicit String16(const char* o, size_t len);
~String16();
-
+
inline const char16_t* string() const;
-
+
+ static inline std::string std_string(const String16& str);
size_t size() const;
void setTo(const String16& other);
status_t setTo(const char16_t* other);
@@ -72,12 +75,12 @@
status_t setTo(const String16& other,
size_t len,
size_t begin=0);
-
+
status_t append(const String16& other);
status_t append(const char16_t* other, size_t len);
-
+
inline String16& operator=(const String16& other);
-
+
inline String16& operator+=(const String16& other);
inline String16 operator+(const String16& other) const;
@@ -108,16 +111,16 @@
inline bool operator!=(const String16& other) const;
inline bool operator>=(const String16& other) const;
inline bool operator>(const String16& other) const;
-
+
inline bool operator<(const char16_t* other) const;
inline bool operator<=(const char16_t* other) const;
inline bool operator==(const char16_t* other) const;
inline bool operator!=(const char16_t* other) const;
inline bool operator>=(const char16_t* other) const;
inline bool operator>(const char16_t* other) const;
-
+
inline operator const char16_t*() const;
-
+
private:
const char16_t* mString;
};
@@ -144,6 +147,11 @@
return mString;
}
+inline std::string String16::std_string(const String16& str)
+{
+ return std::string(String8(str).string());
+}
+
inline String16& String16::operator=(const String16& other)
{
setTo(other);
diff --git a/include/utils/String8.h b/include/utils/String8.h
index 2a75b98..1d12994 100644
--- a/include/utils/String8.h
+++ b/include/utils/String8.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_STRING8_H
#define ANDROID_STRING8_H
+#include <string> // for std::string
+
#include <utils/Errors.h>
#include <utils/Unicode.h>
#include <utils/TypeHelpers.h>
@@ -49,7 +51,7 @@
String8(const String8& o);
explicit String8(const char* o);
explicit String8(const char* o, size_t numChars);
-
+
explicit String8(const String16& o);
explicit String8(const char16_t* o);
explicit String8(const char16_t* o, size_t numChars);
@@ -63,12 +65,13 @@
static String8 formatV(const char* fmt, va_list args);
inline const char* string() const;
+ static inline std::string std_string(const String8& str);
inline size_t size() const;
inline size_t bytes() const;
inline bool isEmpty() const;
-
+
size_t length() const;
-
+
void clear();
void setTo(const String8& other);
@@ -95,10 +98,10 @@
inline String8& operator=(const String8& other);
inline String8& operator=(const char* other);
-
+
inline String8& operator+=(const String8& other);
inline String8 operator+(const String8& other) const;
-
+
inline String8& operator+=(const char* other);
inline String8 operator+(const char* other) const;
@@ -110,20 +113,20 @@
inline bool operator!=(const String8& other) const;
inline bool operator>=(const String8& other) const;
inline bool operator>(const String8& other) const;
-
+
inline bool operator<(const char* other) const;
inline bool operator<=(const char* other) const;
inline bool operator==(const char* other) const;
inline bool operator!=(const char* other) const;
inline bool operator>=(const char* other) const;
inline bool operator>(const char* other) const;
-
+
inline operator const char*() const;
-
+
char* lockBuffer(size_t size);
void unlockBuffer();
status_t unlockBuffer(size_t size);
-
+
// return the index of the first byte of other in this at or after
// start, or -1 if not found
ssize_t find(const char* other, size_t start = 0) const;
@@ -261,6 +264,11 @@
return mString;
}
+inline std::string String8::std_string(const String8& str)
+{
+ return std::string(str.string());
+}
+
inline size_t String8::size() const
{
return length();
diff --git a/include/utils/ashmem.h b/include/utils/ashmem.h
deleted file mode 100644
index 0854775..0000000
--- a/include/utils/ashmem.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* utils/ashmem.h
- **
- ** Copyright 2008 The Android Open Source Project
- **
- ** This file is dual licensed. It may be redistributed and/or modified
- ** under the terms of the Apache 2.0 License OR version 2 of the GNU
- ** General Public License.
- */
-
-#ifndef _UTILS_ASHMEM_H
-#define _UTILS_ASHMEM_H
-
-#include <linux/limits.h>
-#include <linux/ioctl.h>
-
-#define ASHMEM_NAME_LEN 256
-
-#define ASHMEM_NAME_DEF "dev/ashmem"
-
-/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
-#define ASHMEM_NOT_REAPED 0
-#define ASHMEM_WAS_REAPED 1
-
-/* Return values from ASHMEM_UNPIN: Is the mapping now pinned or unpinned? */
-#define ASHMEM_NOW_UNPINNED 0
-#define ASHMEM_NOW_PINNED 1
-
-#define __ASHMEMIOC 0x77
-
-#define ASHMEM_SET_NAME _IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
-#define ASHMEM_GET_NAME _IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
-#define ASHMEM_SET_SIZE _IOW(__ASHMEMIOC, 3, size_t)
-#define ASHMEM_GET_SIZE _IO(__ASHMEMIOC, 4)
-#define ASHMEM_SET_PROT_MASK _IOW(__ASHMEMIOC, 5, unsigned long)
-#define ASHMEM_GET_PROT_MASK _IO(__ASHMEMIOC, 6)
-#define ASHMEM_PIN _IO(__ASHMEMIOC, 7)
-#define ASHMEM_UNPIN _IO(__ASHMEMIOC, 8)
-#define ASHMEM_ISPINNED _IO(__ASHMEMIOC, 9)
-#define ASHMEM_PURGE_ALL_CACHES _IO(__ASHMEMIOC, 10)
-
-#endif /* _UTILS_ASHMEM_H */
diff --git a/init/Android.mk b/init/Android.mk
index 67541b8..36a5713 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -52,7 +52,7 @@
service.cpp \
util.cpp \
-LOCAL_STATIC_LIBRARIES := libbase libselinux
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
LOCAL_MODULE := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
@@ -92,16 +92,16 @@
libcutils \
libext4_utils_static \
libbase \
- libutils \
libc \
libselinux \
liblog \
- libmincrypt \
+ libcrypto_utils_static \
libcrypto_static \
libc++_static \
libdl \
libsparse_static \
- libz
+ libz \
+ libprocessgroup
# Create symlinks
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/action.cpp b/init/action.cpp
index 510ea89..f3e362e 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -42,7 +42,7 @@
expanded_args[0] = args_[0];
for (std::size_t i = 1; i < args_.size(); ++i) {
if (!expand_props(args_[i], &expanded_args[i])) {
- ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
+ LOG(ERROR) << args_[0] << ": cannot expand '" << args_[i] << "'";
return -EINVAL;
}
}
@@ -118,14 +118,13 @@
Timer t;
int result = command.InvokeFunc();
- if (klog_get_level() >= KLOG_INFO_LEVEL) {
+ if (klog_get_level() >= KLOG_DEBUG_LEVEL) {
std::string trigger_name = BuildTriggersString();
std::string cmd_str = command.BuildCommandString();
std::string source = command.BuildSourceString();
- INFO("Command '%s' action=%s%s returned %d took %.2fs\n",
- cmd_str.c_str(), trigger_name.c_str(), source.c_str(),
- result, t.duration());
+ LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << source
+ << " returned " << result << " took " << t.duration() << "s";
}
}
@@ -253,18 +252,17 @@
void Action::DumpState() const {
std::string trigger_name = BuildTriggersString();
- INFO("on %s\n", trigger_name.c_str());
+ LOG(INFO) << "on " << trigger_name;
for (const auto& c : commands_) {
std::string cmd_str = c.BuildCommandString();
- INFO(" %s\n", cmd_str.c_str());
+ LOG(INFO) << " %s" << cmd_str;
}
- INFO("\n");
}
class EventTrigger : public Trigger {
public:
- EventTrigger(const std::string& trigger) : trigger_(trigger) {
+ explicit EventTrigger(const std::string& trigger) : trigger_(trigger) {
}
bool CheckTriggers(const Action& action) const override {
return action.CheckEventTrigger(trigger_);
@@ -288,7 +286,7 @@
class BuiltinTrigger : public Trigger {
public:
- BuiltinTrigger(Action* action) : action_(action) {
+ explicit BuiltinTrigger(Action* action) : action_(action) {
}
bool CheckTriggers(const Action& action) const override {
return action_ == &action;
@@ -366,7 +364,7 @@
if (current_command_ == 0) {
std::string trigger_name = action->BuildTriggersString();
- INFO("processing action (%s)\n", trigger_name.c_str());
+ LOG(INFO) << "processing action (" << trigger_name << ")";
}
action->ExecuteOneCommand(current_command_);
@@ -395,7 +393,6 @@
for (const auto& a : actions_) {
a->DumpState();
}
- INFO("\n");
}
bool ActionParser::ParseSection(const std::vector<std::string>& args,
diff --git a/init/action.h b/init/action.h
index 6dee2d0..0bae9f0 100644
--- a/init/action.h
+++ b/init/action.h
@@ -44,7 +44,7 @@
class Action {
public:
- Action(bool oneshot = false);
+ explicit Action(bool oneshot = false);
bool AddCommand(const std::vector<std::string>& args,
const std::string& filename, int line, std::string* err);
diff --git a/init/bootchart.cpp b/init/bootchart.cpp
index 5704d28..467a838 100644
--- a/init/bootchart.cpp
+++ b/init/bootchart.cpp
@@ -206,12 +206,12 @@
int do_bootchart_init(const std::vector<std::string>& args) {
g_remaining_samples = bootchart_init();
if (g_remaining_samples < 0) {
- ERROR("Bootcharting init failure: %s\n", strerror(errno));
+ PLOG(ERROR) << "Bootcharting initialization failed";
} else if (g_remaining_samples > 0) {
- NOTICE("Bootcharting started (will run for %d s).\n",
- (g_remaining_samples * BOOTCHART_POLLING_MS) / 1000);
+ LOG(INFO) << "Bootcharting started (will run for "
+ << ((g_remaining_samples * BOOTCHART_POLLING_MS) / 1000) << " s).";
} else {
- NOTICE("Not bootcharting.\n");
+ LOG(VERBOSE) << "Not bootcharting.";
}
return 0;
}
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 70f9194..b227d40 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -36,6 +36,7 @@
#include <sys/wait.h>
#include <unistd.h>
#include <linux/loop.h>
+#include <linux/module.h>
#include <ext4_crypt.h>
#include <ext4_crypt_init_extensions.h>
@@ -45,12 +46,12 @@
#include <fs_mgr.h>
#include <android-base/file.h>
#include <android-base/parseint.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <bootloader_message/bootloader_message.h>
#include <cutils/partition_utils.h>
#include <cutils/android_reboot.h>
#include <logwrap/logwrap.h>
-#include <private/android_filesystem_config.h>
#include "action.h"
#include "bootchart.h"
@@ -69,15 +70,15 @@
static const int kTerminateServiceDelayMicroSeconds = 50000;
-static int insmod(const char *filename, const char *options) {
+static int insmod(const char *filename, const char *options, int flags) {
int fd = open(filename, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);
if (fd == -1) {
- ERROR("insmod: open(\"%s\") failed: %s", filename, strerror(errno));
+ PLOG(ERROR) << "insmod: open(\"" << filename << "\") failed";
return -1;
}
- int rc = syscall(__NR_finit_module, fd, options, 0);
+ int rc = syscall(__NR_finit_module, fd, options, flags);
if (rc == -1) {
- ERROR("finit_module for \"%s\" failed: %s", filename, strerror(errno));
+ PLOG(ERROR) << "finit_module for \"" << filename << "\" failed";
}
close(fd);
return rc;
@@ -140,7 +141,7 @@
const std::vector<std::string> options = {"--wipe_data", std::string() + "--reason=" + reason};
std::string err;
if (!write_bootloader_message(options, &err)) {
- ERROR("failed to set bootloader message: %s", err.c_str());
+ LOG(ERROR) << "failed to set bootloader message: " << err;
return -1;
}
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
@@ -213,13 +214,13 @@
const char *f2fs_argv[] = {
"/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
};
- android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv,
+ android_fork_execvp_ext(arraysize(f2fs_argv), (char **)f2fs_argv,
&st, true, LOG_KLOG, true, NULL, NULL, 0);
} else if (!strcmp(entry->mnt_type, "ext4")) {
const char *ext4_argv[] = {
"/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
};
- android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv,
+ android_fork_execvp_ext(arraysize(ext4_argv), (char **)ext4_argv,
&st, true, LOG_KLOG, true, NULL, NULL, 0);
}
}
@@ -283,17 +284,17 @@
}
static int do_insmod(const std::vector<std::string>& args) {
- std::string options;
+ int flags = 0;
+ auto it = args.begin() + 1;
- if (args.size() > 2) {
- options += args[2];
- for (std::size_t i = 3; i < args.size(); ++i) {
- options += ' ';
- options += args[i];
- }
+ if (!(*it).compare("-f")) {
+ flags = MODULE_INIT_IGNORE_VERMAGIC | MODULE_INIT_IGNORE_MODVERSIONS;
+ it++;
}
- return insmod(args[1].c_str(), options.c_str());
+ std::string filename = *it++;
+ std::string options = android::base::Join(std::vector<std::string>(it, args.end()), ' ');
+ return insmod(filename.c_str(), options.c_str(), flags);
}
static int do_mkdir(const std::vector<std::string>& args) {
@@ -405,22 +406,7 @@
source = args[2].c_str();
target = args[3].c_str();
- if (!strncmp(source, "mtd@", 4)) {
- n = mtd_name_to_number(source + 4);
- if (n < 0) {
- return -1;
- }
-
- snprintf(tmp, sizeof(tmp), "/dev/block/mtdblock%d", n);
-
- if (wait)
- wait_for_file(tmp, COMMAND_RETRY_TIMEOUT);
- if (mount(tmp, target, system, flags, options) < 0) {
- return -1;
- }
-
- goto exit_success;
- } else if (!strncmp(source, "loop@", 5)) {
+ if (!strncmp(source, "loop@", 5)) {
int mode, loop, fd;
struct loop_info info;
@@ -459,7 +445,7 @@
}
close(fd);
- ERROR("out of loopback devices");
+ LOG(ERROR) << "out of loopback devices";
return -1;
} else {
if (wait)
@@ -522,9 +508,9 @@
if (pid > 0) {
/* Parent. Wait for the child to return */
int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
- if (wp_ret < 0) {
- /* Unexpected error code. We will continue anyway. */
- NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno));
+ if (wp_ret == -1) {
+ // Unexpected error code. We will continue anyway.
+ PLOG(WARNING) << "waitpid failed";
}
if (WIFEXITED(status)) {
@@ -539,7 +525,7 @@
child_ret = fs_mgr_mount_all(fstab);
fs_mgr_free_fstab(fstab);
if (child_ret == -1) {
- ERROR("fs_mgr_mount_all returned an error\n");
+ PLOG(ERROR) << "fs_mgr_mount_all returned an error";
}
_exit(child_ret);
} else {
@@ -564,7 +550,7 @@
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
- ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
+ PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
ret = wipe_data_via_recovery("wipe_data_via_recovery");
/* If reboot worked, there is no return. */
} else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
@@ -578,7 +564,7 @@
// do anything different from the nonencrypted case.
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret > 0) {
- ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
+ PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << ret;
}
/* else ... < 0: error */
@@ -615,7 +601,7 @@
static int do_start(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
- ERROR("do_start: Service %s not found\n", args[1].c_str());
+ LOG(ERROR) << "do_start: Service " << args[1] << " not found";
return -1;
}
if (!svc->Start())
@@ -626,7 +612,7 @@
static int do_stop(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
- ERROR("do_stop: Service %s not found\n", args[1].c_str());
+ LOG(ERROR) << "do_stop: Service " << args[1] << " not found";
return -1;
}
svc->Stop();
@@ -636,7 +622,7 @@
static int do_restart(const std::vector<std::string>& args) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
- ERROR("do_restart: Service %s not found\n", args[1].c_str());
+ LOG(ERROR) << "do_restart: Service " << args[1] << " not found";
return -1;
}
svc->Restart();
@@ -657,7 +643,7 @@
cmd = ANDROID_RB_RESTART2;
len = 6;
} else {
- ERROR("powerctl: unrecognized command '%s'\n", command);
+ LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
return -EINVAL;
}
@@ -671,7 +657,7 @@
reboot_target = &command[len + 1];
}
} else if (command[len] != '\0') {
- ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
+ LOG(ERROR) << "powerctl: unrecognized reboot target '" << &command[len] << "'";
return -EINVAL;
}
@@ -708,7 +694,7 @@
// Wait a bit before recounting the number or running services.
usleep(kTerminateServiceDelayMicroSeconds);
}
- NOTICE("Terminating running services took %.02f seconds", t.duration());
+ LOG(VERBOSE) << "Terminating running services took " << t.duration() << " seconds";
}
return android_reboot_with_callback(cmd, 0, reboot_target,
@@ -888,7 +874,7 @@
static int do_loglevel(const std::vector<std::string>& args) {
int log_level = std::stoi(args[1]);
if (log_level < KLOG_ERROR_LEVEL || log_level > KLOG_DEBUG_LEVEL) {
- ERROR("loglevel: invalid log level'%d'\n", log_level);
+ LOG(ERROR) << "loglevel: invalid log level " << log_level;
return -EINVAL;
}
klog_set_level(log_level);
diff --git a/init/devices.cpp b/init/devices.cpp
index cffc561..373177e 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -31,6 +31,8 @@
#include <sys/un.h>
#include <linux/netlink.h>
+#include <memory>
+
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
@@ -41,6 +43,7 @@
#include <sys/wait.h>
#include <android-base/file.h>
+#include <android-base/stringprintf.h>
#include <cutils/list.h>
#include <cutils/uevent.h>
@@ -128,49 +131,6 @@
return 0;
}
-void fixup_sys_perms(const char *upath)
-{
- char buf[512];
- struct listnode *node;
- struct perms_ *dp;
-
- /* upaths omit the "/sys" that paths in this list
- * contain, so we add 4 when comparing...
- */
- list_for_each(node, &sys_perms) {
- dp = &(node_to_item(node, struct perm_node, plist))->dp;
- if (dp->prefix) {
- if (strncmp(upath, dp->name + 4, strlen(dp->name + 4)))
- continue;
- } else if (dp->wildcard) {
- if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0)
- continue;
- } else {
- if (strcmp(upath, dp->name + 4))
- continue;
- }
-
- if ((strlen(upath) + strlen(dp->attr) + 6) > sizeof(buf))
- break;
-
- snprintf(buf, sizeof(buf), "/sys%s/%s", upath, dp->attr);
- INFO("fixup %s %d %d 0%o\n", buf, dp->uid, dp->gid, dp->perm);
- chown(buf, dp->uid, dp->gid);
- chmod(buf, dp->perm);
- }
-
- // Now fixup SELinux file labels
- int len = snprintf(buf, sizeof(buf), "/sys%s", upath);
- if ((len < 0) || ((size_t) len >= sizeof(buf))) {
- // Overflow
- return;
- }
- if (access(buf, F_OK) == 0) {
- INFO("restorecon_recursive: %s\n", buf);
- restorecon_recursive(buf);
- }
-}
-
static bool perm_path_matches(const char *path, struct perms_ *dp)
{
if (dp->prefix) {
@@ -187,6 +147,45 @@
return false;
}
+static bool match_subsystem(perms_* dp, const char* pattern,
+ const char* path, const char* subsystem) {
+ if (!pattern || !subsystem || strstr(dp->name, subsystem) == NULL) {
+ return false;
+ }
+
+ std::string subsys_path = android::base::StringPrintf(pattern, subsystem, basename(path));
+ return perm_path_matches(subsys_path.c_str(), dp);
+}
+
+static void fixup_sys_perms(const char* upath, const char* subsystem) {
+ // upaths omit the "/sys" that paths in this list
+ // contain, so we prepend it...
+ std::string path = std::string(SYSFS_PREFIX) + upath;
+
+ listnode* node;
+ list_for_each(node, &sys_perms) {
+ perms_* dp = &(node_to_item(node, perm_node, plist))->dp;
+ if (match_subsystem(dp, SYSFS_PREFIX "/class/%s/%s", path.c_str(), subsystem)) {
+ ; // matched
+ } else if (match_subsystem(dp, SYSFS_PREFIX "/bus/%s/devices/%s", path.c_str(), subsystem)) {
+ ; // matched
+ } else if (!perm_path_matches(path.c_str(), dp)) {
+ continue;
+ }
+
+ std::string attr_file = path + "/" + dp->attr;
+ LOG(INFO) << "fixup " << attr_file
+ << " " << dp->uid << " " << dp->gid << " " << std::oct << dp->perm;
+ chown(attr_file.c_str(), dp->uid, dp->gid);
+ chmod(attr_file.c_str(), dp->perm);
+ }
+
+ if (access(path.c_str(), F_OK) == 0) {
+ LOG(VERBOSE) << "restorecon_recursive: " << path;
+ restorecon_recursive(path.c_str());
+ }
+}
+
static mode_t get_device_perm(const char *path, const char **links,
unsigned *uid, unsigned *gid)
{
@@ -243,8 +242,7 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
if (selabel_lookup_best_match(sehandle, &secontext, path, links, mode)) {
- ERROR("Device '%s' not created; cannot find SELinux label (%s)\n",
- path, strerror(errno));
+ PLOG(ERROR) << "Device '" << path << "' not created; cannot find SELinux label";
return;
}
setfscreatecon(secontext);
@@ -259,11 +257,23 @@
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
if (mknod(path, mode, dev) && (errno == EEXIST)) {
- if (lsetfilecon(path, secontext)) {
- ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
- secontext, path, strerror(errno));
+
+ char* fcon = nullptr;
+ int rc = lgetfilecon(path, &fcon);
+ if (rc < 0) {
+ PLOG(ERROR) << "Cannot get SELinux label on '" << path << "' device";
+ goto out;
+ }
+
+ bool different = strcmp(fcon, secontext) != 0;
+ freecon(fcon);
+
+ if (different && lsetfilecon(path, secontext)) {
+ PLOG(ERROR) << "Cannot set '" << secontext << "' SELinux label on '" << path << "' device";
}
}
+
+out:
chown(path, uid, -1);
setegid(AID_ROOT);
@@ -283,7 +293,7 @@
name += 9;
}
- INFO("adding platform device %s (%s)\n", name, path);
+ LOG(INFO) << "adding platform device " << name << " (" << path << ")";
bus = (platform_node*) calloc(1, sizeof(struct platform_node));
bus->path = strdup(path);
@@ -322,7 +332,7 @@
list_for_each_reverse(node, &platform_names) {
bus = node_to_item(node, struct platform_node, list);
if (!strcmp(path, bus->path)) {
- INFO("removing platform device %s\n", bus->name);
+ LOG(INFO) << "removing platform device " << bus->name;
free(bus->path);
list_remove(node);
free(bus);
@@ -411,16 +421,16 @@
}
if (LOG_UEVENTS) {
- INFO("event { '%s', '%s', '%s', '%s', %d, %d }\n",
- uevent->action, uevent->path, uevent->subsystem,
- uevent->firmware, uevent->major, uevent->minor);
+ LOG(INFO) << android::base::StringPrintf("event { '%s', '%s', '%s', '%s', %d, %d }",
+ uevent->action, uevent->path, uevent->subsystem,
+ uevent->firmware, uevent->major, uevent->minor);
}
}
static char **get_character_device_symlinks(struct uevent *uevent)
{
const char *parent;
- char *slash;
+ const char *slash;
char **links;
int link_num = 0;
int width;
@@ -474,7 +484,7 @@
{
const char *device;
struct platform_node *pdev;
- char *slash;
+ const char *slash;
const char *type;
char buf[256];
char link_path[256];
@@ -497,15 +507,16 @@
return NULL;
memset(links, 0, sizeof(char *) * 4);
- INFO("found %s device %s\n", type, device);
+ LOG(INFO) << "found " << type << " device " << device;
snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device);
if (uevent->partition_name) {
p = strdup(uevent->partition_name);
sanitize(p);
- if (strcmp(uevent->partition_name, p))
- NOTICE("Linking partition '%s' as '%s'\n", uevent->partition_name, p);
+ if (strcmp(uevent->partition_name, p)) {
+ LOG(VERBOSE) << "Linking partition '" << uevent->partition_name << "' as '" << p << "'";
+ }
if (asprintf(&links[link_num], "%s/by-name/%s", link_path, p) > 0)
link_num++;
else
@@ -583,8 +594,7 @@
/* too-long names would overrun our buffer */
if(strlen(name) > len) {
- ERROR("DEVPATH=%s exceeds %u-character limit on filename; ignoring event\n",
- name, len);
+ LOG(ERROR) << "DEVPATH=" << name << " exceeds " << len << "-character limit on filename; ignoring event";
return NULL;
}
@@ -619,12 +629,11 @@
{
int s = snprintf(devpath, DEVPATH_LEN, "%s/%s", dirname, devname);
if (s < 0) {
- ERROR("failed to assemble device path (%s); ignoring event\n",
- strerror(errno));
+ PLOG(ERROR) << "failed to assemble device path; ignoring event";
return false;
} else if (s >= DEVPATH_LEN) {
- ERROR("%s/%s exceeds %u-character limit on path; ignoring event\n",
- dirname, devname, DEVPATH_LEN);
+ LOG(ERROR) << dirname << "/" << devname
+ << " exceeds " << DEVPATH_LEN << "-character limit on path; ignoring event";
return false;
}
return true;
@@ -668,8 +677,7 @@
break;
default:
- ERROR("%s subsystem's devpath option is not set; ignoring event\n",
- uevent->subsystem);
+ LOG(ERROR) << uevent->subsystem << " subsystem's devpath option is not set; ignoring event";
return;
}
@@ -725,9 +733,8 @@
} else if(!strncmp(uevent->subsystem, "sound", 5)) {
base = "/dev/snd/";
make_dir(base, 0755);
- } else if(!strncmp(uevent->subsystem, "misc", 4) &&
- !strncmp(name, "log_", 4)) {
- INFO("kernel logger is deprecated\n");
+ } else if(!strncmp(uevent->subsystem, "misc", 4) && !strncmp(name, "log_", 4)) {
+ LOG(INFO) << "kernel logger is deprecated";
base = "/dev/log/";
make_dir(base, 0755);
name += 4;
@@ -745,7 +752,7 @@
static void handle_device_event(struct uevent *uevent)
{
if (!strcmp(uevent->action,"add") || !strcmp(uevent->action, "change") || !strcmp(uevent->action, "online"))
- fixup_sys_perms(uevent->path);
+ fixup_sys_perms(uevent->path, uevent->subsystem);
if (!strncmp(uevent->subsystem, "block", 5)) {
handle_block_device_event(uevent);
@@ -806,8 +813,7 @@
size_t i;
int booting = is_booting();
- INFO("firmware: loading '%s' for '%s'\n",
- uevent->firmware, uevent->path);
+ LOG(INFO) << "firmware: loading '" << uevent->firmware << "' for '" << uevent->path << "'";
l = asprintf(&root, SYSFS_PREFIX"%s/", uevent->path);
if (l == -1)
@@ -830,7 +836,7 @@
goto loading_close_out;
try_loading_again:
- for (i = 0; i < ARRAY_SIZE(firmware_dirs); i++) {
+ for (i = 0; i < arraysize(firmware_dirs); i++) {
char *file = NULL;
l = asprintf(&file, "%s/%s", firmware_dirs[i], uevent->firmware);
if (l == -1)
@@ -838,10 +844,11 @@
fw_fd = open(file, O_RDONLY|O_CLOEXEC);
free(file);
if (fw_fd >= 0) {
- if(!load_firmware(fw_fd, loading_fd, data_fd))
- INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware);
- else
- INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware);
+ if (!load_firmware(fw_fd, loading_fd, data_fd)) {
+ LOG(INFO) << "firmware: copy success { '" << root << "', '" << uevent->firmware << "' }";
+ } else {
+ LOG(ERROR) << "firmware: copy failure { '" << root << "', '" << uevent->firmware << "' }";
+ }
break;
}
}
@@ -854,7 +861,7 @@
booting = is_booting();
goto try_loading_again;
}
- INFO("firmware: could not open '%s': %s\n", uevent->firmware, strerror(errno));
+ PLOG(ERROR) << "firmware: could not open '" << uevent->firmware << "'";
write(loading_fd, "-1", 2);
goto data_close_out;
}
@@ -888,7 +895,7 @@
process_firmware_event(uevent);
_exit(EXIT_SUCCESS);
} else if (pid < 0) {
- ERROR("could not fork to process firmware event: %s\n", strerror(errno));
+ PLOG(ERROR) << "could not fork to process firmware event";
}
}
@@ -966,10 +973,9 @@
static void coldboot(const char *path)
{
- DIR *d = opendir(path);
+ std::unique_ptr<DIR, decltype(&closedir)> d(opendir(path), closedir);
if(d) {
- do_coldboot(d);
- closedir(d);
+ do_coldboot(d.get());
}
}
@@ -985,7 +991,7 @@
fcntl(device_fd, F_SETFL, O_NONBLOCK);
if (access(COLDBOOT_DONE, F_OK) == 0) {
- NOTICE("Skipping coldboot, already done!\n");
+ LOG(VERBOSE) << "Skipping coldboot, already done!";
return;
}
@@ -994,7 +1000,7 @@
coldboot("/sys/block");
coldboot("/sys/devices");
close(open(COLDBOOT_DONE, O_WRONLY|O_CREAT|O_CLOEXEC, 0000));
- NOTICE("Coldboot took %.2fs.\n", t.duration());
+ LOG(INFO) << "Coldboot took " << t.duration() << "s.";
}
int get_device_fd()
diff --git a/init/import_parser.cpp b/init/import_parser.cpp
index e2a0f83..d52247b 100644
--- a/init/import_parser.cpp
+++ b/init/import_parser.cpp
@@ -38,7 +38,7 @@
return false;
}
- INFO("Added '%s' to import list\n", conf_file.c_str());
+ LOG(INFO) << "Added '" << conf_file << "' to import list";
imports_.emplace_back(std::move(conf_file));
return true;
}
@@ -48,8 +48,7 @@
imports_.clear();
for (const auto& s : current_imports) {
if (!Parser::GetInstance().ParseConfig(s)) {
- ERROR("could not import file '%s' from '%s': %s\n",
- s.c_str(), filename.c_str(), strerror(errno));
+ PLOG(ERROR) << "could not import file '" << s << "' from '" << filename << "'";
}
}
}
diff --git a/init/init.cpp b/init/init.cpp
index 84da2b9..78d71a8 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -18,7 +18,6 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <fstream>
#include <libgen.h>
#include <paths.h>
#include <signal.h>
@@ -30,13 +29,12 @@
#include <sys/mount.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <mtd/mtd-user.h>
-
#include <selinux/selinux.h>
#include <selinux/label.h>
#include <selinux/android.h>
@@ -75,8 +73,7 @@
static char qemu[32];
-int have_console;
-std::string console_name = "/dev/console";
+std::string default_console = "/dev/console";
static time_t process_needs_restart;
const char *ENV[32];
@@ -90,7 +87,7 @@
ev.events = EPOLLIN;
ev.data.ptr = reinterpret_cast<void*>(fn);
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
- ERROR("epoll_ctl failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "epoll_ctl failed";
}
}
@@ -101,7 +98,7 @@
size_t key_len = strlen(key);
/* The last environment entry is reserved to terminate the list */
- for (n = 0; n < (ARRAY_SIZE(ENV) - 1); n++) {
+ for (n = 0; n < (arraysize(ENV) - 1); n++) {
/* Delete any existing entry for this key */
if (ENV[n] != NULL) {
@@ -121,7 +118,7 @@
}
}
- ERROR("No env. room to store: '%s':'%s'\n", key, val);
+ LOG(ERROR) << "No env. room to store: '" << key << "':'" << val << "'";
return -1;
}
@@ -144,7 +141,7 @@
void handle_control_message(const std::string& msg, const std::string& name) {
Service* svc = ServiceManager::GetInstance().FindServiceByName(name);
if (svc == nullptr) {
- ERROR("no such service '%s'\n", name.c_str());
+ LOG(ERROR) << "no such service '" << name << "'";
return;
}
@@ -155,22 +152,22 @@
} else if (msg == "restart") {
svc->Restart();
} else {
- ERROR("unknown control msg '%s'\n", msg.c_str());
+ LOG(ERROR) << "unknown control msg '" << msg << "'";
}
}
static int wait_for_coldboot_done_action(const std::vector<std::string>& args) {
Timer t;
- NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
+ LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE "...";
// Any longer than 1s is an unreasonable length of time to delay booting.
// If you're hitting this timeout, check that you didn't make your
// sepolicy regular expressions too expensive (http://b/19899875).
if (wait_for_file(COLDBOOT_DONE, 1)) {
- ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
+ LOG(ERROR) << "Timed out waiting for " COLDBOOT_DONE;
}
- NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration());
+ LOG(VERBOSE) << "Waiting for " COLDBOOT_DONE " took " << t.duration() << "s.";
return 0;
}
@@ -202,11 +199,11 @@
open("/dev/hw_random", O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
if (hwrandom_fd == -1) {
if (errno == ENOENT) {
- ERROR("/dev/hw_random not found\n");
- /* It's not an error to not have a Hardware RNG. */
- result = 0;
+ LOG(ERROR) << "/dev/hw_random not found";
+ // It's not an error to not have a Hardware RNG.
+ result = 0;
} else {
- ERROR("Failed to open /dev/hw_random: %s\n", strerror(errno));
+ PLOG(ERROR) << "Failed to open /dev/hw_random";
}
goto ret;
}
@@ -214,7 +211,7 @@
urandom_fd = TEMP_FAILURE_RETRY(
open("/dev/urandom", O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
if (urandom_fd == -1) {
- ERROR("Failed to open /dev/urandom: %s\n", strerror(errno));
+ PLOG(ERROR) << "Failed to open /dev/urandom";
goto ret;
}
@@ -222,23 +219,22 @@
chunk_size = TEMP_FAILURE_RETRY(
read(hwrandom_fd, buf, sizeof(buf) - total_bytes_written));
if (chunk_size == -1) {
- ERROR("Failed to read from /dev/hw_random: %s\n", strerror(errno));
+ PLOG(ERROR) << "Failed to read from /dev/hw_random";
goto ret;
} else if (chunk_size == 0) {
- ERROR("Failed to read from /dev/hw_random: EOF\n");
+ LOG(ERROR) << "Failed to read from /dev/hw_random: EOF";
goto ret;
}
chunk_size = TEMP_FAILURE_RETRY(write(urandom_fd, buf, chunk_size));
if (chunk_size == -1) {
- ERROR("Failed to write to /dev/urandom: %s\n", strerror(errno));
+ PLOG(ERROR) << "Failed to write to /dev/urandom";
goto ret;
}
total_bytes_written += chunk_size;
}
- INFO("Mixed %zu bytes from /dev/hw_random into /dev/urandom",
- total_bytes_written);
+ LOG(INFO) << "Mixed " << total_bytes_written << " bytes from /dev/hw_random into /dev/urandom";
result = 0;
ret:
@@ -251,100 +247,6 @@
return result;
}
-static void security_failure() {
- ERROR("Security failure; rebooting into recovery mode...\n");
- android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
- while (true) { pause(); } // never reached
-}
-
-#define MMAP_RND_PATH "/proc/sys/vm/mmap_rnd_bits"
-#define MMAP_RND_COMPAT_PATH "/proc/sys/vm/mmap_rnd_compat_bits"
-
-/* __attribute__((unused)) due to lack of mips support: see mips block
- * in set_mmap_rnd_bits_action */
-static bool __attribute__((unused)) set_mmap_rnd_bits_min(int start, int min, bool compat) {
- std::string path;
- if (compat) {
- path = MMAP_RND_COMPAT_PATH;
- } else {
- path = MMAP_RND_PATH;
- }
- std::ifstream inf(path, std::fstream::in);
- if (!inf) {
- return false;
- }
- while (start >= min) {
- // try to write out new value
- std::string str_val = std::to_string(start);
- std::ofstream of(path, std::fstream::out);
- if (!of) {
- return false;
- }
- of << str_val << std::endl;
- of.close();
-
- // check to make sure it was recorded
- inf.seekg(0);
- std::string str_rec;
- inf >> str_rec;
- if (str_val.compare(str_rec) == 0) {
- break;
- }
- start--;
- }
- inf.close();
- return (start >= min);
-}
-
-/*
- * Set /proc/sys/vm/mmap_rnd_bits and potentially
- * /proc/sys/vm/mmap_rnd_compat_bits to the maximum supported values.
- * Returns -1 if unable to set these to an acceptable value. Apply
- * upstream patch-sets https://lkml.org/lkml/2015/12/21/337 and
- * https://lkml.org/lkml/2016/2/4/831 to enable this.
- */
-static int set_mmap_rnd_bits_action(const std::vector<std::string>& args)
-{
- int ret = -1;
-
- /* values are arch-dependent */
-#if defined(__aarch64__)
- /* arm64 supports 18 - 33 bits depending on pagesize and VA_SIZE */
- if (set_mmap_rnd_bits_min(33, 24, false)
- && set_mmap_rnd_bits_min(16, 16, true)) {
- ret = 0;
- }
-#elif defined(__x86_64__)
- /* x86_64 supports 28 - 32 bits */
- if (set_mmap_rnd_bits_min(32, 32, false)
- && set_mmap_rnd_bits_min(16, 16, true)) {
- ret = 0;
- }
-#elif defined(__arm__) || defined(__i386__)
- /* check to see if we're running on 64-bit kernel */
- bool h64 = !access(MMAP_RND_COMPAT_PATH, F_OK);
- /* supported 32-bit architecture must have 16 bits set */
- if (set_mmap_rnd_bits_min(16, 16, h64)) {
- ret = 0;
- }
-#elif defined(__mips__) || defined(__mips64__)
- // TODO: add mips support b/27788820
- ret = 0;
-#else
- ERROR("Unknown architecture\n");
-#endif
-
-#ifdef __BRILLO__
- // TODO: b/27794137
- ret = 0;
-#endif
- if (ret == -1) {
- ERROR("Unable to set adequate mmap entropy value!\n");
- security_failure();
- }
- return ret;
-}
-
static int keychord_init_action(const std::vector<std::string>& args)
{
keychord_init();
@@ -355,36 +257,8 @@
{
std::string console = property_get("ro.boot.console");
if (!console.empty()) {
- console_name = "/dev/" + console;
+ default_console = "/dev/" + console;
}
-
- int fd = open(console_name.c_str(), O_RDWR | O_CLOEXEC);
- if (fd >= 0)
- have_console = 1;
- close(fd);
-
- fd = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
- if (fd >= 0) {
- const char *msg;
- msg = "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n" // console is 40 cols x 30 lines
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- " A N D R O I D ";
- write(fd, msg, strlen(msg));
- close(fd);
- }
-
return 0;
}
@@ -430,7 +304,7 @@
{ "ro.boot.hardware", "ro.hardware", "unknown", },
{ "ro.boot.revision", "ro.revision", "0", },
};
- for (size_t i = 0; i < ARRAY_SIZE(prop_map); i++) {
+ for (size_t i = 0; i < arraysize(prop_map); i++) {
std::string value = property_get(prop_map[i].src_prop);
property_set(prop_map[i].dst_prop, (!value.empty()) ? value.c_str() : prop_map[i].default_value);
}
@@ -444,7 +318,7 @@
std::string dt_file;
android::base::ReadFileToString(file_name, &dt_file);
if (!dt_file.compare("android,firmware")) {
- ERROR("firmware/android is not compatible with 'android,firmware'\n");
+ LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
return;
}
@@ -515,30 +389,12 @@
return true;
}
-int selinux_reload_policy(void)
-{
- INFO("SELinux: Attempting to reload policy files\n");
-
- if (selinux_android_reload_policy() == -1) {
- return -1;
- }
-
- if (sehandle)
- selabel_close(sehandle);
-
- if (sehandle_prop)
- selabel_close(sehandle_prop);
-
- selinux_init_all_handles();
- return 0;
-}
-
static int audit_callback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
property_audit_data *d = reinterpret_cast<property_audit_data*>(data);
if (!d || !d->name || !d->cr) {
- ERROR("audit_callback invoked with null data arguments!");
+ LOG(ERROR) << "audit_callback invoked with null data arguments!";
return 0;
}
@@ -547,6 +403,12 @@
return 0;
}
+static void security_failure() {
+ LOG(ERROR) << "Security failure; rebooting into recovery mode...";
+ android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+ while (true) { pause(); } // never reached
+}
+
static void selinux_initialize(bool in_kernel_domain) {
Timer t;
@@ -557,9 +419,9 @@
selinux_set_callback(SELINUX_CB_AUDIT, cb);
if (in_kernel_domain) {
- INFO("Loading SELinux policy...\n");
+ LOG(INFO) << "Loading SELinux policy...";
if (selinux_android_load_policy() < 0) {
- ERROR("failed to load policy: %s\n", strerror(errno));
+ PLOG(ERROR) << "failed to load policy";
security_failure();
}
@@ -567,8 +429,7 @@
bool is_enforcing = selinux_is_enforcing();
if (kernel_enforcing != is_enforcing) {
if (security_setenforce(is_enforcing)) {
- ERROR("security_setenforce(%s) failed: %s\n",
- is_enforcing ? "true" : "false", strerror(errno));
+ PLOG(ERROR) << "security_setenforce(%s) failed" << (is_enforcing ? "true" : "false");
security_failure();
}
}
@@ -577,13 +438,29 @@
security_failure();
}
- NOTICE("(Initializing SELinux %s took %.2fs.)\n",
- is_enforcing ? "enforcing" : "non-enforcing", t.duration());
+ LOG(INFO) << "(Initializing SELinux " << (is_enforcing ? "enforcing" : "non-enforcing")
+ << " took " << t.duration() << "s.)";
} else {
selinux_init_all_handles();
}
}
+// Set the UDC controller for the ConfigFS USB Gadgets.
+// Read the UDC controller in use from "/sys/class/udc".
+// In case of multiple UDC controllers select the first one.
+static void set_usb_controller() {
+ std::unique_ptr<DIR, decltype(&closedir)>dir(opendir("/sys/class/udc"), closedir);
+ if (!dir) return;
+
+ dirent* dp;
+ while ((dp = readdir(dir.get())) != nullptr) {
+ if (dp->d_name[0] == '.') continue;
+
+ property_set("sys.usb.controller", dp->d_name);
+ break;
+ }
+}
+
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
@@ -610,17 +487,15 @@
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
mount("sysfs", "/sys", "sysfs", 0, NULL);
+ mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
+ mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
}
- // We must have some place other than / to create the device nodes for
- // kmsg and null, otherwise we won't be able to remount / read-only
- // later on. Now that tmpfs is mounted on /dev, we can actually talk
- // to the outside world.
- open_devnull_stdio();
- klog_init();
- klog_set_level(KLOG_NOTICE_LEVEL);
+ // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
+ // talk to the outside world...
+ InitKernelLogging(argv);
- NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
+ LOG(INFO) << "init " << (is_first_stage ? "first stage" : "second stage") << " started!";
if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
@@ -645,13 +520,13 @@
// that the SELinux policy has been loaded.
if (is_first_stage) {
if (restorecon("/init") == -1) {
- ERROR("restorecon failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "restorecon failed";
security_failure();
}
char* path = argv[0];
char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
if (execv(path, args) == -1) {
- ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
+ PLOG(ERROR) << "execv(\"" << path << "\") failed";
security_failure();
}
}
@@ -659,8 +534,9 @@
// These directories were necessarily created before initial policy load
// and therefore need their security context restored to the proper value.
// This must happen before /dev is populated by ueventd.
- NOTICE("Running restorecon...\n");
+ LOG(INFO) << "Running restorecon...";
restorecon("/dev");
+ restorecon("/dev/kmsg");
restorecon("/dev/socket");
restorecon("/dev/__properties__");
restorecon("/property_contexts");
@@ -668,7 +544,7 @@
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
- ERROR("epoll_create1 failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "epoll_create1 failed";
exit(1);
}
@@ -677,6 +553,7 @@
property_load_boot_defaults();
export_oem_lock_status();
start_property_service();
+ set_usb_controller();
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
@@ -695,7 +572,6 @@
am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
// ... so that we can start queuing up actions that require stuff from /dev.
am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
- am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
am.QueueBuiltinAction(keychord_init_action, "keychord_init");
am.QueueBuiltinAction(console_init_action, "console_init");
@@ -739,7 +615,7 @@
epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
if (nr == -1) {
- ERROR("epoll_wait failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
diff --git a/init/init.h b/init/init.h
index 345d442..0019337 100644
--- a/init/init.h
+++ b/init/init.h
@@ -26,8 +26,7 @@
extern const char *ENV[32];
extern bool waiting_for_exec;
-extern int have_console;
-extern std::string console_name;
+extern std::string default_console;
extern struct selabel_handle *sehandle;
extern struct selabel_handle *sehandle_prop;
@@ -35,8 +34,6 @@
void property_changed(const char *name, const char *value);
-int selinux_reload_policy(void);
-
void register_epoll_handler(int fd, void (*fn)());
int add_environment(const char* key, const char* val);
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index b44ca59..9ec26af 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -93,7 +93,7 @@
}
bool Parser::ParseConfigFile(const std::string& path) {
- INFO("Parsing file %s...\n", path.c_str());
+ LOG(INFO) << "Parsing file " << path << "...";
Timer t;
std::string data;
if (!read_file(path.c_str(), &data)) {
@@ -110,15 +110,15 @@
// Nexus 9 boot time, so it's disabled by default.
if (false) DumpState();
- NOTICE("(Parsing %s took %.2fs.)\n", path.c_str(), t.duration());
+ LOG(VERBOSE) << "(Parsing " << path << " took " << t.duration() << "s.)";
return true;
}
bool Parser::ParseConfigDir(const std::string& path) {
- INFO("Parsing directory %s...\n", path.c_str());
+ LOG(INFO) << "Parsing directory " << path << "...";
std::unique_ptr<DIR, int(*)(DIR*)> config_dir(opendir(path.c_str()), closedir);
if (!config_dir) {
- ERROR("Could not import directory '%s'\n", path.c_str());
+ PLOG(ERROR) << "Could not import directory '" << path << "'";
return false;
}
dirent* current_file;
@@ -128,7 +128,7 @@
// Ignore directories and only process regular files.
if (current_file->d_type == DT_REG) {
if (!ParseConfigFile(current_path)) {
- ERROR("could not import file '%s'\n", current_path.c_str());
+ LOG(ERROR) << "could not import file '" << current_path << "'";
}
}
}
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 1468c57..3dbb2f0 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -43,7 +43,7 @@
size = sizeof(*keychord) + svc->keycodes().size() * sizeof(keychord->keycodes[0]);
keychords = (input_keychord*) realloc(keychords, keychords_length + size);
if (!keychords) {
- ERROR("could not allocate keychords\n");
+ PLOG(ERROR) << "could not allocate keychords";
keychords_length = 0;
keychords_count = 0;
return;
@@ -69,7 +69,7 @@
ret = read(keychord_fd, &id, sizeof(id));
if (ret != sizeof(id)) {
- ERROR("could not read keychord id\n");
+ PLOG(ERROR) << "could not read keychord id";
return;
}
@@ -78,13 +78,13 @@
if (adb_enabled == "running") {
Service* svc = ServiceManager::GetInstance().FindServiceByKeychord(id);
if (svc) {
- NOTICE("Starting service '%s' from keychord %d\n", svc->name().c_str(), id);
+ LOG(INFO) << "Starting service " << svc->name() << " from keychord " << id;
svc->Start();
} else {
- ERROR("Service for keychord %d not found\n", id);
+ LOG(ERROR) << "Service for keychord " << id << " not found";
}
} else {
- WARNING("Not starting service for keychord %d because ADB is disabled\n", id);
+ LOG(WARNING) << "Not starting service for keychord " << id << " because ADB is disabled";
}
}
@@ -98,13 +98,13 @@
keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
if (keychord_fd == -1) {
- ERROR("could not open /dev/keychord: %s\n", strerror(errno));
+ PLOG(ERROR) << "could not open /dev/keychord";
return;
}
int ret = write(keychord_fd, keychords, keychords_length);
if (ret != keychords_length) {
- ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
+ PLOG(ERROR) << "could not configure /dev/keychord " << ret;
close(keychord_fd);
}
diff --git a/init/log.cpp b/init/log.cpp
index ace9fd7..379141a 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -16,54 +16,77 @@
#include "log.h"
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/uio.h>
#include <selinux/selinux.h>
-#include <android-base/stringprintf.h>
+static const int kLogSeverityToKLogLevel[] = {
+ [android::base::VERBOSE] = KLOG_DEBUG_LEVEL,
+ [android::base::DEBUG] = KLOG_DEBUG_LEVEL,
+ [android::base::INFO] = KLOG_INFO_LEVEL,
+ [android::base::WARNING] = KLOG_WARNING_LEVEL,
+ [android::base::ERROR] = KLOG_ERROR_LEVEL,
+ [android::base::FATAL] = KLOG_ERROR_LEVEL,
+};
+static_assert(arraysize(kLogSeverityToKLogLevel) == android::base::FATAL + 1,
+ "Mismatch in size of kLogSeverityToKLogLevel and values in LogSeverity");
-static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
- static const char* tag = basename(getprogname());
-
+static void KernelLogger(android::base::LogId, android::base::LogSeverity severity,
+ const char* tag, const char*, unsigned int, const char* msg) {
+ int level = kLogSeverityToKLogLevel[severity];
if (level > klog_get_level()) return;
// The kernel's printk buffer is only 1024 bytes.
// TODO: should we automatically break up long lines into multiple lines?
// Or we could log but with something like "..." at the end?
char buf[1024];
- size_t prefix_size = snprintf(buf, sizeof(buf), "<%d>%s: ", level, tag);
- size_t msg_size = vsnprintf(buf + prefix_size, sizeof(buf) - prefix_size, fmt, ap);
- if (msg_size >= sizeof(buf) - prefix_size) {
- msg_size = snprintf(buf + prefix_size, sizeof(buf) - prefix_size,
- "(%zu-byte message too long for printk)\n", msg_size);
+ size_t size = snprintf(buf, sizeof(buf), "<%d>%s: %s\n", level, tag, msg);
+ if (size > sizeof(buf)) {
+ size = snprintf(buf, sizeof(buf), "<%d>%s: %zu-byte message too long for printk\n",
+ level, tag, size);
}
iovec iov[1];
iov[0].iov_base = buf;
- iov[0].iov_len = prefix_size + msg_size;
-
+ iov[0].iov_len = size;
klog_writev(level, iov, 1);
}
-void init_klog_write(int level, const char* fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- init_klog_vwrite(level, fmt, ap);
- va_end(ap);
+void InitKernelLogging(char* argv[]) {
+ // Make stdin/stdout/stderr all point to /dev/null.
+ int fd = open("/sys/fs/selinux/null", O_RDWR);
+ if (fd == -1) {
+ int saved_errno = errno;
+ android::base::InitLogging(argv, &KernelLogger);
+ errno = saved_errno;
+ PLOG(FATAL) << "Couldn't open /sys/fs/selinux/null";
+ }
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ if (fd > 2) close(fd);
+
+ android::base::InitLogging(argv, &KernelLogger);
+ klog_set_level(KLOG_INFO_LEVEL);
}
int selinux_klog_callback(int type, const char *fmt, ...) {
- int level = KLOG_ERROR_LEVEL;
+ android::base::LogSeverity severity = android::base::ERROR;
if (type == SELINUX_WARNING) {
- level = KLOG_WARNING_LEVEL;
+ severity = android::base::WARNING;
} else if (type == SELINUX_INFO) {
- level = KLOG_INFO_LEVEL;
+ severity = android::base::INFO;
}
+ char buf[1024];
va_list ap;
va_start(ap, fmt);
- init_klog_vwrite(level, fmt, ap);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
+ KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
return 0;
}
diff --git a/init/log.h b/init/log.h
index c5c30af..cf552a1 100644
--- a/init/log.h
+++ b/init/log.h
@@ -17,16 +17,12 @@
#ifndef _INIT_LOG_H_
#define _INIT_LOG_H_
+#include <android-base/logging.h>
+
#include <cutils/klog.h>
-#define ERROR(x...) init_klog_write(KLOG_ERROR_LEVEL, x)
-#define WARNING(x...) init_klog_write(KLOG_WARNING_LEVEL, x)
-#define NOTICE(x...) init_klog_write(KLOG_NOTICE_LEVEL, x)
-#define INFO(x...) init_klog_write(KLOG_INFO_LEVEL, x)
-#define DEBUG(x...) init_klog_write(KLOG_DEBUG_LEVEL, x)
-#define VERBOSE(x...) init_klog_write(KLOG_DEBUG_LEVEL, x)
+void InitKernelLogging(char* argv[]);
-void init_klog_write(int level, const char* fmt, ...) __printflike(2, 3);
int selinux_klog_callback(int level, const char* fmt, ...) __printflike(2, 3);
#endif
diff --git a/init/parser.cpp b/init/parser.cpp
index 8193729..45862b7 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -12,7 +12,7 @@
char buf[128];
int off;
- snprintf(buf, 128, "%s: %d: ", state->filename, state->line);
+ snprintf(buf, sizeof(buf), "%s: %d: ", state->filename, state->line);
buf[127] = 0;
off = strlen(buf);
@@ -20,7 +20,7 @@
vsnprintf(buf + off, 128 - off, fmt, ap);
va_end(ap);
buf[127] = 0;
- ERROR("%s", buf);
+ LOG(ERROR) << buf;
}
int next_token(struct parse_state *state)
diff --git a/init/parser/tokenizer.h b/init/parser/tokenizer.h
index 8312a08..ade8f73 100644
--- a/init/parser/tokenizer.h
+++ b/init/parser/tokenizer.h
@@ -36,7 +36,7 @@
// a TOK_NEWLINE will not be generated for that line.
class Tokenizer {
public:
- Tokenizer(const std::string& data);
+ explicit Tokenizer(const std::string& data);
~Tokenizer();
enum TokenType { TOK_START, TOK_END, TOK_NEWLINE, TOK_TEXT };
diff --git a/init/perfboot.py b/init/perfboot.py
index 91e6c2b..713290b 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -191,9 +191,9 @@
def init_perf(device, output, record_list, tags):
device.wait()
- build_type = device.get_prop('ro.build.type')
+ debuggable = device.get_prop('ro.debuggable')
original_dropbox_max_files = None
- if build_type != 'user':
+ if debuggable == '1':
# Workaround for Dropbox issue (http://b/20890386).
original_dropbox_max_files = disable_dropbox(device)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 5c1ae79..e2e1b16 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -41,7 +41,6 @@
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/mman.h>
-#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
@@ -65,7 +64,7 @@
void property_init() {
if (__system_property_area_init()) {
- ERROR("Failed to initialize property area\n");
+ LOG(ERROR) << "Failed to initialize property area";
exit(1);
}
}
@@ -128,7 +127,7 @@
snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
fd = mkstemp(tempPath);
if (fd < 0) {
- ERROR("Unable to write persistent property to temp file %s: %s\n", tempPath, strerror(errno));
+ PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath;
return;
}
write(fd, value, strlen(value));
@@ -137,8 +136,8 @@
snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
if (rename(tempPath, path)) {
+ PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path;
unlink(tempPath);
- ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);
}
}
@@ -175,13 +174,9 @@
if (!is_legal_property_name(name, namelen)) return -1;
if (valuelen >= PROP_VALUE_MAX) return -1;
- if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {
- if (selinux_reload_policy() != 0) {
- ERROR("Failed to reload policy\n");
- }
- } else if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
+ if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
if (restorecon_recursive(value) != 0) {
- ERROR("Failed to restorecon_recursive %s\n", value);
+ LOG(ERROR) << "Failed to restorecon_recursive " << value;
}
}
@@ -224,7 +219,7 @@
int property_set(const char* name, const char* value) {
int rc = property_set_impl(name, value);
if (rc == -1) {
- ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);
+ LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed";
}
return rc;
}
@@ -250,7 +245,7 @@
/* Check socket options here */
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
close(s);
- ERROR("Unable to receive socket options\n");
+ PLOG(ERROR) << "Unable to receive socket options";
return;
}
@@ -259,19 +254,18 @@
ufds[0].revents = 0;
nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
if (nr == 0) {
- ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
+ LOG(ERROR) << "sys_prop: timeout waiting for uid " << cr.uid << " to send property message.";
close(s);
return;
} else if (nr < 0) {
- ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));
+ PLOG(ERROR) << "sys_prop: error waiting for uid " << cr.uid << " to send property message";
close(s);
return;
}
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
if(r != sizeof(prop_msg)) {
- ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",
- r, sizeof(prop_msg), strerror(errno));
+ PLOG(ERROR) << "sys_prop: mis-match msg size received: " << r << " expected: " << sizeof(prop_msg);
close(s);
return;
}
@@ -282,7 +276,7 @@
msg.value[PROP_VALUE_MAX-1] = 0;
if (!is_legal_property_name(msg.name, strlen(msg.name))) {
- ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
+ LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
close(s);
return;
}
@@ -296,15 +290,17 @@
if (check_control_mac_perms(msg.value, source_ctx, &cr)) {
handle_control_message((char*) msg.name + 4, (char*) msg.value);
} else {
- ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
- msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
+ LOG(ERROR) << "sys_prop: Unable to " << (msg.name + 4)
+ << " service ctl [" << msg.value << "]"
+ << " uid:" << cr.uid
+ << " gid:" << cr.gid
+ << " pid:" << cr.pid;
}
} else {
if (check_mac_perms(msg.name, source_ctx, &cr)) {
property_set((char*) msg.name, (char*) msg.value);
} else {
- ERROR("sys_prop: permission denied uid:%d name:%s\n",
- cr.uid, msg.name);
+ LOG(ERROR) << "sys_prop: permission denied uid:" << cr.uid << " name:" << msg.name;
}
// Note: bionic's property client code assumes that the
@@ -394,7 +390,7 @@
data.push_back('\n');
load_properties(&data[0], filter);
}
- NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
+ LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t.duration() << "s.)";
}
static void load_persistent_properties() {
@@ -402,8 +398,8 @@
std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(PERSISTENT_PROPERTY_DIR), closedir);
if (!dir) {
- ERROR("Unable to open persistent property directory \"%s\": %s\n",
- PERSISTENT_PROPERTY_DIR, strerror(errno));
+ PLOG(ERROR) << "Unable to open persistent property directory \""
+ << PERSISTENT_PROPERTY_DIR << "\"";
return;
}
@@ -419,25 +415,23 @@
// Open the file and read the property value.
int fd = openat(dirfd(dir.get()), entry->d_name, O_RDONLY | O_NOFOLLOW);
if (fd == -1) {
- ERROR("Unable to open persistent property file \"%s\": %s\n",
- entry->d_name, strerror(errno));
+ PLOG(ERROR) << "Unable to open persistent property file \"" << entry->d_name << "\"";
continue;
}
struct stat sb;
if (fstat(fd, &sb) == -1) {
- ERROR("fstat on property file \"%s\" failed: %s\n", entry->d_name, strerror(errno));
+ PLOG(ERROR) << "fstat on property file \"" << entry->d_name << "\" failed";
close(fd);
continue;
}
// File must not be accessible to others, be owned by root/root, and
// not be a hard link to any other file.
- if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || (sb.st_uid != 0) || (sb.st_gid != 0) ||
- (sb.st_nlink != 1)) {
- ERROR("skipping insecure property file %s (uid=%u gid=%u nlink=%u mode=%o)\n",
- entry->d_name, (unsigned int)sb.st_uid, (unsigned int)sb.st_gid,
- (unsigned int)sb.st_nlink, sb.st_mode);
+ if (((sb.st_mode & (S_IRWXG | S_IRWXO)) != 0) || sb.st_uid != 0 || sb.st_gid != 0 || sb.st_nlink != 1) {
+ PLOG(ERROR) << "skipping insecure property file " << entry->d_name
+ << " (uid=" << sb.st_uid << " gid=" << sb.st_gid
+ << " nlink=" << sb.st_nlink << " mode=" << std::oct << sb.st_mode << ")";
close(fd);
continue;
}
@@ -448,8 +442,7 @@
value[length] = 0;
property_set(entry->d_name, value);
} else {
- ERROR("Unable to read persistent property file %s: %s\n",
- entry->d_name, strerror(errno));
+ PLOG(ERROR) << "Unable to read persistent property file " << entry->d_name;
}
close(fd);
}
@@ -482,27 +475,27 @@
void load_recovery_id_prop() {
std::string ro_hardware = property_get("ro.hardware");
if (ro_hardware.empty()) {
- ERROR("ro.hardware not set - unable to load recovery id\n");
+ LOG(ERROR) << "ro.hardware not set - unable to load recovery id";
return;
}
std::string fstab_filename = FSTAB_PREFIX + ro_hardware;
std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename.c_str()),
- fs_mgr_free_fstab);
+ fs_mgr_free_fstab);
if (!tab) {
- ERROR("unable to read fstab %s: %s\n", fstab_filename.c_str(), strerror(errno));
+ PLOG(ERROR) << "unable to read fstab " << fstab_filename;
return;
}
fstab_rec* rec = fs_mgr_get_entry_for_mount_point(tab.get(), RECOVERY_MOUNT_POINT);
if (rec == NULL) {
- ERROR("/recovery not specified in fstab\n");
+ LOG(ERROR) << "/recovery not specified in fstab";
return;
}
int fd = open(rec->blk_device, O_RDONLY);
if (fd == -1) {
- ERROR("error opening block device %s: %s\n", rec->blk_device, strerror(errno));
+ PLOG(ERROR) << "error opening block device " << rec->blk_device;
return;
}
@@ -511,7 +504,7 @@
std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
property_set("ro.recovery_id", hex.c_str());
} else {
- ERROR("error reading /recovery: %s\n", strerror(errno));
+ PLOG(ERROR) << "error reading /recovery";
}
close(fd);
@@ -528,7 +521,7 @@
property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
0666, 0, 0, NULL);
if (property_set_fd == -1) {
- ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "start_property_service socket creation failed";
exit(1);
}
diff --git a/init/readme.txt b/init/readme.txt
index 4481e24..cde4055 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -115,6 +115,13 @@
Options are modifiers to services. They affect how and when init
runs the service.
+console [<console>]
+ This service needs a console. The optional second parameter chooses a
+ specific console instead of the default. The default "/dev/console" can
+ be changed by setting the "androidboot.console" kernel parameter. In
+ all cases the leading "/dev/" should be omitted, so "/dev/tty0" would be
+ specified as just "console tty0".
+
critical
This is a device-critical service. If it exits more than four times in
four minutes, the device will reboot into recovery mode.
@@ -177,6 +184,9 @@
Write the child's pid to the given files when it forks. Meant for
cgroup/cpuset usage.
+priority <priority>
+ Scheduling priority of the service process. This value has to be in range
+ -20 to 19. Default priority is 0. Priority is set via setpriority().
Triggers
--------
@@ -271,8 +281,11 @@
ifup <interface>
Bring the network interface <interface> online.
-insmod <path>
- Install the module at <path>
+insmod [-f] <path> [<options>]
+ Install the module at <path> with the specified options.
+ -f
+ Force installation of the module even if the version of the running kernel
+ and the version of the kernel for which the module was compiled do not match.
load_all_props
Loads properties from /system, /vendor, et cetera.
@@ -298,8 +311,6 @@
mount <type> <device> <dir> [ <flag> ]* [<options>]
Attempt to mount the named device at the directory <dir>
- <device> may be of the form mtd@name to specify a mtd block
- device by name.
<flag>s include "ro", "rw", "remount", "noatime", ...
<options> include "barrier=1", "noauto_da_alloc", "discard", ... as
a comma separated string, eg: barrier=1,noauto_da_alloc
@@ -507,5 +518,5 @@
emulator -partition-size 1024 -verbose -show-kernel -no-window
-You might want to call klog_set_level(6) after the klog_init() call
-so you see the kernel logging in dmesg (or the emulator output).
+You might want to change the klog_set_level call so you see all the kernel
+logging in dmesg (or the emulator output).
diff --git a/init/service.cpp b/init/service.cpp
index 3149f8e..32aafd6 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,7 +17,12 @@
#include "service.h"
#include <fcntl.h>
+#include <sched.h>
+#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
@@ -27,8 +32,12 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <cutils/android_reboot.h>
#include <cutils/sockets.h>
+#include <system/thread_defs.h>
+
+#include <processgroup/processgroup.h>
#include "action.h"
#include "init.h"
@@ -43,6 +52,96 @@
#define CRITICAL_CRASH_THRESHOLD 4 // if we crash >4 times ...
#define CRITICAL_CRASH_WINDOW (4*60) // ... in 4 minutes, goto recovery
+static std::string ComputeContextFromExecutable(std::string& service_name,
+ const std::string& service_path) {
+ std::string computed_context;
+
+ char* raw_con = nullptr;
+ char* raw_filecon = nullptr;
+
+ if (getcon(&raw_con) == -1) {
+ LOG(ERROR) << "could not get context while starting '" << service_name << "'";
+ return "";
+ }
+ std::unique_ptr<char> mycon(raw_con);
+
+ if (getfilecon(service_path.c_str(), &raw_filecon) == -1) {
+ LOG(ERROR) << "could not get file context while starting '" << service_name << "'";
+ return "";
+ }
+ std::unique_ptr<char> filecon(raw_filecon);
+
+ char* new_con = nullptr;
+ int rc = security_compute_create(mycon.get(), filecon.get(),
+ string_to_security_class("process"), &new_con);
+ if (rc == 0) {
+ computed_context = new_con;
+ free(new_con);
+ }
+ if (rc == 0 && computed_context == mycon.get()) {
+ LOG(ERROR) << "service " << service_name << " does not have a SELinux domain defined";
+ return "";
+ }
+ if (rc < 0) {
+ LOG(ERROR) << "could not get context while starting '" << service_name << "'";
+ return "";
+ }
+ return computed_context;
+}
+
+static void SetUpPidNamespace(const std::string& service_name) {
+ constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID;
+
+ // It's OK to LOG(FATAL) in this function since it's running in the first
+ // child process.
+ if (mount("", "/proc", "proc", kSafeFlags | MS_REMOUNT, "") == -1) {
+ PLOG(FATAL) << "couldn't remount(/proc) for " << service_name;
+ }
+
+ if (prctl(PR_SET_NAME, service_name.c_str()) == -1) {
+ PLOG(FATAL) << "couldn't set name for " << service_name;
+ }
+
+ pid_t child_pid = fork();
+ if (child_pid == -1) {
+ PLOG(FATAL) << "couldn't fork init inside the PID namespace for " << service_name;
+ }
+
+ if (child_pid > 0) {
+ // So that we exit with the right status.
+ static int init_exitstatus = 0;
+ signal(SIGTERM, [](int) { _exit(init_exitstatus); });
+
+ pid_t waited_pid;
+ int status;
+ while ((waited_pid = wait(&status)) > 0) {
+ // This loop will end when there are no processes left inside the
+ // PID namespace or when the init process inside the PID namespace
+ // gets a signal.
+ if (waited_pid == child_pid) {
+ init_exitstatus = status;
+ }
+ }
+ if (!WIFEXITED(init_exitstatus)) {
+ _exit(EXIT_FAILURE);
+ }
+ _exit(WEXITSTATUS(init_exitstatus));
+ }
+}
+
+static void ExpandArgs(const std::vector<std::string>& args, std::vector<char*>* strs) {
+ std::vector<std::string> expanded_args;
+ expanded_args.resize(args.size());
+ strs->push_back(const_cast<char*>(args[0].c_str()));
+ for (std::size_t i = 1; i < args.size(); ++i) {
+ if (!expand_props(args[i], &expanded_args[i])) {
+ LOG(FATAL) << args[0] << ": cannot expand '" << args[i] << "'";
+ }
+ strs->push_back(const_cast<char*>(expanded_args[i].c_str()));
+ }
+ strs->push_back(nullptr);
+}
+
SocketInfo::SocketInfo() : uid(0), gid(0), perm(0) {
}
@@ -62,17 +161,22 @@
Service::Service(const std::string& name, const std::string& classname,
const std::vector<std::string>& args)
: name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
- time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), seclabel_(""),
- ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+ time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), namespace_flags_(0),
+ seclabel_(""), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
+ priority_(0), args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
Service::Service(const std::string& name, const std::string& classname,
- unsigned flags, uid_t uid, gid_t gid, const std::vector<gid_t>& supp_gids,
- const std::string& seclabel, const std::vector<std::string>& args)
- : name_(name), classname_(classname), flags_(flags), pid_(0), time_started_(0),
- time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid), supp_gids_(supp_gids),
- seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+ unsigned flags, uid_t uid, gid_t gid,
+ const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+ const std::string& seclabel,
+ const std::vector<std::string>& args)
+ : name_(name), classname_(classname), flags_(flags), pid_(0),
+ time_started_(0), time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid),
+ supp_gids_(supp_gids), namespace_flags_(namespace_flags),
+ seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0),
+ priority_(0), args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -85,19 +189,73 @@
std::string prop_name = StringPrintf("init.svc.%s", name_.c_str());
if (prop_name.length() >= PROP_NAME_MAX) {
// If the property name would be too long, we can't set it.
- ERROR("Property name \"init.svc.%s\" too long; not setting to %s\n",
- name_.c_str(), new_state.c_str());
+ LOG(ERROR) << "Property name \"init.svc." << name_ << "\" too long; not setting to " << new_state;
return;
}
property_set(prop_name.c_str(), new_state.c_str());
}
+void Service::KillProcessGroup(int signal) {
+ LOG(INFO) << "Sending signal " << signal
+ << " to service '" << name_
+ << "' (pid " << pid_ << ") process group...";
+ if (killProcessGroup(uid_, pid_, signal) == -1) {
+ PLOG(ERROR) << "killProcessGroup(" << uid_ << ", " << pid_ << ", " << signal << ") failed";
+ }
+ if (kill(-pid_, signal) == -1) {
+ PLOG(ERROR) << "kill(" << pid_ << ", " << signal << ") failed";
+ }
+}
+
+void Service::CreateSockets(const std::string& context) {
+ for (const auto& si : sockets_) {
+ int socket_type = ((si.type == "stream" ? SOCK_STREAM :
+ (si.type == "dgram" ? SOCK_DGRAM :
+ SOCK_SEQPACKET)));
+ const char* socketcon = !si.socketcon.empty() ? si.socketcon.c_str() : context.c_str();
+
+ int s = create_socket(si.name.c_str(), socket_type, si.perm, si.uid, si.gid, socketcon);
+ if (s >= 0) {
+ PublishSocket(si.name, s);
+ }
+ }
+}
+
+void Service::SetProcessAttributes() {
+ // TODO: work out why this fails for `console` then upgrade to FATAL.
+ if (setpgid(0, getpid()) == -1) PLOG(ERROR) << "setpgid failed for " << name_;
+
+ if (gid_) {
+ if (setgid(gid_) != 0) {
+ PLOG(FATAL) << "setgid failed for " << name_;
+ }
+ }
+ if (!supp_gids_.empty()) {
+ if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
+ PLOG(FATAL) << "setgroups failed for " << name_;
+ }
+ }
+ if (uid_) {
+ if (setuid(uid_) != 0) {
+ PLOG(FATAL) << "setuid failed for " << name_;
+ }
+ }
+ if (!seclabel_.empty()) {
+ if (setexeccon(seclabel_.c_str()) < 0) {
+ PLOG(FATAL) << "cannot setexeccon('" << seclabel_ << "') for " << name_;
+ }
+ }
+ if (priority_ != 0) {
+ if (setpriority(PRIO_PROCESS, 0, priority_) != 0) {
+ PLOG(FATAL) << "setpriority failed for " << name_;
+ }
+ }
+}
+
bool Service::Reap() {
if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
- NOTICE("Service '%s' (pid %d) killing any children in process group\n",
- name_.c_str(), pid_);
- kill(-pid_, SIGKILL);
+ KillProcessGroup(SIGKILL);
}
// Remove any sockets we may have created.
@@ -107,7 +265,7 @@
}
if (flags_ & SVC_EXEC) {
- INFO("SVC_EXEC pid %d finished...\n", pid_);
+ LOG(INFO) << "SVC_EXEC pid " << pid_ << " finished...";
return true;
}
@@ -130,9 +288,10 @@
if ((flags_ & SVC_CRITICAL) && !(flags_ & SVC_RESTART)) {
if (time_crashed_ + CRITICAL_CRASH_WINDOW >= now) {
if (++nr_crashed_ > CRITICAL_CRASH_THRESHOLD) {
- ERROR("critical process '%s' exited %d times in %d minutes; "
- "rebooting into recovery mode\n", name_.c_str(),
- CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
+ LOG(ERROR) << "critical process '" << name_ << "' exited "
+ << CRITICAL_CRASH_THRESHOLD << " times in "
+ << (CRITICAL_CRASH_WINDOW / 60) << " minutes; "
+ << "rebooting into recovery mode";
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
return false;
}
@@ -153,40 +312,37 @@
}
void Service::DumpState() const {
- INFO("service %s\n", name_.c_str());
- INFO(" class '%s'\n", classname_.c_str());
- INFO(" exec");
- for (const auto& s : args_) {
- INFO(" '%s'", s.c_str());
- }
- INFO("\n");
+ LOG(INFO) << "service " << name_;
+ LOG(INFO) << " class '" << classname_ << "'";
+ LOG(INFO) << " exec "<< android::base::Join(args_, " ");
for (const auto& si : sockets_) {
- INFO(" socket %s %s 0%o\n", si.name.c_str(), si.type.c_str(), si.perm);
+ LOG(INFO) << " socket " << si.name << " " << si.type << " " << std::oct << si.perm;
}
}
-bool Service::HandleClass(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseClass(const std::vector<std::string>& args, std::string* err) {
classname_ = args[1];
return true;
}
-bool Service::HandleConsole(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseConsole(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_CONSOLE;
+ console_ = args.size() > 1 ? "/dev/" + args[1] : "";
return true;
}
-bool Service::HandleCritical(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseCritical(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_CRITICAL;
return true;
}
-bool Service::HandleDisabled(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseDisabled(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_DISABLED;
flags_ |= SVC_RC_DISABLED;
return true;
}
-bool Service::HandleGroup(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseGroup(const std::vector<std::string>& args, std::string* err) {
gid_ = decode_uid(args[1].c_str());
for (std::size_t n = 2; n < args.size(); n++) {
supp_gids_.emplace_back(decode_uid(args[n].c_str()));
@@ -194,7 +350,20 @@
return true;
}
-bool Service::HandleIoprio(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParsePriority(const std::vector<std::string>& args, std::string* err) {
+ priority_ = std::stoi(args[1]);
+
+ if (priority_ < ANDROID_PRIORITY_HIGHEST || priority_ > ANDROID_PRIORITY_LOWEST) {
+ priority_ = 0;
+ *err = StringPrintf("process priority value must be range %d - %d",
+ ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
+ return false;
+ }
+
+ return true;
+}
+
+bool Service::ParseIoprio(const std::vector<std::string>& args, std::string* err) {
ioprio_pri_ = std::stoul(args[2], 0, 8);
if (ioprio_pri_ < 0 || ioprio_pri_ > 7) {
@@ -216,36 +385,52 @@
return true;
}
-bool Service::HandleKeycodes(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseKeycodes(const std::vector<std::string>& args, std::string* err) {
for (std::size_t i = 1; i < args.size(); i++) {
keycodes_.emplace_back(std::stoi(args[i]));
}
return true;
}
-bool Service::HandleOneshot(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseOneshot(const std::vector<std::string>& args, std::string* err) {
flags_ |= SVC_ONESHOT;
return true;
}
-bool Service::HandleOnrestart(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseOnrestart(const std::vector<std::string>& args, std::string* err) {
std::vector<std::string> str_args(args.begin() + 1, args.end());
onrestart_.AddCommand(str_args, "", 0, err);
return true;
}
-bool Service::HandleSeclabel(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseNamespace(const std::vector<std::string>& args, std::string* err) {
+ for (size_t i = 1; i < args.size(); i++) {
+ if (args[i] == "pid") {
+ namespace_flags_ |= CLONE_NEWPID;
+ // PID namespaces require mount namespaces.
+ namespace_flags_ |= CLONE_NEWNS;
+ } else if (args[i] == "mnt") {
+ namespace_flags_ |= CLONE_NEWNS;
+ } else {
+ *err = "namespace must be 'pid' or 'mnt'";
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Service::ParseSeclabel(const std::vector<std::string>& args, std::string* err) {
seclabel_ = args[1];
return true;
}
-bool Service::HandleSetenv(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseSetenv(const std::vector<std::string>& args, std::string* err) {
envvars_.emplace_back(args[1], args[2]);
return true;
}
/* name type perm [ uid gid context ] */
-bool Service::HandleSocket(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseSocket(const std::vector<std::string>& args, std::string* err) {
if (args[2] != "dgram" && args[2] != "stream" && args[2] != "seqpacket") {
*err = "socket type must be 'dgram', 'stream' or 'seqpacket'";
return false;
@@ -260,59 +445,61 @@
return true;
}
-bool Service::HandleUser(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseUser(const std::vector<std::string>& args, std::string* err) {
uid_ = decode_uid(args[1].c_str());
return true;
}
-bool Service::HandleWritepid(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseWritepid(const std::vector<std::string>& args, std::string* err) {
writepid_files_.assign(args.begin() + 1, args.end());
return true;
}
-class Service::OptionHandlerMap : public KeywordMap<OptionHandler> {
+class Service::OptionParserMap : public KeywordMap<OptionParser> {
public:
- OptionHandlerMap() {
+ OptionParserMap() {
}
private:
Map& map() const override;
};
-Service::OptionHandlerMap::Map& Service::OptionHandlerMap::map() const {
+Service::OptionParserMap::Map& Service::OptionParserMap::map() const {
constexpr std::size_t kMax = std::numeric_limits<std::size_t>::max();
- static const Map option_handlers = {
- {"class", {1, 1, &Service::HandleClass}},
- {"console", {0, 0, &Service::HandleConsole}},
- {"critical", {0, 0, &Service::HandleCritical}},
- {"disabled", {0, 0, &Service::HandleDisabled}},
- {"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
- {"ioprio", {2, 2, &Service::HandleIoprio}},
- {"keycodes", {1, kMax, &Service::HandleKeycodes}},
- {"oneshot", {0, 0, &Service::HandleOneshot}},
- {"onrestart", {1, kMax, &Service::HandleOnrestart}},
- {"seclabel", {1, 1, &Service::HandleSeclabel}},
- {"setenv", {2, 2, &Service::HandleSetenv}},
- {"socket", {3, 6, &Service::HandleSocket}},
- {"user", {1, 1, &Service::HandleUser}},
- {"writepid", {1, kMax, &Service::HandleWritepid}},
+ static const Map option_parsers = {
+ {"class", {1, 1, &Service::ParseClass}},
+ {"console", {0, 1, &Service::ParseConsole}},
+ {"critical", {0, 0, &Service::ParseCritical}},
+ {"disabled", {0, 0, &Service::ParseDisabled}},
+ {"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::ParseGroup}},
+ {"ioprio", {2, 2, &Service::ParseIoprio}},
+ {"priority", {1, 1, &Service::ParsePriority}},
+ {"keycodes", {1, kMax, &Service::ParseKeycodes}},
+ {"oneshot", {0, 0, &Service::ParseOneshot}},
+ {"onrestart", {1, kMax, &Service::ParseOnrestart}},
+ {"namespace", {1, 2, &Service::ParseNamespace}},
+ {"seclabel", {1, 1, &Service::ParseSeclabel}},
+ {"setenv", {2, 2, &Service::ParseSetenv}},
+ {"socket", {3, 6, &Service::ParseSocket}},
+ {"user", {1, 1, &Service::ParseUser}},
+ {"writepid", {1, kMax, &Service::ParseWritepid}},
};
- return option_handlers;
+ return option_parsers;
}
-bool Service::HandleLine(const std::vector<std::string>& args, std::string* err) {
+bool Service::ParseLine(const std::vector<std::string>& args, std::string* err) {
if (args.empty()) {
*err = "option needed, but not provided";
return false;
}
- static const OptionHandlerMap handler_map;
- auto handler = handler_map.FindFunction(args[0], args.size() - 1, err);
+ static const OptionParserMap parser_map;
+ auto parser = parser_map.FindFunction(args[0], args.size() - 1, err);
- if (!handler) {
+ if (!parser) {
return false;
}
- return (this->*handler)(args, err);
+ return (this->*parser)(args, err);
}
bool Service::Start() {
@@ -329,16 +516,22 @@
}
bool needs_console = (flags_ & SVC_CONSOLE);
- if (needs_console && !have_console) {
- ERROR("service '%s' requires console\n", name_.c_str());
- flags_ |= SVC_DISABLED;
- return false;
+ if (needs_console) {
+ if (console_.empty()) {
+ console_ = default_console;
+ }
+
+ bool have_console = (open(console_.c_str(), O_RDWR | O_CLOEXEC) != -1);
+ if (!have_console) {
+ PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
+ flags_ |= SVC_DISABLED;
+ return false;
+ }
}
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
- ERROR("cannot find '%s' (%s), disabling '%s'\n",
- args_[0].c_str(), strerror(errno), name_.c_str());
+ PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
@@ -347,80 +540,48 @@
if (!seclabel_.empty()) {
scon = seclabel_;
} else {
- char* mycon = nullptr;
- char* fcon = nullptr;
-
- INFO("computing context for service '%s'\n", args_[0].c_str());
- int rc = getcon(&mycon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", name_.c_str());
- return false;
- }
-
- rc = getfilecon(args_[0].c_str(), &fcon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", name_.c_str());
- free(mycon);
- return false;
- }
-
- char* ret_scon = nullptr;
- rc = security_compute_create(mycon, fcon, string_to_security_class("process"),
- &ret_scon);
- if (rc == 0) {
- scon = ret_scon;
- free(ret_scon);
- }
- if (rc == 0 && scon == mycon) {
- ERROR("Service %s does not have a SELinux domain defined.\n", name_.c_str());
- free(mycon);
- free(fcon);
- return false;
- }
- free(mycon);
- free(fcon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", name_.c_str());
+ LOG(INFO) << "computing context for service '" << name_ << "'";
+ scon = ComputeContextFromExecutable(name_, args_[0]);
+ if (scon == "") {
return false;
}
}
- NOTICE("Starting service '%s'...\n", name_.c_str());
+ LOG(VERBOSE) << "starting service '" << name_ << "'...";
- pid_t pid = fork();
+ pid_t pid = -1;
+ if (namespace_flags_) {
+ pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
+ } else {
+ pid = fork();
+ }
+
if (pid == 0) {
umask(077);
+ if (namespace_flags_ & CLONE_NEWPID) {
+ // This will fork again to run an init process inside the PID
+ // namespace.
+ SetUpPidNamespace(name_);
+ }
+
for (const auto& ei : envvars_) {
add_environment(ei.name.c_str(), ei.value.c_str());
}
- for (const auto& si : sockets_) {
- int socket_type = ((si.type == "stream" ? SOCK_STREAM :
- (si.type == "dgram" ? SOCK_DGRAM :
- SOCK_SEQPACKET)));
- const char* socketcon =
- !si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();
-
- int s = create_socket(si.name.c_str(), socket_type, si.perm,
- si.uid, si.gid, socketcon);
- if (s >= 0) {
- PublishSocket(si.name, s);
- }
- }
+ CreateSockets(scon);
std::string pid_str = StringPrintf("%d", getpid());
for (const auto& file : writepid_files_) {
if (!WriteStringToFile(pid_str, file)) {
- ERROR("couldn't write %s to %s: %s\n",
- pid_str.c_str(), file.c_str(), strerror(errno));
+ PLOG(ERROR) << "couldn't write " << pid_str << " to " << file;
}
}
if (ioprio_class_ != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), ioprio_class_, ioprio_pri_)) {
- ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
- getpid(), ioprio_class_, ioprio_pri_, strerror(errno));
+ PLOG(ERROR) << "failed to set pid " << getpid()
+ << " ioprio=" << ioprio_class_ << "," << ioprio_pri_;
}
}
@@ -431,57 +592,21 @@
ZapStdio();
}
- setpgid(0, getpid());
+ // As requested, set our gid, supplemental gids, uid, context, and
+ // priority. Aborts on failure.
+ SetProcessAttributes();
- // As requested, set our gid, supplemental gids, and uid.
- if (gid_) {
- if (setgid(gid_) != 0) {
- ERROR("setgid failed: %s\n", strerror(errno));
- _exit(127);
- }
- }
- if (!supp_gids_.empty()) {
- if (setgroups(supp_gids_.size(), &supp_gids_[0]) != 0) {
- ERROR("setgroups failed: %s\n", strerror(errno));
- _exit(127);
- }
- }
- if (uid_) {
- if (setuid(uid_) != 0) {
- ERROR("setuid failed: %s\n", strerror(errno));
- _exit(127);
- }
- }
- if (!seclabel_.empty()) {
- if (setexeccon(seclabel_.c_str()) < 0) {
- ERROR("cannot setexeccon('%s'): %s\n",
- seclabel_.c_str(), strerror(errno));
- _exit(127);
- }
- }
-
- std::vector<std::string> expanded_args;
std::vector<char*> strs;
- expanded_args.resize(args_.size());
- strs.push_back(const_cast<char*>(args_[0].c_str()));
- for (std::size_t i = 1; i < args_.size(); ++i) {
- if (!expand_props(args_[i], &expanded_args[i])) {
- ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
- _exit(127);
- }
- strs.push_back(const_cast<char*>(expanded_args[i].c_str()));
- }
- strs.push_back(nullptr);
-
+ ExpandArgs(args_, &strs);
if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
- ERROR("cannot execve('%s'): %s\n", strs[0], strerror(errno));
+ PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
}
_exit(127);
}
if (pid < 0) {
- ERROR("failed to start '%s'\n", name_.c_str());
+ PLOG(ERROR) << "failed to fork for '" << name_ << "'";
pid_ = 0;
return false;
}
@@ -490,10 +615,16 @@
pid_ = pid;
flags_ |= SVC_RUNNING;
+ errno = -createProcessGroup(uid_, pid_);
+ if (errno != 0) {
+ PLOG(ERROR) << "createProcessGroup(" << uid_ << ", " << pid_ << ") failed for service '"
+ << name_ << "'";
+ }
+
if ((flags_ & SVC_EXEC) != 0) {
- INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
- pid_, uid_, gid_, supp_gids_.size(),
- !seclabel_.empty() ? seclabel_.c_str() : "default");
+ LOG(INFO) << android::base::StringPrintf(
+ "SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...", pid_, uid_, gid_,
+ supp_gids_.size(), !seclabel_.empty() ? seclabel_.c_str() : "default");
}
NotifyStateChange("running");
@@ -529,9 +660,7 @@
flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
flags_ |= SVC_DISABLED;
if (pid_) {
- NOTICE("Sending SIGTERM to service '%s' (pid %d)...\n", name_.c_str(),
- pid_);
- kill(-pid_, SIGTERM);
+ KillProcessGroup(SIGTERM);
NotifyStateChange("stopping");
}
}
@@ -561,19 +690,18 @@
}
}
-/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
+// The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART.
void Service::StopOrReset(int how) {
- /* The service is still SVC_RUNNING until its process exits, but if it has
- * already exited it shoudn't attempt a restart yet. */
+ // The service is still SVC_RUNNING until its process exits, but if it has
+ // already exited it shoudn't attempt a restart yet.
flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
- /* Hrm, an illegal flag. Default to SVC_DISABLED */
+ // An illegal flag: default to SVC_DISABLED.
how = SVC_DISABLED;
}
- /* if the service has not yet started, prevent
- * it from auto-starting with its class
- */
+
+ // If the service has not yet started, prevent it from auto-starting with its class.
if (how == SVC_RESET) {
flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;
} else {
@@ -581,8 +709,7 @@
}
if (pid_) {
- NOTICE("Service '%s' is being killed...\n", name_.c_str());
- kill(-pid_, SIGKILL);
+ KillProcessGroup(SIGKILL);
NotifyStateChange("stopping");
} else {
NotifyStateChange("stopped");
@@ -599,10 +726,8 @@
}
void Service::OpenConsole() const {
- int fd;
- if ((fd = open(console_name.c_str(), O_RDWR)) < 0) {
- fd = open("/dev/null", O_RDWR);
- }
+ int fd = open(console_.c_str(), O_RDWR);
+ if (fd == -1) fd = open("/dev/null", O_RDWR);
ioctl(fd, TIOCSCTTY, 0);
dup2(fd, 0);
dup2(fd, 1);
@@ -632,8 +757,7 @@
void ServiceManager::AddService(std::unique_ptr<Service> service) {
Service* old_service = FindServiceByName(service->name());
if (old_service) {
- ERROR("ignored duplicate definition of service '%s'",
- service->name().c_str());
+ LOG(ERROR) << "ignored duplicate definition of service '" << service->name() << "'";
return;
}
services_.emplace_back(std::move(service));
@@ -650,12 +774,12 @@
}
}
if (command_arg > 4 + NR_SVC_SUPP_GIDS) {
- ERROR("exec called with too many supplementary group ids\n");
+ LOG(ERROR) << "exec called with too many supplementary group ids";
return nullptr;
}
if (command_arg >= args.size()) {
- ERROR("exec called without command\n");
+ LOG(ERROR) << "exec called without command";
return nullptr;
}
std::vector<std::string> str_args(args.begin() + command_arg, args.end());
@@ -663,6 +787,7 @@
exec_count_++;
std::string name = StringPrintf("exec %d (%s)", exec_count_, str_args[0].c_str());
unsigned flags = SVC_EXEC | SVC_ONESHOT;
+ unsigned namespace_flags = 0;
std::string seclabel = "";
if (command_arg > 2 && args[1] != "-") {
@@ -683,10 +808,10 @@
}
std::unique_ptr<Service> svc_p(new Service(name, "default", flags, uid, gid,
- supp_gids, seclabel, str_args));
+ supp_gids, namespace_flags,
+ seclabel, str_args));
if (!svc_p) {
- ERROR("Couldn't allocate service for exec of '%s'",
- str_args[0].c_str());
+ LOG(ERROR) << "Couldn't allocate service for exec of '" << str_args[0] << "'";
return nullptr;
}
Service* svc = svc_p.get();
@@ -729,7 +854,7 @@
return nullptr;
}
-void ServiceManager::ForEachService(std::function<void(Service*)> callback) const {
+void ServiceManager::ForEachService(const std::function<void(Service*)>& callback) const {
for (const auto& s : services_) {
callback(s.get());
}
@@ -769,7 +894,6 @@
for (const auto& s : services_) {
s->DumpState();
}
- INFO("\n");
}
bool ServiceManager::ReapOneProcess() {
@@ -778,7 +902,7 @@
if (pid == 0) {
return false;
} else if (pid == -1) {
- ERROR("waitpid failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "waitpid failed";
return false;
}
@@ -793,13 +917,13 @@
}
if (WIFEXITED(status)) {
- NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status));
+ LOG(VERBOSE) << name << " exited with status " << WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
- NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status));
+ LOG(VERBOSE) << name << " killed by signal " << WTERMSIG(status);
} else if (WIFSTOPPED(status)) {
- NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status));
+ LOG(VERBOSE) << name << " stopped by signal " << WSTOPSIG(status);
} else {
- NOTICE("%s state changed", name.c_str());
+ LOG(VERBOSE) << name << " state changed";
}
if (!svc) {
@@ -840,7 +964,7 @@
bool ServiceParser::ParseLineSection(const std::vector<std::string>& args,
const std::string& filename, int line,
std::string* err) const {
- return service_ ? service_->HandleLine(args, err) : false;
+ return service_ ? service_->ParseLine(args, err) : false;
}
void ServiceParser::EndSection() {
diff --git a/init/service.h b/init/service.h
index d9d18ef..fb03a07 100644
--- a/init/service.h
+++ b/init/service.h
@@ -72,10 +72,11 @@
const std::vector<std::string>& args);
Service(const std::string& name, const std::string& classname,
- unsigned flags, uid_t uid, gid_t gid, const std::vector<gid_t>& supp_gids,
- const std::string& seclabel, const std::vector<std::string>& args);
+ unsigned flags, uid_t uid, gid_t gid,
+ const std::vector<gid_t>& supp_gids, unsigned namespace_flags,
+ const std::string& seclabel, const std::vector<std::string>& args);
- bool HandleLine(const std::vector<std::string>& args, std::string* err);
+ bool ParseLine(const std::vector<std::string>& args, std::string* err);
bool Start();
bool StartIfNotDisabled();
bool Enable();
@@ -93,6 +94,7 @@
pid_t pid() const { return pid_; }
uid_t uid() const { return uid_; }
gid_t gid() const { return gid_; }
+ int priority() const { return priority_; }
const std::vector<gid_t>& supp_gids() const { return supp_gids_; }
const std::string& seclabel() const { return seclabel_; }
const std::vector<int>& keycodes() const { return keycodes_; }
@@ -101,33 +103,39 @@
const std::vector<std::string>& args() const { return args_; }
private:
- using OptionHandler = bool (Service::*) (const std::vector<std::string>& args,
- std::string* err);
- class OptionHandlerMap;
+ using OptionParser = bool (Service::*) (const std::vector<std::string>& args,
+ std::string* err);
+ class OptionParserMap;
void NotifyStateChange(const std::string& new_state) const;
void StopOrReset(int how);
void ZapStdio() const;
void OpenConsole() const;
void PublishSocket(const std::string& name, int fd) const;
+ void KillProcessGroup(int signal);
+ void CreateSockets(const std::string& scon);
+ void SetProcessAttributes();
- bool HandleClass(const std::vector<std::string>& args, std::string* err);
- bool HandleConsole(const std::vector<std::string>& args, std::string* err);
- bool HandleCritical(const std::vector<std::string>& args, std::string* err);
- bool HandleDisabled(const std::vector<std::string>& args, std::string* err);
- bool HandleGroup(const std::vector<std::string>& args, std::string* err);
- bool HandleIoprio(const std::vector<std::string>& args, std::string* err);
- bool HandleKeycodes(const std::vector<std::string>& args, std::string* err);
- bool HandleOneshot(const std::vector<std::string>& args, std::string* err);
- bool HandleOnrestart(const std::vector<std::string>& args, std::string* err);
- bool HandleSeclabel(const std::vector<std::string>& args, std::string* err);
- bool HandleSetenv(const std::vector<std::string>& args, std::string* err);
- bool HandleSocket(const std::vector<std::string>& args, std::string* err);
- bool HandleUser(const std::vector<std::string>& args, std::string* err);
- bool HandleWritepid(const std::vector<std::string>& args, std::string* err);
+ bool ParseClass(const std::vector<std::string>& args, std::string* err);
+ bool ParseConsole(const std::vector<std::string>& args, std::string* err);
+ bool ParseCritical(const std::vector<std::string>& args, std::string* err);
+ bool ParseDisabled(const std::vector<std::string>& args, std::string* err);
+ bool ParseGroup(const std::vector<std::string>& args, std::string* err);
+ bool ParsePriority(const std::vector<std::string>& args, std::string* err);
+ bool ParseIoprio(const std::vector<std::string>& args, std::string* err);
+ bool ParseKeycodes(const std::vector<std::string>& args, std::string* err);
+ bool ParseOneshot(const std::vector<std::string>& args, std::string* err);
+ bool ParseOnrestart(const std::vector<std::string>& args, std::string* err);
+ bool ParseNamespace(const std::vector<std::string>& args, std::string* err);
+ bool ParseSeclabel(const std::vector<std::string>& args, std::string* err);
+ bool ParseSetenv(const std::vector<std::string>& args, std::string* err);
+ bool ParseSocket(const std::vector<std::string>& args, std::string* err);
+ bool ParseUser(const std::vector<std::string>& args, std::string* err);
+ bool ParseWritepid(const std::vector<std::string>& args, std::string* err);
std::string name_;
std::string classname_;
+ std::string console_;
unsigned flags_;
pid_t pid_;
@@ -138,6 +146,7 @@
uid_t uid_;
gid_t gid_;
std::vector<gid_t> supp_gids_;
+ unsigned namespace_flags_;
std::string seclabel_;
@@ -154,6 +163,7 @@
IoSchedClass ioprio_class_;
int ioprio_pri_;
+ int priority_;
std::vector<std::string> args_;
};
@@ -167,7 +177,7 @@
Service* FindServiceByName(const std::string& name) const;
Service* FindServiceByPid(pid_t pid) const;
Service* FindServiceByKeychord(int keychord_id) const;
- void ForEachService(std::function<void(Service*)> callback) const;
+ void ForEachService(const std::function<void(Service*)>& callback) const;
void ForEachServiceInClass(const std::string& classname,
void (*func)(Service* svc)) const;
void ForEachServiceWithFlags(unsigned matchflags,
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index ea483d4..0dea3e0 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -47,7 +47,7 @@
static void SIGCHLD_handler(int) {
if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
- ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "write(signal_write_fd) failed";
}
}
@@ -55,7 +55,7 @@
// Create a signalling mechanism for SIGCHLD.
int s[2];
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
- ERROR("socketpair failed: %s\n", strerror(errno));
+ PLOG(ERROR) << "socketpair failed";
exit(1);
}
diff --git a/init/ueventd.cpp b/init/ueventd.cpp
index 249739b..e7794ec 100644
--- a/init/ueventd.cpp
+++ b/init/ueventd.cpp
@@ -16,14 +16,17 @@
#include <ctype.h>
#include <fcntl.h>
+#include <grp.h>
#include <poll.h>
+#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+
#include <android-base/stringprintf.h>
-#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
#include "ueventd.h"
@@ -49,11 +52,9 @@
*/
signal(SIGCHLD, SIG_IGN);
- open_devnull_stdio();
- klog_init();
- klog_set_level(KLOG_NOTICE_LEVEL);
+ InitKernelLogging(argv);
- NOTICE("ueventd started!\n");
+ LOG(INFO) << "ueventd started!";
selinux_callback cb;
cb.func_log = selinux_klog_callback;
@@ -84,15 +85,6 @@
return 0;
}
-static int get_android_id(const char *id)
-{
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(android_ids); i++)
- if (!strcmp(id, android_ids[i].name))
- return android_ids[i].aid;
- return -1;
-}
-
void set_device_permission(int nargs, char **args)
{
char *name;
@@ -103,7 +95,6 @@
int prefix = 0;
int wildcard = 0;
char *endptr;
- int ret;
char *tmp = 0;
if (nargs == 0)
@@ -115,57 +106,48 @@
name = args[0];
if (!strncmp(name,"/sys/", 5) && (nargs == 5)) {
- INFO("/sys/ rule %s %s\n",args[0],args[1]);
+ LOG(INFO) << "/sys/ rule " << args[0] << " " << args[1];
attr = args[1];
args++;
nargs--;
}
if (nargs != 4) {
- ERROR("invalid line ueventd.rc line for '%s'\n", args[0]);
+ LOG(ERROR) << "invalid line ueventd.rc line for '" << args[0] << "'";
return;
}
- /* If path starts with mtd@ lookup the mount number. */
- if (!strncmp(name, "mtd@", 4)) {
- int n = mtd_name_to_number(name + 4);
- if (n >= 0)
- asprintf(&tmp, "/dev/mtd/mtd%d", n);
- name = tmp;
- } else {
- int len = strlen(name);
- char *wildcard_chr = strchr(name, '*');
- if ((name[len - 1] == '*') &&
- (wildcard_chr == (name + len - 1))) {
- prefix = 1;
- name[len - 1] = '\0';
- } else if (wildcard_chr) {
- wildcard = 1;
- }
+ int len = strlen(name);
+ char *wildcard_chr = strchr(name, '*');
+ if ((name[len - 1] == '*') && (wildcard_chr == (name + len - 1))) {
+ prefix = 1;
+ name[len - 1] = '\0';
+ } else if (wildcard_chr) {
+ wildcard = 1;
}
perm = strtol(args[1], &endptr, 8);
if (!endptr || *endptr != '\0') {
- ERROR("invalid mode '%s'\n", args[1]);
+ LOG(ERROR) << "invalid mode '" << args[1] << "'";
free(tmp);
return;
}
- ret = get_android_id(args[2]);
- if (ret < 0) {
- ERROR("invalid uid '%s'\n", args[2]);
+ struct passwd* pwd = getpwnam(args[2]);
+ if (!pwd) {
+ LOG(ERROR) << "invalid uid '" << args[2] << "'";
free(tmp);
return;
}
- uid = ret;
+ uid = pwd->pw_uid;
- ret = get_android_id(args[3]);
- if (ret < 0) {
- ERROR("invalid gid '%s'\n", args[3]);
+ struct group* grp = getgrnam(args[3]);
+ if (!grp) {
+ LOG(ERROR) << "invalid gid '" << args[3] << "'";
free(tmp);
return;
}
- gid = ret;
+ gid = grp->gr_gid;
add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard);
free(tmp);
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 09f4638..baff58c 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -38,7 +38,7 @@
#include "ueventd_keywords.h"
#define KEYWORD(symbol, flags, nargs) \
- [ K_##symbol ] = { #symbol, nargs + 1, flags, },
+ [ K_##symbol ] = { #symbol, (nargs) + 1, flags, },
static struct {
const char *name;
diff --git a/init/util.cpp b/init/util.cpp
index 89d3276..c1750d2 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -23,6 +23,7 @@
#include <errno.h>
#include <time.h>
#include <ftw.h>
+#include <pwd.h>
#include <selinux/label.h>
#include <selinux/android.h>
@@ -33,44 +34,31 @@
#include <sys/un.h>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <android-base/strings.h>
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
#include <android-base/stringprintf.h>
-#include <private/android_filesystem_config.h>
-
#include "init.h"
#include "log.h"
#include "property_service.h"
#include "util.h"
-/*
- * android_name_to_id - returns the integer uid/gid associated with the given
- * name, or UINT_MAX on error.
- */
-static unsigned int android_name_to_id(const char *name)
-{
- const struct android_id_info *info = android_ids;
- unsigned int n;
-
- for (n = 0; n < android_id_count; n++) {
- if (!strcmp(info[n].name, name))
- return info[n].aid;
- }
-
- return UINT_MAX;
-}
-
static unsigned int do_decode_uid(const char *s)
{
unsigned int v;
if (!s || *s == '\0')
return UINT_MAX;
- if (isalpha(s[0]))
- return android_name_to_id(s);
+
+ if (isalpha(s[0])) {
+ struct passwd* pwd = getpwnam(s);
+ if (!pwd)
+ return UINT_MAX;
+ return pwd->pw_uid;
+ }
errno = 0;
v = (unsigned int) strtoul(s, 0, 0);
@@ -87,7 +75,7 @@
unsigned int decode_uid(const char *s) {
unsigned int v = do_decode_uid(s);
if (v == UINT_MAX) {
- ERROR("decode_uid: Unable to find UID for '%s'. Returning UINT_MAX\n", s);
+ LOG(ERROR) << "decode_uid: Unable to find UID for '" << s << "'; returning UINT_MAX";
}
return v;
}
@@ -107,14 +95,14 @@
if (socketcon) {
if (setsockcreatecon(socketcon) == -1) {
- ERROR("setsockcreatecon(\"%s\") failed: %s\n", socketcon, strerror(errno));
+ PLOG(ERROR) << "setsockcreatecon(\"" << socketcon << "\") failed";
return -1;
}
}
fd = socket(PF_UNIX, type, 0);
if (fd < 0) {
- ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
+ PLOG(ERROR) << "Failed to open socket '" << name << "'";
return -1;
}
@@ -128,7 +116,7 @@
ret = unlink(addr.sun_path);
if (ret != 0 && errno != ENOENT) {
- ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
+ PLOG(ERROR) << "Failed to unlink old socket '" << name << "'";
goto out_close;
}
@@ -146,23 +134,26 @@
freecon(filecon);
if (ret) {
- ERROR("Failed to bind socket '%s': %s\n", name, strerror(savederrno));
+ errno = savederrno;
+ PLOG(ERROR) << "Failed to bind socket '" << name << "'";
goto out_unlink;
}
ret = lchown(addr.sun_path, uid, gid);
if (ret) {
- ERROR("Failed to lchown socket '%s': %s\n", addr.sun_path, strerror(errno));
+ PLOG(ERROR) << "Failed to lchown socket '" << addr.sun_path << "'";
goto out_unlink;
}
ret = fchmodat(AT_FDCWD, addr.sun_path, perm, AT_SYMLINK_NOFOLLOW);
if (ret) {
- ERROR("Failed to fchmodat socket '%s': %s\n", addr.sun_path, strerror(errno));
+ PLOG(ERROR) << "Failed to fchmodat socket '" << addr.sun_path << "'";
goto out_unlink;
}
- INFO("Created socket '%s' with mode '%o', user '%d', group '%d'\n",
- addr.sun_path, perm, uid, gid);
+ LOG(INFO) << "Created socket '" << addr.sun_path << "'"
+ << ", mode " << std::oct << perm << std::dec
+ << ", user " << uid
+ << ", group " << gid;
return fd;
@@ -185,11 +176,11 @@
// or group-writable files.
struct stat sb;
if (fstat(fd, &sb) == -1) {
- ERROR("fstat failed for '%s': %s\n", path, strerror(errno));
+ PLOG(ERROR) << "fstat failed for '" << path << "'";
return false;
}
if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
- ERROR("skipping insecure file '%s'\n", path);
+ PLOG(ERROR) << "skipping insecure file '" << path << "'";
return false;
}
@@ -201,89 +192,17 @@
int write_file(const char* path, const char* content) {
int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600));
if (fd == -1) {
- NOTICE("write_file: Unable to open '%s': %s\n", path, strerror(errno));
+ PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
return -1;
}
int result = android::base::WriteStringToFd(content, fd) ? 0 : -1;
if (result == -1) {
- NOTICE("write_file: Unable to write to '%s': %s\n", path, strerror(errno));
+ PLOG(ERROR) << "write_file: Unable to write to '" << path << "'";
}
close(fd);
return result;
}
-#define MAX_MTD_PARTITIONS 16
-
-static struct {
- char name[16];
- int number;
-} mtd_part_map[MAX_MTD_PARTITIONS];
-
-static int mtd_part_count = -1;
-
-static void find_mtd_partitions(void)
-{
- int fd;
- char buf[1024];
- char *pmtdbufp;
- ssize_t pmtdsize;
- int r;
-
- fd = open("/proc/mtd", O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return;
-
- buf[sizeof(buf) - 1] = '\0';
- pmtdsize = read(fd, buf, sizeof(buf) - 1);
- pmtdbufp = buf;
- while (pmtdsize > 0) {
- int mtdnum, mtdsize, mtderasesize;
- char mtdname[16];
- mtdname[0] = '\0';
- mtdnum = -1;
- r = sscanf(pmtdbufp, "mtd%d: %x %x %15s",
- &mtdnum, &mtdsize, &mtderasesize, mtdname);
- if ((r == 4) && (mtdname[0] == '"')) {
- char *x = strchr(mtdname + 1, '"');
- if (x) {
- *x = 0;
- }
- INFO("mtd partition %d, %s\n", mtdnum, mtdname + 1);
- if (mtd_part_count < MAX_MTD_PARTITIONS) {
- strcpy(mtd_part_map[mtd_part_count].name, mtdname + 1);
- mtd_part_map[mtd_part_count].number = mtdnum;
- mtd_part_count++;
- } else {
- ERROR("too many mtd partitions\n");
- }
- }
- while (pmtdsize > 0 && *pmtdbufp != '\n') {
- pmtdbufp++;
- pmtdsize--;
- }
- if (pmtdsize > 0) {
- pmtdbufp++;
- pmtdsize--;
- }
- }
- close(fd);
-}
-
-int mtd_name_to_number(const char *name)
-{
- int n;
- if (mtd_part_count < 0) {
- mtd_part_count = 0;
- find_mtd_partitions();
- }
- for (n = 0; n < mtd_part_count; n++) {
- if (!strcmp(name, mtd_part_map[n].name)) {
- return mtd_part_map[n].number;
- }
- }
- return -1;
-}
-
time_t gettime() {
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -313,7 +232,7 @@
if (width == 0)
continue;
if ((unsigned int)width > sizeof(buf) - 1) {
- ERROR("path too long for mkdir_recursive\n");
+ LOG(ERROR) << "path too long for mkdir_recursive";
return -1;
}
memcpy(buf, pathname, width);
@@ -355,7 +274,7 @@
{
int ret;
char buf[256];
- char *slash;
+ const char *slash;
int width;
slash = strrchr(newpath, '/');
@@ -367,12 +286,10 @@
memcpy(buf, newpath, width);
buf[width] = 0;
ret = mkdir_recursive(buf, 0755);
- if (ret)
- ERROR("Failed to create directory %s: %s (%d)\n", buf, strerror(errno), errno);
+ if (ret) PLOG(ERROR) << "Failed to create directory " << buf;
ret = symlink(oldpath, newpath);
- if (ret && errno != EEXIST)
- ERROR("Failed to symlink %s to %s: %s (%d)\n", oldpath, newpath, strerror(errno), errno);
+ if (ret && errno != EEXIST) PLOG(ERROR) << "Failed to symlink " << oldpath << " to " << newpath;
}
void remove_link(const char *oldpath, const char *newpath)
@@ -399,34 +316,8 @@
return ret;
}
-void open_devnull_stdio(void)
-{
- // Try to avoid the mknod() call if we can. Since SELinux makes
- // a /dev/null replacement available for free, let's use it.
- int fd = open("/sys/fs/selinux/null", O_RDWR);
- if (fd == -1) {
- // OOPS, /sys/fs/selinux/null isn't available, likely because
- // /sys/fs/selinux isn't mounted. Fall back to mknod.
- static const char *name = "/dev/__null__";
- if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
- fd = open(name, O_RDWR);
- unlink(name);
- }
- if (fd == -1) {
- exit(1);
- }
- }
-
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- if (fd > 2) {
- close(fd);
- }
-}
-
void import_kernel_cmdline(bool in_qemu,
- std::function<void(const std::string&, const std::string&, bool)> fn) {
+ const std::function<void(const std::string&, const std::string&, bool)>& fn) {
std::string cmdline;
android::base::ReadFileToString("/proc/cmdline", &cmdline);
@@ -539,7 +430,7 @@
const char* end = strchr(c, '}');
if (!end) {
// failed to find closing brace, abort.
- ERROR("unexpected end of string in '%s', looking for }\n", src.c_str());
+ LOG(ERROR) << "unexpected end of string in '" << src << "', looking for }";
return false;
}
prop_name = std::string(c, end);
@@ -551,21 +442,19 @@
}
} else {
prop_name = c;
- ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
- c);
+ LOG(ERROR) << "using deprecated syntax for specifying property '" << c << "', use ${name} instead";
c += prop_name.size();
}
if (prop_name.empty()) {
- ERROR("invalid zero-length prop name in '%s'\n", src.c_str());
+ LOG(ERROR) << "invalid zero-length property name in '" << src << "'";
return false;
}
std::string prop_val = property_get(prop_name.c_str());
if (prop_val.empty()) {
if (def_val.empty()) {
- ERROR("property '%s' doesn't exist while expanding '%s'\n",
- prop_name.c_str(), src.c_str());
+ LOG(ERROR) << "property '" << prop_name << "' doesn't exist while expanding '" << src << "'";
return false;
}
prop_val = def_val;
diff --git a/init/util.h b/init/util.h
index af4b098..29d0497 100644
--- a/init/util.h
+++ b/init/util.h
@@ -23,11 +23,8 @@
#include <string>
#include <functional>
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
#define COLDBOOT_DONE "/dev/.coldboot_done"
-int mtd_name_to_number(const char *name);
int create_socket(const char *name, int type, mode_t perm,
uid_t uid, gid_t gid, const char *socketcon);
@@ -57,9 +54,8 @@
void make_link_init(const char *oldpath, const char *newpath);
void remove_link(const char *oldpath, const char *newpath);
int wait_for_file(const char *filename, int timeout);
-void open_devnull_stdio(void);
void import_kernel_cmdline(bool in_qemu,
- std::function<void(const std::string&, const std::string&, bool)>);
+ const std::function<void(const std::string&, const std::string&, bool)>&);
int make_dir(const char *path, mode_t mode);
int restorecon(const char *pathname);
int restorecon_recursive(const char *pathname);
diff --git a/init/watchdogd.cpp b/init/watchdogd.cpp
index 0d16db9..b196147 100644
--- a/init/watchdogd.cpp
+++ b/init/watchdogd.cpp
@@ -28,9 +28,7 @@
#define DEV_NAME "/dev/watchdog"
int watchdogd_main(int argc, char **argv) {
- open_devnull_stdio();
- klog_init();
- klog_set_level(KLOG_NOTICE_LEVEL);
+ InitKernelLogging(argv);
int interval = 10;
if (argc >= 2) interval = atoi(argv[1]);
@@ -38,30 +36,31 @@
int margin = 10;
if (argc >= 3) margin = atoi(argv[2]);
- NOTICE("started (interval %d, margin %d)!\n", interval, margin);
+ LOG(INFO) << "watchdogd started (interval " << interval << ", margin " << margin << ")!";
int fd = open(DEV_NAME, O_RDWR|O_CLOEXEC);
if (fd == -1) {
- ERROR("Failed to open %s: %s\n", DEV_NAME, strerror(errno));
+ PLOG(ERROR) << "Failed to open " << DEV_NAME;
return 1;
}
int timeout = interval + margin;
int ret = ioctl(fd, WDIOC_SETTIMEOUT, &timeout);
if (ret) {
- ERROR("Failed to set timeout to %d: %s\n", timeout, strerror(errno));
+ PLOG(ERROR) << "Failed to set timeout to " << timeout;
ret = ioctl(fd, WDIOC_GETTIMEOUT, &timeout);
if (ret) {
- ERROR("Failed to get timeout: %s\n", strerror(errno));
+ PLOG(ERROR) << "Failed to get timeout";
} else {
if (timeout > margin) {
interval = timeout - margin;
} else {
interval = 1;
}
- WARNING("Adjusted interval to timeout returned by driver:"
- " timeout %d, interval %d, margin %d\n",
- timeout, interval, margin);
+ LOG(WARNING) << "Adjusted interval to timeout returned by driver: "
+ << "timeout " << timeout
+ << ", interval " << interval
+ << ", margin " << margin;
}
}
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
new file mode 100644
index 0000000..93d997b
--- /dev/null
+++ b/libbacktrace/Android.bp
@@ -0,0 +1,121 @@
+//
+// Copyright (C) 2014 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.
+//
+
+cc_defaults {
+ name: "libbacktrace_common",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ conlyflags: ["-std=gnu99"],
+ cppflags: ["-std=gnu++11"],
+
+ clang_cflags: ["-Wno-inline-asm"],
+
+ // The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
+ include_dirs: ["external/libunwind/include/tdep"],
+
+ // TODO: LLVM_DEVICE_BUILD_MK
+ // TODO: LLVM_HOST_BUILD_MK
+
+ target: {
+ host: {
+ // -fno-omit-frame-pointer should be set for host build. Because currently
+ // libunwind can't recognize .debug_frame using dwarf version 4, and it relies
+ // on stack frame pointer to do unwinding on x86.
+ // $(LLVM_HOST_BUILD_MK) overwrites -fno-omit-frame-pointer. so the below line
+ // must be after the include.
+ cflags: [
+ "-Wno-extern-c-compat",
+ "-fno-omit-frame-pointer",
+ ],
+ },
+
+ darwin: {
+ enabled: false,
+ },
+ },
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ }
+}
+
+libbacktrace_sources = [
+ "Backtrace.cpp",
+ "BacktraceCurrent.cpp",
+ "BacktracePtrace.cpp",
+ "thread_utils.c",
+ "ThreadEntry.cpp",
+ "UnwindCurrent.cpp",
+ "UnwindMap.cpp",
+ "UnwindPtrace.cpp",
+]
+
+cc_library {
+ name: "libbacktrace",
+ defaults: ["libbacktrace_common"],
+ host_supported: true,
+
+ srcs: [
+ "BacktraceMap.cpp",
+ ],
+
+ target: {
+ darwin: {
+ enabled: true,
+ },
+ linux: {
+ srcs: libbacktrace_sources,
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libunwind",
+ ],
+
+ static_libs: ["libcutils"],
+ },
+ android: {
+ srcs: libbacktrace_sources,
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ "libunwind",
+ ],
+
+ static_libs: ["libcutils"],
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libbacktrace_test",
+ defaults: ["libbacktrace_common"],
+ host_supported: true,
+ strip: {
+ none: true,
+ },
+ cflags: ["-O0"],
+ srcs: ["backtrace_testlib.c"],
+}
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index ee25e08..9bb113a 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -25,7 +25,9 @@
libbacktrace_common_cppflags := \
-std=gnu++11 \
- -I external/libunwind/include/tdep \
+
+libbacktrace_common_c_includes := \
+ external/libunwind/include/tdep \
# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
libbacktrace_common_clang_cflags += \
@@ -42,45 +44,6 @@
include $(LLVM_ROOT_PATH)/llvm.mk
#-------------------------------------------------------------------------
-# The libbacktrace library.
-#-------------------------------------------------------------------------
-libbacktrace_src_files := \
- Backtrace.cpp \
- BacktraceCurrent.cpp \
- BacktraceMap.cpp \
- BacktracePtrace.cpp \
- thread_utils.c \
- ThreadEntry.cpp \
- UnwindCurrent.cpp \
- UnwindMap.cpp \
- UnwindPtrace.cpp \
-
-libbacktrace_shared_libraries := \
- libbase \
- liblog \
- libunwind \
-
-libbacktrace_static_libraries := \
- libcutils
-
-module := libbacktrace
-module_tag := optional
-build_type := target
-build_target := SHARED_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-libbacktrace_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-libbacktrace_static_libraries := \
- libbase \
- liblog \
- libunwind \
-
-build_target := STATIC_LIBRARY
-include $(LOCAL_PATH)/Android.build.mk
-libbacktrace_static_libraries :=
-
-#-------------------------------------------------------------------------
# The libbacktrace_offline shared library.
#-------------------------------------------------------------------------
libbacktrace_offline_src_files := \
@@ -125,26 +88,6 @@
include $(LOCAL_PATH)/Android.build.mk
#-------------------------------------------------------------------------
-# The libbacktrace_test library needed by backtrace_test.
-#-------------------------------------------------------------------------
-libbacktrace_test_cflags := \
- -O0 \
-
-libbacktrace_test_src_files := \
- backtrace_testlib.c \
-
-libbacktrace_test_strip_module := false
-
-module := libbacktrace_test
-module_tag := debug
-build_type := target
-build_target := SHARED_LIBRARY
-libbacktrace_test_multilib := both
-include $(LOCAL_PATH)/Android.build.mk
-build_type := host
-include $(LOCAL_PATH)/Android.build.mk
-
-#-------------------------------------------------------------------------
# The backtrace_test executable.
#-------------------------------------------------------------------------
backtrace_test_cflags := \
@@ -209,22 +152,3 @@
include $(LOCAL_PATH)/Android.build.mk
build_type := host
include $(LOCAL_PATH)/Android.build.mk
-
-#----------------------------------------------------------------------------
-# Special truncated libbacktrace library for mac.
-#----------------------------------------------------------------------------
-ifeq ($(HOST_OS),darwin)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libbacktrace
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := \
- BacktraceMap.cpp \
-
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-endif # HOST_OS-darwin
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index ba86632..00c35b1 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <inttypes.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
@@ -35,8 +36,8 @@
}
void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
- for (BacktraceMap::const_iterator it = begin();
- it != end(); ++it) {
+ ScopedBacktraceMapIteratorLock lock(this);
+ for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) {
if (addr >= it->start && addr < it->end) {
*map = *it;
return;
@@ -46,8 +47,8 @@
}
bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
- unsigned long int start;
- unsigned long int end;
+ uint64_t start;
+ uint64_t end;
char permissions[5];
int name_pos;
@@ -56,14 +57,14 @@
// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
- if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
+ if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c %n",
&start, &end, permissions, &name_pos) != 3) {
#else
// Linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
- if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d %n",
+ if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %*x %*x:%*x %*d %n",
&start, &end, permissions, &name_pos) != 3) {
#endif
return false;
diff --git a/libbacktrace/BacktraceOffline.cpp b/libbacktrace/BacktraceOffline.cpp
index 9a4f622..c2b68bc 100644
--- a/libbacktrace/BacktraceOffline.cpp
+++ b/libbacktrace/BacktraceOffline.cpp
@@ -665,7 +665,7 @@
class ScopedZiparchiveHandle {
public:
- ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
+ explicit ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
}
~ScopedZiparchiveHandle() {
diff --git a/libbacktrace/GetPss.cpp b/libbacktrace/GetPss.cpp
index 09a721d..6d750ea 100644
--- a/libbacktrace/GetPss.cpp
+++ b/libbacktrace/GetPss.cpp
@@ -24,7 +24,7 @@
// This is an extremely simplified version of libpagemap.
-#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
+#define _BITS(x, offset, bits) (((x) >> (offset)) & ((1LL << (bits)) - 1))
#define PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
#define PAGEMAP_SWAPPED(x) (_BITS(x, 62, 1))
@@ -33,7 +33,7 @@
#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
#define PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
-static bool ReadData(int fd, unsigned long place, uint64_t *data) {
+static bool ReadData(int fd, off_t place, uint64_t *data) {
if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
return false;
}
@@ -71,12 +71,13 @@
total_pss = 0;
break;
}
- for (size_t page = start/pagesize; page < end/pagesize; page++) {
+ for (off_t page = static_cast<off_t>(start/pagesize);
+ page < static_cast<off_t>(end/pagesize); page++) {
uint64_t data;
if (ReadData(pagemap_fd, page, &data)) {
if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
uint64_t count;
- if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
+ if (ReadData(pagecount_fd, static_cast<off_t>(PAGEMAP_PFN(data)), &count)) {
total_pss += (count >= 1) ? pagesize / count : 0;
}
}
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 34d79f9..af79562 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -72,6 +73,7 @@
}
UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
+ pthread_rwlock_init(&map_lock_, nullptr);
}
UnwindMapLocal::~UnwindMapLocal() {
@@ -82,9 +84,14 @@
}
bool UnwindMapLocal::GenerateMap() {
+ // Lock so that multiple threads cannot modify the maps data at the
+ // same time.
+ pthread_rwlock_wrlock(&map_lock_);
+
// It's possible for the map to be regenerated while this loop is occurring.
// If that happens, get the map again, but only try at most three times
// before giving up.
+ bool generated = false;
for (int i = 0; i < 3; i++) {
maps_.clear();
@@ -110,12 +117,17 @@
}
// Check to see if the map changed while getting the data.
if (ret != -UNW_EINVAL) {
- return true;
+ generated = true;
+ break;
}
}
- BACK_LOGW("Unable to generate the map.");
- return false;
+ pthread_rwlock_unlock(&map_lock_);
+
+ if (!generated) {
+ BACK_LOGW("Unable to generate the map.");
+ }
+ return generated;
}
bool UnwindMapLocal::Build() {
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index 111401f..d5bec06 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -17,6 +17,7 @@
#ifndef _LIBBACKTRACE_UNWIND_MAP_H
#define _LIBBACKTRACE_UNWIND_MAP_H
+#include <pthread.h>
#include <stdint.h>
#include <sys/types.h>
@@ -28,7 +29,7 @@
class UnwindMap : public BacktraceMap {
public:
- UnwindMap(pid_t pid);
+ explicit UnwindMap(pid_t pid);
unw_map_cursor_t* GetMapCursor() { return &map_cursor_; }
@@ -38,7 +39,7 @@
class UnwindMapRemote : public UnwindMap {
public:
- UnwindMapRemote(pid_t pid);
+ explicit UnwindMapRemote(pid_t pid);
virtual ~UnwindMapRemote();
bool Build() override;
@@ -56,10 +57,15 @@
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+ void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
+ void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
+
private:
bool GenerateMap();
bool map_created_;
+
+ pthread_rwlock_t map_lock_;
};
#endif // _LIBBACKTRACE_UNWIND_MAP_H
diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp
index 88a3533..d6dc2c9 100644
--- a/libbacktrace/backtrace_offline_test.cpp
+++ b/libbacktrace/backtrace_offline_test.cpp
@@ -73,7 +73,7 @@
return ucontext;
}
-static void OfflineBacktraceFunctionCall(std::function<int(void (*)(void*), void*)> function,
+static void OfflineBacktraceFunctionCall(const std::function<int(void (*)(void*), void*)>& function,
std::vector<uintptr_t>* pc_values) {
// Create a thread to generate the needed stack and registers information.
g_exit_flag = false;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index f6b2591..e25c8e9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -414,17 +414,16 @@
char task_path[128];
snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
- DIR* tasks_dir = opendir(task_path);
+ std::unique_ptr<DIR, decltype(&closedir)> tasks_dir(opendir(task_path), closedir);
ASSERT_TRUE(tasks_dir != nullptr);
struct dirent* entry;
- while ((entry = readdir(tasks_dir)) != nullptr) {
+ while ((entry = readdir(tasks_dir.get())) != nullptr) {
char* end;
pid_t tid = strtoul(entry->d_name, &end, 10);
if (*end == '\0') {
threads->push_back(tid);
}
}
- closedir(tasks_dir);
}
TEST(libbacktrace, ptrace_threads) {
@@ -896,6 +895,7 @@
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
// Basic test that verifies that the map is in the expected order.
+ ScopedBacktraceMapIteratorLock lock(map.get());
std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
ASSERT_TRUE(test_it != test_maps.end());
@@ -1421,7 +1421,7 @@
#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"
-#define MAX_LEAK_BYTES 32*1024UL
+#define MAX_LEAK_BYTES (32*1024UL)
void CheckForLeak(pid_t pid, pid_t tid) {
// Do a few runs to get the PSS stable.
@@ -1445,9 +1445,9 @@
}
size_t new_pss = GetPssBytes();
ASSERT_TRUE(new_pss != 0);
- size_t abs_diff = (new_pss > stable_pss) ? new_pss - stable_pss : stable_pss - new_pss;
- // As long as the new pss is within a certain amount, consider everything okay.
- ASSERT_LE(abs_diff, MAX_LEAK_BYTES);
+ if (new_pss > stable_pss) {
+ ASSERT_LE(new_pss - stable_pss, MAX_LEAK_BYTES);
+ }
}
TEST(libbacktrace, check_for_leak_local) {
diff --git a/libbinderwrapper/real_binder_wrapper.cc b/libbinderwrapper/real_binder_wrapper.cc
index 1c51822..f93f183 100644
--- a/libbinderwrapper/real_binder_wrapper.cc
+++ b/libbinderwrapper/real_binder_wrapper.cc
@@ -29,7 +29,7 @@
// be awkward.
class RealBinderWrapper::DeathRecipient : public IBinder::DeathRecipient {
public:
- explicit DeathRecipient(const base::Closure& callback)
+ explicit DeathRecipient(const ::base::Closure& callback)
: callback_(callback) {}
~DeathRecipient() = default;
@@ -40,7 +40,7 @@
private:
// Callback to run in response to binder death.
- base::Closure callback_;
+ ::base::Closure callback_;
DISALLOW_COPY_AND_ASSIGN(DeathRecipient);
};
@@ -85,7 +85,7 @@
bool RealBinderWrapper::RegisterForDeathNotifications(
const sp<IBinder>& binder,
- const base::Closure& callback) {
+ const ::base::Closure& callback) {
sp<DeathRecipient> recipient(new DeathRecipient(callback));
if (binder->linkToDeath(recipient) != OK) {
LOG(ERROR) << "Failed to register for death notifications on "
diff --git a/libbinderwrapper/real_binder_wrapper.h b/libbinderwrapper/real_binder_wrapper.h
index ea08371..fa05383 100644
--- a/libbinderwrapper/real_binder_wrapper.h
+++ b/libbinderwrapper/real_binder_wrapper.h
@@ -17,6 +17,8 @@
#ifndef SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_
#define SYSTEM_CORE_LIBBINDERWRAPPER_REAL_BINDER_WRAPPER_H_
+#include <map>
+
#include <base/macros.h>
#include <binderwrapper/binder_wrapper.h>
@@ -36,7 +38,7 @@
const sp<IBinder>& binder) override;
sp<BBinder> CreateLocalBinder() override;
bool RegisterForDeathNotifications(const sp<IBinder>& binder,
- const base::Closure& callback) override;
+ const ::base::Closure& callback) override;
bool UnregisterForDeathNotifications(const sp<IBinder>& binder) override;
uid_t GetCallingUid() override;
pid_t GetCallingPid() override;
diff --git a/libbinderwrapper/stub_binder_wrapper.cc b/libbinderwrapper/stub_binder_wrapper.cc
index 87c6ab7..8e75f62 100644
--- a/libbinderwrapper/stub_binder_wrapper.cc
+++ b/libbinderwrapper/stub_binder_wrapper.cc
@@ -64,7 +64,7 @@
bool StubBinderWrapper::RegisterForDeathNotifications(
const sp<IBinder>& binder,
- const base::Closure& callback) {
+ const ::base::Closure& callback) {
death_callbacks_[binder] = callback;
return true;
}
diff --git a/libcrypto_utils/Android.mk b/libcrypto_utils/Android.mk
new file mode 100644
index 0000000..b6d2204
--- /dev/null
+++ b/libcrypto_utils/Android.mk
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcrypto
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_SHARED_LIBRARIES := libcrypto
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils_static
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcrypto
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrypto_utils_static
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_SRC_FILES := android_pubkey.c
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c99
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_STATIC_LIBRARIES := libcrypto_static
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcrypto_utils/android_pubkey.c b/libcrypto_utils/android_pubkey.c
new file mode 100644
index 0000000..3052e52
--- /dev/null
+++ b/libcrypto_utils/android_pubkey.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 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 <crypto_utils/android_pubkey.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+
+// Better safe than sorry.
+#if (ANDROID_PUBKEY_MODULUS_SIZE % 4) != 0
+#error RSA modulus size must be multiple of the word size!
+#endif
+
+// Size of the RSA modulus in words.
+#define ANDROID_PUBKEY_MODULUS_SIZE_WORDS (ANDROID_PUBKEY_MODULUS_SIZE / 4)
+
+// This file implements encoding and decoding logic for Android's custom RSA
+// public key binary format. Public keys are stored as a sequence of
+// little-endian 32 bit words. Note that Android only supports little-endian
+// processors, so we don't do any byte order conversions when parsing the binary
+// struct.
+typedef struct RSAPublicKey {
+ // Modulus length. This must be ANDROID_PUBKEY_MODULUS_SIZE.
+ uint32_t modulus_size_words;
+
+ // Precomputed montgomery parameter: -1 / n[0] mod 2^32
+ uint32_t n0inv;
+
+ // RSA modulus as a little-endian array.
+ uint8_t modulus[ANDROID_PUBKEY_MODULUS_SIZE];
+
+ // Montgomery parameter R^2 as a little-endian array of little-endian words.
+ uint8_t rr[ANDROID_PUBKEY_MODULUS_SIZE];
+
+ // RSA modulus: 3 or 65537
+ uint32_t exponent;
+} RSAPublicKey;
+
+// Reverses byte order in |buffer|.
+static void reverse_bytes(uint8_t* buffer, size_t size) {
+ for (size_t i = 0; i < (size + 1) / 2; ++i) {
+ uint8_t tmp = buffer[i];
+ buffer[i] = buffer[size - i - 1];
+ buffer[size - i - 1] = tmp;
+ }
+}
+
+bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key) {
+ const RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
+ bool ret = false;
+ uint8_t modulus_buffer[ANDROID_PUBKEY_MODULUS_SIZE];
+ RSA* new_key = RSA_new();
+ if (!new_key) {
+ goto cleanup;
+ }
+
+ // Check |size| is large enough and the modulus size is correct.
+ if (size < sizeof(RSAPublicKey)) {
+ goto cleanup;
+ }
+ if (key_struct->modulus_size_words != ANDROID_PUBKEY_MODULUS_SIZE_WORDS) {
+ goto cleanup;
+ }
+
+ // Convert the modulus to big-endian byte order as expected by BN_bin2bn.
+ memcpy(modulus_buffer, key_struct->modulus, sizeof(modulus_buffer));
+ reverse_bytes(modulus_buffer, sizeof(modulus_buffer));
+ new_key->n = BN_bin2bn(modulus_buffer, sizeof(modulus_buffer), NULL);
+ if (!new_key->n) {
+ goto cleanup;
+ }
+
+ // Read the exponent.
+ new_key->e = BN_new();
+ if (!new_key->e || !BN_set_word(new_key->e, key_struct->exponent)) {
+ goto cleanup;
+ }
+
+ // Note that we don't extract the montgomery parameters n0inv and rr from
+ // the RSAPublicKey structure. They assume a word size of 32 bits, but
+ // BoringSSL may use a word size of 64 bits internally, so we're lacking the
+ // top 32 bits of n0inv in general. For now, we just ignore the parameters
+ // and have BoringSSL recompute them internally. More sophisticated logic can
+ // be added here if/when we want the additional speedup from using the
+ // pre-computed montgomery parameters.
+
+ *key = new_key;
+ ret = true;
+
+cleanup:
+ if (!ret && new_key) {
+ RSA_free(new_key);
+ }
+ return ret;
+}
+
+static bool android_pubkey_encode_bignum(const BIGNUM* num, uint8_t* buffer) {
+ if (!BN_bn2bin_padded(buffer, ANDROID_PUBKEY_MODULUS_SIZE, num)) {
+ return false;
+ }
+
+ reverse_bytes(buffer, ANDROID_PUBKEY_MODULUS_SIZE);
+ return true;
+}
+
+bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size) {
+ RSAPublicKey* key_struct = (RSAPublicKey*)key_buffer;
+ bool ret = false;
+ BN_CTX* ctx = BN_CTX_new();
+ BIGNUM* r32 = BN_new();
+ BIGNUM* n0inv = BN_new();
+ BIGNUM* rr = BN_new();
+
+ if (sizeof(RSAPublicKey) > size ||
+ RSA_size(key) != ANDROID_PUBKEY_MODULUS_SIZE) {
+ goto cleanup;
+ }
+
+ // Store the modulus size.
+ key_struct->modulus_size_words = ANDROID_PUBKEY_MODULUS_SIZE_WORDS;
+
+ // Compute and store n0inv = -1 / N[0] mod 2^32.
+ if (!ctx || !r32 || !n0inv || !BN_set_bit(r32, 32) ||
+ !BN_mod(n0inv, key->n, r32, ctx) ||
+ !BN_mod_inverse(n0inv, n0inv, r32, ctx) || !BN_sub(n0inv, r32, n0inv)) {
+ goto cleanup;
+ }
+ key_struct->n0inv = (uint32_t)BN_get_word(n0inv);
+
+ // Store the modulus.
+ if (!android_pubkey_encode_bignum(key->n, key_struct->modulus)) {
+ goto cleanup;
+ }
+
+ // Compute and store rr = (2^(rsa_size)) ^ 2 mod N.
+ if (!ctx || !rr || !BN_set_bit(rr, ANDROID_PUBKEY_MODULUS_SIZE * 8) ||
+ !BN_mod_sqr(rr, rr, key->n, ctx) ||
+ !android_pubkey_encode_bignum(rr, key_struct->rr)) {
+ goto cleanup;
+ }
+
+ // Store the exponent.
+ key_struct->exponent = (uint32_t)BN_get_word(key->e);
+
+ ret = true;
+
+cleanup:
+ BN_free(rr);
+ BN_free(n0inv);
+ BN_free(r32);
+ BN_CTX_free(ctx);
+ return ret;
+}
diff --git a/libcrypto_utils/include/crypto_utils/android_pubkey.h b/libcrypto_utils/include/crypto_utils/android_pubkey.h
new file mode 100644
index 0000000..1045eba
--- /dev/null
+++ b/libcrypto_utils/include/crypto_utils/android_pubkey.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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 CRYPTO_UTILS_ANDROID_PUBKEY_H
+#define CRYPTO_UTILS_ANDROID_PUBKEY_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <openssl/rsa.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Size of an RSA modulus such as an encrypted block or a signature.
+#define ANDROID_PUBKEY_MODULUS_SIZE (2048 / 8)
+
+// Size of an encoded RSA key.
+#define ANDROID_PUBKEY_ENCODED_SIZE \
+ (3 * sizeof(uint32_t) + 2 * ANDROID_PUBKEY_MODULUS_SIZE)
+
+/* Allocates a new RSA |key| object, decodes a public RSA key stored in
+ * Android's custom binary format from |key_buffer| and sets the key parameters
+ * in |key|. |size| specifies the size of the key buffer and must be at least
+ * |ANDROID_PUBKEY_ENCODED_SIZE|. The resulting |*key| can be used with the
+ * standard BoringSSL API to perform public operations.
+ *
+ * Returns true if successful, in which case the caller receives ownership of
+ * the |*key| object, i.e. needs to call RSA_free() when done with it. If there
+ * is an error, |key| is left untouched and the return value will be false.
+ */
+bool android_pubkey_decode(const uint8_t* key_buffer, size_t size, RSA** key);
+
+/* Encodes |key| in the Android RSA public key binary format and stores the
+ * bytes in |key_buffer|. |key_buffer| should be of size at least
+ * |ANDROID_PUBKEY_ENCODED_SIZE|.
+ *
+ * Returns true if successful, false on error.
+ */
+bool android_pubkey_encode(const RSA* key, uint8_t* key_buffer, size_t size);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // CRYPTO_UTILS_ANDROID_PUBKEY_H
diff --git a/libmincrypt/tools/Android.mk b/libcrypto_utils/tests/Android.mk
similarity index 68%
rename from libmincrypt/tools/Android.mk
rename to libcrypto_utils/tests/Android.mk
index 3154914..bdaef71 100644
--- a/libmincrypt/tools/Android.mk
+++ b/libcrypto_utils/tests/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2008 The Android Open Source Project
+#
+# Copyright (C) 2016 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.
@@ -11,12 +12,13 @@
# 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.
+#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := dumpkey
-LOCAL_SRC_FILES := DumpPublicKey.java
-LOCAL_JAR_MANIFEST := DumpPublicKey.mf
-LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
-include $(BUILD_HOST_JAVA_LIBRARY)
+LOCAL_MODULE := libcrypto_utils_test
+LOCAL_SRC_FILES := android_pubkey_test.cpp
+LOCAL_CFLAGS := -Wall -Werror -Wextra -std=c++11
+LOCAL_SHARED_LIBRARIES := libcrypto_utils libcrypto
+include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcrypto_utils/tests/android_pubkey_test.cpp b/libcrypto_utils/tests/android_pubkey_test.cpp
new file mode 100644
index 0000000..f8c2e0c
--- /dev/null
+++ b/libcrypto_utils/tests/android_pubkey_test.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2016 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 <crypto_utils/android_pubkey.h>
+
+#include <string.h>
+
+#include <memory>
+
+#include <openssl/obj_mac.h>
+#include <openssl/rsa.h>
+
+#include <gtest/gtest.h>
+
+// Test digest to verify.
+const uint8_t kDigest[] = {
+ 0x31, 0x5f, 0x5b, 0xdb, 0x76, 0xd0, 0x78, 0xc4, 0x3b, 0x8a, 0xc0,
+ 0x06, 0x4e, 0x4a, 0x01, 0x64, 0x61, 0x2b, 0x1f, 0xce, 0x77, 0xc8,
+ 0x69, 0x34, 0x5b, 0xfc, 0x94, 0xc7, 0x58, 0x94, 0xed, 0xd3,
+};
+
+// 2048 RSA test key.
+const uint8_t kKey2048[ANDROID_PUBKEY_ENCODED_SIZE] = {
+ 0x40, 0x00, 0x00, 0x00, 0x05, 0x75, 0x61, 0xd1, 0x33, 0xf0, 0x2d, 0x12,
+ 0x45, 0xfb, 0xae, 0x07, 0x02, 0x15, 0x4f, 0x3a, 0x2b, 0xa3, 0xbc, 0x49,
+ 0xbd, 0x14, 0x07, 0xa0, 0xc0, 0x9f, 0x0c, 0x52, 0x60, 0x77, 0x9f, 0xa2,
+ 0x31, 0xd0, 0xa7, 0xfb, 0x7e, 0xde, 0xfb, 0xc9, 0x05, 0xc0, 0x97, 0xf7,
+ 0x74, 0x99, 0xe6, 0xd1, 0x08, 0xa6, 0xc2, 0x59, 0x5a, 0xd8, 0x37, 0x1d,
+ 0xe0, 0x48, 0x5e, 0x63, 0x44, 0x04, 0x8b, 0x05, 0x20, 0xf6, 0x25, 0x67,
+ 0x38, 0xb2, 0xb6, 0xf9, 0xbe, 0xb6, 0x1d, 0x7f, 0x1b, 0x71, 0x8a, 0xeb,
+ 0xb7, 0xf8, 0x01, 0xc1, 0x5e, 0xf7, 0xfe, 0x48, 0x08, 0x27, 0x0f, 0x27,
+ 0x2a, 0x64, 0x1a, 0x43, 0x8d, 0xcf, 0x5a, 0x33, 0x5c, 0x18, 0xc5, 0xf4,
+ 0xe7, 0xfe, 0xee, 0xd3, 0x12, 0x62, 0xad, 0x61, 0x78, 0x9a, 0x03, 0xb0,
+ 0xaf, 0xab, 0x91, 0x57, 0x46, 0xbf, 0x18, 0xc6, 0xbc, 0x0c, 0x6b, 0x55,
+ 0xcd, 0xda, 0xc4, 0xcc, 0x98, 0x46, 0x91, 0x99, 0xbc, 0xa3, 0xca, 0x6c,
+ 0x86, 0xa6, 0x1c, 0x8f, 0xca, 0xf8, 0xf6, 0x8a, 0x00, 0x8e, 0x05, 0xd7,
+ 0x13, 0x43, 0xe2, 0xf2, 0x1a, 0x13, 0xf3, 0x50, 0x13, 0xa4, 0xf2, 0x4e,
+ 0x41, 0xb1, 0x36, 0x78, 0x55, 0x4c, 0x5e, 0x27, 0xc5, 0xc0, 0x4b, 0xd8,
+ 0x93, 0xaa, 0x7e, 0xf0, 0x90, 0x08, 0x10, 0x26, 0x72, 0x6d, 0xb9, 0x21,
+ 0xae, 0x4d, 0x01, 0x4b, 0x55, 0x1d, 0xe7, 0x1e, 0x5e, 0x31, 0x6e, 0x62,
+ 0xd1, 0x33, 0x26, 0xcb, 0xdb, 0xfe, 0x72, 0x98, 0xc8, 0x06, 0x1c, 0x12,
+ 0xdf, 0xfc, 0x74, 0xe5, 0x7a, 0x6f, 0xf5, 0xa3, 0x63, 0x08, 0xe3, 0x02,
+ 0x68, 0x4d, 0x7c, 0x70, 0x05, 0xec, 0x95, 0x7e, 0x24, 0xa4, 0xbc, 0x4c,
+ 0xcd, 0x39, 0x14, 0xb5, 0x2a, 0x8f, 0xc1, 0xe3, 0x4e, 0xfa, 0xf8, 0x70,
+ 0x50, 0x8f, 0xd5, 0x8e, 0xc7, 0xb5, 0x32, 0x89, 0x4d, 0xbb, 0x6a, 0xc1,
+ 0xc1, 0xa2, 0x42, 0x57, 0x57, 0xbd, 0x2a, 0xdc, 0xa6, 0xfd, 0xc8, 0x86,
+ 0x44, 0x6a, 0x03, 0x5d, 0x4d, 0x28, 0xe1, 0xde, 0xb4, 0xa9, 0xa5, 0x03,
+ 0x61, 0x7a, 0x5f, 0xb1, 0x09, 0x17, 0x2b, 0x9c, 0xa2, 0x54, 0x28, 0xad,
+ 0x34, 0xc9, 0x5f, 0x6c, 0x9f, 0xb8, 0xd2, 0xa9, 0x78, 0xa7, 0xaa, 0xb3,
+ 0x11, 0x2f, 0x65, 0x9b, 0x4e, 0x67, 0x0c, 0xcc, 0x20, 0x36, 0xbf, 0x26,
+ 0x2b, 0x4e, 0xc0, 0xd4, 0xbd, 0x22, 0x64, 0xc4, 0x1c, 0x56, 0x69, 0xdb,
+ 0x5f, 0x89, 0xe1, 0x75, 0x68, 0x8d, 0x0e, 0xab, 0x1c, 0x10, 0x1a, 0xc0,
+ 0x12, 0x5d, 0x6f, 0xbd, 0x09, 0xbb, 0x47, 0xcb, 0xe7, 0x34, 0xef, 0x56,
+ 0xab, 0xea, 0xc3, 0xe9, 0x7f, 0x9a, 0x3d, 0xe9, 0x2d, 0x14, 0x61, 0x25,
+ 0x37, 0x5c, 0x3b, 0x4b, 0xaf, 0x5a, 0x4b, 0xc8, 0x99, 0x1a, 0x32, 0x8f,
+ 0x54, 0x07, 0xd3, 0x57, 0x8a, 0x3d, 0x2a, 0xf7, 0x9e, 0x7e, 0x92, 0x2a,
+ 0x50, 0xe9, 0xd8, 0xdb, 0xd6, 0x03, 0xd3, 0x8e, 0x54, 0x32, 0xce, 0x87,
+ 0x93, 0x92, 0xe7, 0x75, 0xe1, 0x6b, 0x78, 0x1a, 0x85, 0xc2, 0x46, 0xa1,
+ 0x31, 0xbb, 0xc7, 0xb9, 0x1d, 0xd1, 0x71, 0xe0, 0xe2, 0x9b, 0x9c, 0x0d,
+ 0xa3, 0xcf, 0x93, 0x4d, 0x87, 0x7b, 0x65, 0xd9, 0xda, 0x4c, 0xd9, 0x6a,
+ 0xa6, 0x36, 0xc2, 0xc7, 0xe3, 0x33, 0xe2, 0xc3, 0x83, 0xd1, 0x72, 0x54,
+ 0x30, 0x81, 0x5e, 0x34, 0x2c, 0x61, 0xee, 0xf4, 0x48, 0x97, 0xb6, 0xaa,
+ 0x47, 0x6a, 0x05, 0x09, 0xd8, 0x4d, 0x90, 0xaf, 0xa8, 0x4e, 0x82, 0xe4,
+ 0x8e, 0xb5, 0xe2, 0x65, 0x86, 0x67, 0xe9, 0x5b, 0x4b, 0x9a, 0x68, 0x08,
+ 0x30, 0xf6, 0x25, 0x8b, 0x20, 0xda, 0x26, 0x6f, 0xbd, 0x0d, 0xa5, 0xd8,
+ 0x6a, 0x7b, 0x01, 0x2f, 0xab, 0x7b, 0xb5, 0xfe, 0x62, 0x37, 0x2d, 0x94,
+ 0x43, 0x2f, 0x4d, 0x16, 0x01, 0x00, 0x01, 0x00,
+};
+
+// 2048 bit RSA signature.
+const uint8_t kSignature2048[ANDROID_PUBKEY_MODULUS_SIZE] = {
+ 0x3a, 0x11, 0x84, 0x40, 0xc1, 0x2f, 0x13, 0x8c, 0xde, 0xb0, 0xc3, 0x89,
+ 0x8a, 0x63, 0xb2, 0x50, 0x93, 0x58, 0xc0, 0x0c, 0xb7, 0x08, 0xe7, 0x6c,
+ 0x52, 0x87, 0x4e, 0x78, 0x89, 0xa3, 0x9a, 0x47, 0xeb, 0x11, 0x57, 0xbc,
+ 0xb3, 0x97, 0xf8, 0x34, 0xf1, 0xf7, 0xbf, 0x3a, 0xfa, 0x1c, 0x6b, 0xdc,
+ 0xd1, 0x02, 0xde, 0x9a, 0x0d, 0x72, 0xe7, 0x19, 0x63, 0x81, 0x46, 0x68,
+ 0x1e, 0x63, 0x64, 0xc6, 0x59, 0xe7, 0x7c, 0x39, 0xed, 0x32, 0xd2, 0xd1,
+ 0xd5, 0x1f, 0x13, 0x9b, 0x52, 0xdf, 0x34, 0xa3, 0xc0, 0xc4, 0x9a, 0x63,
+ 0x9b, 0x9c, 0xbe, 0x22, 0xc8, 0xd8, 0x14, 0x2f, 0x4c, 0x78, 0x36, 0xdb,
+ 0x16, 0x41, 0x67, 0xc1, 0x21, 0x8a, 0x73, 0xb2, 0xe5, 0xb0, 0xd3, 0x80,
+ 0x91, 0x7a, 0xbf, 0xf9, 0x59, 0x4a, 0x4d, 0x78, 0x45, 0x44, 0xa1, 0x52,
+ 0x86, 0x29, 0x48, 0x4d, 0xf0, 0x5d, 0xf2, 0x55, 0xa7, 0xcd, 0xc5, 0x2b,
+ 0x7b, 0xe0, 0xb1, 0xf6, 0x2a, 0xd5, 0x61, 0xba, 0x1e, 0x1e, 0x3a, 0xf0,
+ 0x55, 0xbc, 0x8c, 0x44, 0x41, 0xfc, 0xb8, 0x8c, 0x76, 0xbf, 0x80, 0x58,
+ 0x82, 0x35, 0x4b, 0x0c, 0xfd, 0xef, 0xd5, 0x70, 0xd1, 0x64, 0xcb, 0x46,
+ 0x58, 0x37, 0xbc, 0xa9, 0x7d, 0xd4, 0x70, 0xac, 0xce, 0xec, 0xca, 0x48,
+ 0xcb, 0x0a, 0x40, 0x77, 0x04, 0x59, 0xca, 0x9c, 0x7d, 0x1a, 0x0b, 0xf0,
+ 0xb5, 0xdd, 0xde, 0x71, 0x18, 0xb8, 0xef, 0x90, 0x2a, 0x09, 0x42, 0x39,
+ 0x74, 0xff, 0x45, 0xa1, 0x39, 0x17, 0x50, 0x89, 0xa6, 0x5f, 0xbc, 0x9c,
+ 0x0c, 0x9b, 0x47, 0x25, 0x79, 0x3e, 0xe3, 0xaa, 0xaf, 0xbe, 0x73, 0x6b,
+ 0xcb, 0xe7, 0x35, 0xc1, 0x27, 0x09, 0xcd, 0xeb, 0xd7, 0xcf, 0x63, 0x83,
+ 0x64, 0x8c, 0x45, 0x1c, 0x1d, 0x58, 0xcc, 0xd2, 0xf8, 0x2b, 0x4c, 0x4e,
+ 0x14, 0x89, 0x2d, 0x70,
+};
+
+struct AndroidPubkeyTest : public ::testing::Test {
+ void SetUp() override {
+ RSA* new_key = nullptr;
+ ASSERT_TRUE(android_pubkey_decode(kKey2048, sizeof(kKey2048), &new_key));
+ key_.reset(new_key);
+ }
+
+ std::unique_ptr<RSA, void(*)(RSA*)> key_ = {nullptr, RSA_free};
+};
+
+TEST_F(AndroidPubkeyTest, Decode) {
+ // Make sure the decoded key successfully verifies a valid signature.
+ EXPECT_TRUE(RSA_verify(NID_sha256, kDigest, sizeof(kDigest), kSignature2048,
+ sizeof(kSignature2048), key_.get()));
+}
+
+TEST_F(AndroidPubkeyTest, Encode) {
+ uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+ ASSERT_TRUE(android_pubkey_encode(key_.get(), key_data, sizeof(key_data)));
+ ASSERT_EQ(0, memcmp(kKey2048, key_data, sizeof(kKey2048)));
+}
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
new file mode 100644
index 0000000..4f26034
--- /dev/null
+++ b/libcutils/Android.bp
@@ -0,0 +1,155 @@
+//
+// 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.
+//
+
+// some files must not be compiled when building against Mingw
+// they correspond to features not used by our host development tools
+// which are also hard or even impossible to port to native Win32
+libcutils_nonwindows_sources = [
+ "fs.c",
+ "multiuser.c",
+ "socket_inaddr_any_server_unix.c",
+ "socket_local_client_unix.c",
+ "socket_local_server_unix.c",
+ "socket_loopback_client_unix.c",
+ "socket_loopback_server_unix.c",
+ "socket_network_client_unix.c",
+ "sockets_unix.cpp",
+ "str_parms.c",
+]
+
+cc_library {
+ name: "libcutils",
+ host_supported: true,
+ srcs: [
+ "config_utils.c",
+ "fs_config.c",
+ "canned_fs_config.c",
+ "hashmap.c",
+ "iosched_policy.c",
+ "load_file.c",
+ "native_handle.c",
+ "open_memstream.c",
+ "process_name.c",
+ "record_stream.c",
+ "sched_policy.c",
+ "sockets.cpp",
+ "strdup16to8.c",
+ "strdup8to16.c",
+ "strlcpy.c",
+ "threads.c",
+ ],
+
+ target: {
+ host: {
+ srcs: ["dlmalloc_stubs.c"],
+ },
+ not_windows: {
+ srcs: libcutils_nonwindows_sources + [
+ "ashmem-host.c",
+ "trace-host.c",
+ ],
+ },
+ windows: {
+ srcs: [
+ "socket_inaddr_any_server_windows.c",
+ "socket_network_client_windows.c",
+ "sockets_windows.cpp",
+ ],
+
+ enabled: true,
+ shared: {
+ enabled: false,
+ },
+ },
+
+ android: {
+ srcs: libcutils_nonwindows_sources + [
+ "android_reboot.c",
+ "ashmem-dev.c",
+ "debugger.c",
+ "klog.cpp",
+ "partition_utils.c",
+ "properties.c",
+ "qtaguid.c",
+ "trace-dev.c",
+ "uevent.c",
+ ],
+
+ // TODO: remove liblog as whole static library, once we don't have prebuilt that requires
+ // liblog symbols present in libcutils.
+ whole_static_libs: [
+ "liblog",
+ ],
+
+ static_libs: ["libdebuggerd_client"],
+ export_static_lib_headers: ["libdebuggerd_client"],
+
+ cflags: [
+ "-std=gnu90",
+ ],
+ },
+
+ android_arm: {
+ srcs: ["arch-arm/memset32.S"],
+ },
+ android_arm64: {
+ srcs: ["arch-arm64/android_memset.S"],
+ },
+
+ android_mips: {
+ srcs: ["arch-mips/android_memset.c"],
+ },
+ android_mips64: {
+ srcs: ["arch-mips/android_memset.c"],
+ },
+
+ android_x86: {
+ srcs: [
+ "arch-x86/android_memset16.S",
+ "arch-x86/android_memset32.S",
+ ],
+ },
+
+ android_x86_64: {
+ srcs: [
+ "arch-x86_64/android_memset16.S",
+ "arch-x86_64/android_memset32.S",
+ ],
+ },
+ },
+
+ shared_libs: ["liblog"],
+ product_variables: {
+ cpusets: {
+ cflags: ["-DUSE_CPUSETS"],
+ },
+ schedboost: {
+ cflags: ["-DUSE_SCHEDBOOST"],
+ },
+ },
+ cflags: [
+ "-Werror",
+ "-Wall",
+ "-Wextra",
+ ],
+
+ clang: true,
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+}
+
+subdirs = ["tests"]
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
deleted file mode 100644
index 0c6e5a1..0000000
--- a/libcutils/Android.mk
+++ /dev/null
@@ -1,151 +0,0 @@
-#
-# 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.
-#
-LOCAL_PATH := $(my-dir)
-include $(CLEAR_VARS)
-
-libcutils_common_sources := \
- atomic.c.arm \
- config_utils.c \
- fs_config.c \
- canned_fs_config.c \
- hashmap.c \
- iosched_policy.c \
- load_file.c \
- native_handle.c \
- open_memstream.c \
- process_name.c \
- record_stream.c \
- sched_policy.c \
- sockets.cpp \
- strdup16to8.c \
- strdup8to16.c \
- strlcpy.c \
- threads.c \
-
-# some files must not be compiled when building against Mingw
-# they correspond to features not used by our host development tools
-# which are also hard or even impossible to port to native Win32
-libcutils_nonwindows_sources := \
- fs.c \
- multiuser.c \
- socket_inaddr_any_server_unix.c \
- socket_local_client_unix.c \
- socket_local_server_unix.c \
- socket_loopback_client_unix.c \
- socket_loopback_server_unix.c \
- socket_network_client_unix.c \
- sockets_unix.cpp \
- str_parms.c \
-
-libcutils_nonwindows_host_sources := \
- ashmem-host.c \
- trace-host.c \
-
-libcutils_windows_host_sources := \
- socket_inaddr_any_server_windows.c \
- socket_network_client_windows.c \
- sockets_windows.cpp \
-
-# Shared and static library for host
-# Note: when linking this library on Windows, you must also link to Winsock2
-# using "LOCAL_LDLIBS_windows := -lws2_32".
-# ========================================================
-LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SRC_FILES_windows := $(libcutils_windows_host_sources)
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror -Wall -Wextra
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(libcutils_common_sources) dlmalloc_stubs.c
-LOCAL_SRC_FILES_darwin := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SRC_FILES_linux := $(libcutils_nonwindows_sources) $(libcutils_nonwindows_host_sources)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror -Wall -Wextra
-LOCAL_MULTILIB := both
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-
-# Shared and static library for target
-# ========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils
-LOCAL_SRC_FILES := $(libcutils_common_sources) \
- $(libcutils_nonwindows_sources) \
- android_reboot.c \
- ashmem-dev.c \
- debugger.c \
- klog.c \
- partition_utils.c \
- properties.c \
- qtaguid.c \
- trace-dev.c \
- uevent.c \
-
-LOCAL_SRC_FILES_arm += arch-arm/memset32.S
-LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
-
-LOCAL_SRC_FILES_mips += arch-mips/android_memset.c
-LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.c
-
-LOCAL_SRC_FILES_x86 += \
- arch-x86/android_memset16.S \
- arch-x86/android_memset32.S \
-
-LOCAL_SRC_FILES_x86_64 += \
- arch-x86_64/android_memset16.S \
- arch-x86_64/android_memset32.S \
-
-LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_STATIC_LIBRARIES := liblog
-ifneq ($(ENABLE_CPUSETS),)
-LOCAL_CFLAGS += -DUSE_CPUSETS
-endif
-ifneq ($(ENABLE_SCHEDBOOST),)
-LOCAL_CFLAGS += -DUSE_SCHEDBOOST
-endif
-LOCAL_CFLAGS += -Werror -Wall -Wextra -std=gnu90
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils
-# TODO: remove liblog as whole static library, once we don't have prebuilt that requires
-# liblog symbols present in libcutils.
-LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
-LOCAL_SHARED_LIBRARIES := liblog
-ifneq ($(ENABLE_CPUSETS),)
-LOCAL_CFLAGS += -DUSE_CPUSETS
-endif
-ifneq ($(ENABLE_SCHEDBOOST),)
-LOCAL_CFLAGS += -DUSE_SCHEDBOOST
-endif
-LOCAL_CFLAGS += -Werror -Wall -Wextra
-LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index c85f06b..1f9f753 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -62,12 +62,12 @@
int ashmem_pin_region(int fd __unused, size_t offset __unused, size_t len __unused)
{
- return ASHMEM_NOT_PURGED;
+ return 0 /*ASHMEM_NOT_PURGED*/;
}
int ashmem_unpin_region(int fd __unused, size_t offset __unused, size_t len __unused)
{
- return ASHMEM_IS_UNPINNED;
+ return 0 /*ASHMEM_IS_UNPINNED*/;
}
int ashmem_get_size_region(int fd)
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
index 5800857..e0e6a34 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.c
@@ -14,22 +14,22 @@
* limitations under the License.
*/
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <private/android_filesystem_config.h>
#include <private/canned_fs_config.h>
typedef struct {
- const char* path;
- unsigned uid;
- unsigned gid;
- unsigned mode;
- uint64_t capabilities;
+ const char* path;
+ unsigned uid;
+ unsigned gid;
+ unsigned mode;
+ uint64_t capabilities;
} Path;
static Path* canned_data = NULL;
@@ -37,81 +37,87 @@
static int canned_used = 0;
static int path_compare(const void* a, const void* b) {
- return strcmp(((Path*)a)->path, ((Path*)b)->path);
+ return strcmp(((Path*)a)->path, ((Path*)b)->path);
}
int load_canned_fs_config(const char* fn) {
- FILE* f = fopen(fn, "r");
- if (f == NULL) {
- fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
- return -1;
- }
+ char line[PATH_MAX + 200];
+ FILE* f;
- char line[PATH_MAX + 200];
- while (fgets(line, sizeof(line), f)) {
- while (canned_used >= canned_alloc) {
- canned_alloc = (canned_alloc+1) * 2;
- canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
- }
- Path* p = canned_data + canned_used;
- p->path = strdup(strtok(line, " "));
- p->uid = atoi(strtok(NULL, " "));
- p->gid = atoi(strtok(NULL, " "));
- p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal
- p->capabilities = 0;
+ f = fopen(fn, "r");
+ if (f == NULL) {
+ fprintf(stderr, "failed to open %s: %s\n", fn, strerror(errno));
+ return -1;
+ }
- char* token = NULL;
- do {
- token = strtok(NULL, " ");
- if (token && strncmp(token, "capabilities=", 13) == 0) {
- p->capabilities = strtoll(token+13, NULL, 0);
- break;
- }
- } while (token);
+ while (fgets(line, sizeof(line), f)) {
+ Path* p;
+ char* token;
- canned_used++;
- }
+ while (canned_used >= canned_alloc) {
+ canned_alloc = (canned_alloc+1) * 2;
+ canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
+ }
+ p = canned_data + canned_used;
+ p->path = strdup(strtok(line, " "));
+ p->uid = atoi(strtok(NULL, " "));
+ p->gid = atoi(strtok(NULL, " "));
+ p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal
+ p->capabilities = 0;
- fclose(f);
+ do {
+ token = strtok(NULL, " ");
+ if (token && strncmp(token, "capabilities=", 13) == 0) {
+ p->capabilities = strtoll(token+13, NULL, 0);
+ break;
+ }
+ } while (token);
- qsort(canned_data, canned_used, sizeof(Path), path_compare);
- printf("loaded %d fs_config entries\n", canned_used);
+ canned_used++;
+ }
- return 0;
+ fclose(f);
+
+ qsort(canned_data, canned_used, sizeof(Path), path_compare);
+ printf("loaded %d fs_config entries\n", canned_used);
+
+ return 0;
}
static const int kDebugCannedFsConfig = 0;
void canned_fs_config(const char* path, int dir, const char* target_out_path,
- unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
- Path key;
+ unsigned* uid, unsigned* gid, unsigned* mode, uint64_t* capabilities) {
+ Path key, *p;
+
key.path = path;
- if (path[0] == '/')
- key.path++; // canned paths lack the leading '/'
- Path* p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
- if (p == NULL) {
- fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
- exit(1);
- }
- *uid = p->uid;
- *gid = p->gid;
- *mode = p->mode;
- *capabilities = p->capabilities;
+ if (path[0] == '/') key.path++; // canned paths lack the leading '/'
+ p = (Path*) bsearch(&key, canned_data, canned_used, sizeof(Path), path_compare);
+ if (p == NULL) {
+ fprintf(stderr, "failed to find [%s] in canned fs_config\n", path);
+ exit(1);
+ }
+ *uid = p->uid;
+ *gid = p->gid;
+ *mode = p->mode;
+ *capabilities = p->capabilities;
- if (kDebugCannedFsConfig) {
- // for debugging, run the built-in fs_config and compare the results.
+ if (kDebugCannedFsConfig) {
+ // for debugging, run the built-in fs_config and compare the results.
- unsigned c_uid, c_gid, c_mode;
- uint64_t c_capabilities;
- fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
+ unsigned c_uid, c_gid, c_mode;
+ uint64_t c_capabilities;
- if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
- if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
- if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
- if (c_capabilities != *capabilities)
- printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
- path,
- *capabilities,
- c_capabilities);
+ fs_config(path, dir, target_out_path, &c_uid, &c_gid, &c_mode, &c_capabilities);
+
+ if (c_uid != *uid) printf("%s uid %d %d\n", path, *uid, c_uid);
+ if (c_gid != *gid) printf("%s gid %d %d\n", path, *gid, c_gid);
+ if (c_mode != *mode) printf("%s mode 0%o 0%o\n", path, *mode, c_mode);
+ if (c_capabilities != *capabilities) {
+ printf("%s capabilities %" PRIx64 " %" PRIx64 "\n",
+ path,
+ *capabilities,
+ c_capabilities);
}
+ }
}
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 71bc94b..13c2ceb 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -24,7 +24,8 @@
#include <cutils/iosched_policy.h>
#if defined(__ANDROID__)
-#include <linux/ioprio.h>
+#define IOPRIO_WHO_PROCESS (1)
+#define IOPRIO_CLASS_SHIFT (13)
#include <sys/syscall.h>
#define __android_unused
#else
diff --git a/libcutils/klog.c b/libcutils/klog.cpp
similarity index 77%
rename from libcutils/klog.c
rename to libcutils/klog.cpp
index 7402903..061af1b 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.cpp
@@ -26,7 +26,6 @@
#include <cutils/klog.h>
-static int klog_fd = -1;
static int klog_level = KLOG_DEFAULT_LEVEL;
int klog_get_level(void) {
@@ -37,32 +36,23 @@
klog_level = level;
}
-void klog_init(void) {
- if (klog_fd >= 0) return; /* Already initialized */
-
- klog_fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
- if (klog_fd >= 0) {
- return;
- }
-
- static const char* name = "/dev/__kmsg__";
- if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
- klog_fd = open(name, O_WRONLY | O_CLOEXEC);
- unlink(name);
- }
+static int __open_klog(void) {
+ return TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC));
}
#define LOG_BUF_MAX 512
void klog_writev(int level, const struct iovec* iov, int iov_count) {
if (level > klog_level) return;
- if (klog_fd < 0) klog_init();
- if (klog_fd < 0) return;
+
+ static int klog_fd = __open_klog();
+ if (klog_fd == -1) return;
TEMP_FAILURE_RETRY(writev(klog_fd, iov, iov_count));
}
void klog_write(int level, const char* fmt, ...) {
if (level > klog_level) return;
+
char buf[LOG_BUF_MAX];
va_list ap;
va_start(ap, fmt);
diff --git a/libcutils/qtaguid.c b/libcutils/qtaguid.c
index 2fbe02e..dcd16ef 100644
--- a/libcutils/qtaguid.c
+++ b/libcutils/qtaguid.c
@@ -47,10 +47,7 @@
/* Only call once per process. */
void qtaguid_resTrack(void) {
- resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY));
- if (resTrackFd >=0) {
- TEMP_FAILURE_RETRY(fcntl(resTrackFd, F_SETFD, FD_CLOEXEC));
- }
+ resTrackFd = TEMP_FAILURE_RETRY(open("/dev/xt_qtaguid", O_RDONLY | O_CLOEXEC));
}
/*
@@ -63,7 +60,7 @@
ALOGV("write_ctrl(%s)", cmd);
- fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY));
+ fd = TEMP_FAILURE_RETRY(open(CTRL_PROCPATH, O_WRONLY | O_CLOEXEC));
if (fd < 0) {
return -errno;
}
@@ -86,7 +83,7 @@
int param_fd;
int res;
- param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY));
+ param_fd = TEMP_FAILURE_RETRY(open(param_path, O_WRONLY | O_CLOEXEC));
if (param_fd < 0) {
return -errno;
}
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 05a2048..26f908f 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -171,7 +171,7 @@
FILE *fp;
snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
- if (!(fp = fopen(pathBuf, "r"))) {
+ if (!(fp = fopen(pathBuf, "re"))) {
return -1;
}
@@ -329,6 +329,27 @@
#endif
}
+static void set_timerslack_ns(int tid, unsigned long long slack) {
+ char buf[64];
+
+ /* v4.6+ kernels support the /proc/<tid>/timerslack_ns interface. */
+ snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", tid);
+ int fd = open(buf, O_WRONLY | O_CLOEXEC);
+ if (fd != -1) {
+ int len = snprintf(buf, sizeof(buf), "%llu", slack);
+ if (write(fd, buf, len) != len) {
+ SLOGE("set_timerslack_ns write failed: %s\n", strerror(errno));
+ }
+ close(fd);
+ return;
+ }
+
+ /* If the above fails, try the old common.git PR_SET_TIMERSLACK_PID. */
+ if (prctl(PR_SET_TIMERSLACK_PID, slack, tid) == -1) {
+ SLOGE("set_timerslack_ns prctl failed: %s\n", strerror(errno));
+ }
+}
+
int set_sched_policy(int tid, SchedPolicy policy)
{
if (tid == 0) {
@@ -341,12 +362,11 @@
char statfile[64];
char statline[1024];
char thread_name[255];
- int fd;
- sprintf(statfile, "/proc/%d/stat", tid);
+ snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid);
memset(thread_name, 0, sizeof(thread_name));
- fd = open(statfile, O_RDONLY);
+ int fd = open(statfile, O_RDONLY | O_CLOEXEC);
if (fd >= 0) {
int rc = read(fd, statline, 1023);
close(fd);
@@ -425,8 +445,8 @@
¶m);
}
- prctl(PR_SET_TIMERSLACK_PID,
- policy == SP_BACKGROUND ? TIMER_SLACK_BG : TIMER_SLACK_FG, tid);
+ set_timerslack_ns(tid, policy == SP_BACKGROUND ?
+ TIMER_SLACK_BG : TIMER_SLACK_FG);
return 0;
}
diff --git a/libcutils/strdup8to16.c b/libcutils/strdup8to16.c
index 63e5ca4..c23cf8b 100644
--- a/libcutils/strdup8to16.c
+++ b/libcutils/strdup8to16.c
@@ -27,7 +27,7 @@
#define UTF16_REPLACEMENT_CHAR 0xfffd
/* Clever trick from Dianne that returns 1-4 depending on leading bit sequence*/
-#define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> ((ch >> 3) & 0x1e)) & 3) + 1)
+#define UTF8_SEQ_LENGTH(ch) (((0xe5000000 >> (((ch) >> 3) & 0x1e)) & 3) + 1)
/* note: macro expands to multiple lines */
#define UTF8_SHIFT_AND_MASK(unicode, byte) \
diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp
new file mode 100644
index 0000000..530c747
--- /dev/null
+++ b/libcutils/tests/Android.bp
@@ -0,0 +1,72 @@
+// Copyright (C) 2014 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.
+
+cc_defaults {
+ name: "libcutils_test_default",
+ srcs: ["sockets_test.cpp"],
+
+ target: {
+ android: {
+ srcs: [
+ "MemsetTest.cpp",
+ "PropertiesTest.cpp",
+ "trace-dev_test.cpp",
+ ],
+ },
+
+ not_windows: {
+ srcs: ["test_str_parms.cpp"],
+ },
+ },
+
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+}
+
+test_libraries = [
+ "libcutils",
+ "liblog",
+ "libbase",
+]
+
+cc_test {
+ name: "libcutils_test",
+ defaults: ["libcutils_test_default"],
+ host_supported: true,
+ shared_libs: test_libraries,
+}
+
+cc_test {
+ name: "libcutils_test_static",
+ defaults: ["libcutils_test_default"],
+ static_libs: ["libc"] + test_libraries,
+ stl: "libc++_static",
+
+ target: {
+ android: {
+ static_executable: true,
+ },
+ windows: {
+ host_ldlibs: ["-lws2_32"],
+
+ enabled: true,
+ },
+ },
+}
diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk
deleted file mode 100644
index 52cf5f4..0000000
--- a/libcutils/tests/Android.mk
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH := $(call my-dir)
-
-test_src_files := \
- sockets_test.cpp \
-
-test_src_files_nonwindows := \
- test_str_parms.cpp \
-
-test_target_only_src_files := \
- MemsetTest.cpp \
- PropertiesTest.cpp \
- trace-dev_test.cpp \
-
-test_libraries := libcutils liblog libbase
-
-
-#
-# Target.
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test
-LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
-LOCAL_SHARED_LIBRARIES := $(test_libraries)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test_static
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SRC_FILES := $(test_src_files) $(test_target_only_src_files)
-LOCAL_STATIC_LIBRARIES := libc $(test_libraries)
-LOCAL_CXX_STL := libc++_static
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_NATIVE_TEST)
-
-
-#
-# Host.
-#
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test
-LOCAL_SRC_FILES := $(test_src_files) $(test_src_files_nonwindows)
-LOCAL_SHARED_LIBRARIES := $(test_libraries)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-include $(BUILD_HOST_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libcutils_test_static
-LOCAL_SRC_FILES := $(test_src_files)
-LOCAL_SRC_FILES_darwin := $(test_src_files_nonwindows)
-LOCAL_SRC_FILES_linux := $(test_src_files_nonwindows)
-LOCAL_STATIC_LIBRARIES := $(test_libraries)
-LOCAL_LDLIBS_windows := -lws2_32
-LOCAL_CXX_STL := libc++_static
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
-LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
index 659821c..f66590b 100644
--- a/libcutils/tests/PropertiesTest.cpp
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -15,7 +15,7 @@
*/
#define LOG_TAG "Properties_test"
-#include <utils/Log.h>
+#include <cutils/log.h>
#include <gtest/gtest.h>
#include <cutils/properties.h>
@@ -24,11 +24,12 @@
#include <sstream>
#include <iostream>
+#include <android-base/macros.h>
+
namespace android {
#define STRINGIFY_INNER(x) #x
#define STRINGIFY(x) STRINGIFY_INNER(x)
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#define ASSERT_OK(x) ASSERT_EQ(0, (x))
#define EXPECT_OK(x) EXPECT_EQ(0, (x))
@@ -85,7 +86,7 @@
}
void ResetValue(unsigned char c = 0xFF) {
- for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) {
+ for (size_t i = 0; i < arraysize(mValue); ++i) {
mValue[i] = (char) c;
}
}
@@ -106,14 +107,14 @@
ResetValue();
// Since the value is null, default value will be returned
- int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+ size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len);
EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue);
}
// Trivial case => get returns what was set
{
- int len = SetAndGetProperty("hello_world");
+ size_t len = SetAndGetProperty("hello_world");
EXPECT_EQ(strlen("hello_world"), len) << "hello_world key";
EXPECT_STREQ("hello_world", mValue);
ResetValue();
@@ -122,7 +123,7 @@
// Set to empty string => get returns default always
{
const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING";
- int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
+ size_t len = SetAndGetProperty("", EMPTY_STRING_DEFAULT);
EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key";
EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue);
ResetValue();
@@ -147,7 +148,7 @@
// Expect that the value set fails since it's too long
EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str()));
- int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
+ size_t len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT);
EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed";
EXPECT_STREQ(VALID_TEST_VALUE, mValue);
@@ -177,7 +178,7 @@
* TRUE
*/
const char *valuesTrue[] = { "1", "true", "y", "yes", "on", };
- for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) {
+ for (size_t i = 0; i < arraysize(valuesTrue); ++i) {
ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i]));
bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false);
EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'";
@@ -187,7 +188,7 @@
* FALSE
*/
const char *valuesFalse[] = { "0", "false", "n", "no", "off", };
- for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) {
+ for (size_t i = 0; i < arraysize(valuesFalse); ++i) {
ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i]));
bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true);
EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'";
@@ -200,7 +201,7 @@
"+1", " 1 ", " true", " true ", " y ", " yes", "yes ",
"+0", "-0", "00", " 00 ", " false", "false ",
};
- for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) {
+ for (size_t i = 0; i < arraysize(valuesNeither); ++i) {
ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i]));
// The default value should always be used
@@ -249,9 +250,9 @@
DEFAULT_VALUE, DEFAULT_VALUE,
};
- ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+ ASSERT_EQ(arraysize(setValues), arraysize(getValues));
- for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+ for (size_t i = 0; i < arraysize(setValues); ++i) {
ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE);
@@ -296,9 +297,9 @@
DEFAULT_VALUE, DEFAULT_VALUE,
};
- ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues));
+ ASSERT_EQ(arraysize(setValues), arraysize(getValues));
- for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) {
+ for (size_t i = 0; i < arraysize(setValues); ++i) {
ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i]));
int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE);
diff --git a/libdiskconfig/Android.bp b/libdiskconfig/Android.bp
new file mode 100644
index 0000000..041fd63
--- /dev/null
+++ b/libdiskconfig/Android.bp
@@ -0,0 +1,32 @@
+cc_library {
+ name: "libdiskconfig",
+ srcs: [
+ "diskconfig.c",
+ "diskutils.c",
+ "write_lst.c",
+ "config_mbr.c",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ cflags: ["-Werror"],
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ linux: {
+ cflags: [
+ "-O2",
+ "-g",
+ "-W",
+ "-Wall",
+ "-D_LARGEFILE64_SOURCE",
+ ],
+ },
+ },
+}
diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk
deleted file mode 100644
index 624e385..0000000
--- a/libdiskconfig/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-commonSources := \
- diskconfig.c \
- diskutils.c \
- write_lst.c \
- config_mbr.c
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(commonSources)
-LOCAL_MODULE := libdiskconfig
-LOCAL_MODULE_TAGS := optional
-LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc
-LOCAL_CFLAGS := -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-ifeq ($(HOST_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(commonSources)
-LOCAL_MODULE := libdiskconfig_host
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -O2 -g -W -Wall -Werror -D_LARGEFILE64_SOURCE
-include $(BUILD_HOST_STATIC_LIBRARY)
-endif # HOST_OS == linux
diff --git a/include/diskconfig/diskconfig.h b/libdiskconfig/include/diskconfig/diskconfig.h
similarity index 100%
rename from include/diskconfig/diskconfig.h
rename to libdiskconfig/include/diskconfig/diskconfig.h
diff --git a/libion/Android.bp b/libion/Android.bp
new file mode 100644
index 0000000..da98111
--- /dev/null
+++ b/libion/Android.bp
@@ -0,0 +1,25 @@
+
+cc_library {
+ name: "libion",
+ srcs: ["ion.c"],
+ shared_libs: ["liblog"],
+ local_include_dirs: [
+ "include",
+ "kernel-headers",
+ ],
+ export_include_dirs: [
+ "include",
+ "kernel-headers",
+ ],
+ cflags: ["-Werror"],
+}
+
+cc_binary {
+ name: "iontest",
+ srcs: ["ion_test.c"],
+ static_libs: ["libion"],
+ shared_libs: ["liblog"],
+ cflags: ["-Werror"],
+}
+
+subdirs = ["tests"]
diff --git a/libion/Android.mk b/libion/Android.mk
deleted file mode 100644
index 6562cd3..0000000
--- a/libion/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ion.c
-LOCAL_MODULE := libion
-LOCAL_MODULE_TAGS := optional
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
-LOCAL_CFLAGS := -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := ion.c ion_test.c
-LOCAL_MODULE := iontest
-LOCAL_MODULE_TAGS := optional tests
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/kernel-headers
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/libion/kernel-headers/linux/ion.h b/libion/kernel-headers/linux/ion.h
index 5af39d0..3c28080 100644
--- a/libion/kernel-headers/linux/ion.h
+++ b/libion/kernel-headers/linux/ion.h
@@ -38,7 +38,7 @@
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ION_HEAP_CARVEOUT_MASK (1 << ION_HEAP_TYPE_CARVEOUT)
#define ION_HEAP_TYPE_DMA_MASK (1 << ION_HEAP_TYPE_DMA)
-#define ION_NUM_HEAP_IDS sizeof(unsigned int) * 8
+#define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8)
#define ION_FLAG_CACHED 1
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define ION_FLAG_CACHED_NEEDS_SYNC 2
diff --git a/libion/tests/Android.bp b/libion/tests/Android.bp
new file mode 100644
index 0000000..4428848
--- /dev/null
+++ b/libion/tests/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "ion-unit-tests",
+ clang: true,
+ cflags: [
+ "-g",
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ ],
+ shared_libs: ["libion"],
+ srcs: [
+ "ion_test_fixture.cpp",
+ "allocate_test.cpp",
+ "formerly_valid_handle_test.cpp",
+ "invalid_values_test.cpp",
+ "map_test.cpp",
+ "device_test.cpp",
+ "exit_test.cpp",
+ ],
+}
diff --git a/libion/tests/allocate_test.cpp b/libion/tests/allocate_test.cpp
index e26b302..3c4524e 100644
--- a/libion/tests/allocate_test.cpp
+++ b/libion/tests/allocate_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <memory>
#include <sys/mman.h>
#include <gtest/gtest.h>
@@ -90,7 +91,7 @@
TEST_F(Allocate, Zeroed)
{
- void *zeroes = calloc(4096, 1);
+ auto zeroes_ptr = std::make_unique<char[]>(4096);
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -125,14 +126,11 @@
ptr = mmap(NULL, 4096, PROT_READ, MAP_SHARED, map_fd, 0);
ASSERT_TRUE(ptr != NULL);
- ASSERT_EQ(0, memcmp(ptr, zeroes, 4096));
+ ASSERT_EQ(0, memcmp(ptr, zeroes_ptr.get(), 4096));
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(zeroes);
-
}
TEST_F(Allocate, Large)
diff --git a/libion/tests/device_test.cpp b/libion/tests/device_test.cpp
index 6f6e1bd..0be52bf 100644
--- a/libion/tests/device_test.cpp
+++ b/libion/tests/device_test.cpp
@@ -15,6 +15,7 @@
*/
#include <fcntl.h>
+#include <memory>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -133,8 +134,8 @@
TEST_F(Device, KernelReadCached)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -161,14 +162,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, KernelWriteCached)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (int i = 0; i < 4096; i++)
((char *)buf)[i] = i;
@@ -195,14 +194,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, DMAReadCached)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -227,14 +224,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, DMAWriteCached)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (int i = 0; i < 4096; i++)
((char *)buf)[i] = i;
@@ -261,14 +256,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, KernelReadCachedNeedsSync)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -295,14 +288,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, KernelWriteCachedNeedsSync)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (int i = 0; i < 4096; i++)
((char *)buf)[i] = i;
@@ -329,14 +320,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, DMAReadCachedNeedsSync)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -363,14 +352,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, DMAWriteCachedNeedsSync)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (int i = 0; i < 4096; i++)
((char *)buf)[i] = i;
@@ -399,13 +386,11 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, KernelRead)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -432,14 +417,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, KernelWrite)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (int i = 0; i < 4096; i++)
((char *)buf)[i] = i;
@@ -466,14 +449,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, DMARead)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
@@ -498,14 +479,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, DMAWrite)
{
- void *alloc = malloc(8192 + 1024);
- void *buf = (void *)(ALIGN((unsigned long)alloc, 4096) + 1024);
+ auto alloc_ptr = std::make_unique<char[]>(8192 + 1024);
+ void *buf = (void *)(ALIGN((unsigned long)alloc_ptr.get(), 4096) + 1024);
for (int i = 0; i < 4096; i++)
((char *)buf)[i] = i;
@@ -532,13 +511,12 @@
ASSERT_EQ(0, munmap(ptr, 4096));
ASSERT_EQ(0, close(map_fd));
}
-
- free(alloc);
}
TEST_F(Device, IsCached)
{
- void *buf = malloc(4096);
+ auto buf_ptr = std::make_unique<char[]>(4096);
+ void *buf = buf_ptr.get();
for (unsigned int heapMask : m_allHeaps) {
SCOPED_TRACE(::testing::Message() << "heap " << heapMask);
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 9c68fca..e32f73c 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -24,7 +24,6 @@
]
liblog_host_sources = [
"fake_log_device.c",
- //"event.logtags",
"fake_writer.c",
]
liblog_target_sources = [
@@ -56,7 +55,9 @@
android: {
srcs: liblog_target_sources,
// AddressSanitizer runtime library depends on liblog.
- sanitize: ["never"],
+ sanitize: {
+ never: true,
+ },
},
android_arm: {
// TODO: This is to work around b/24465209. Remove after root cause is fixed
@@ -86,6 +87,7 @@
"-DLIBLOG_LOG_TAG=1005",
"-DSNET_EVENT_LOG_TAG=1397638484",
],
+ logtags: ["event.logtags"],
compile_multilib: "both",
stl: "none",
}
diff --git a/liblog/Android.mk b/liblog/Android.mk
index b24b489..6c4dff5 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -1,85 +1,3 @@
-#
-# Copyright (C) 2008-2014 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.
-#
LOCAL_PATH := $(my-dir)
-include $(CLEAR_VARS)
-
-# This is what we want to do:
-# liblog_cflags := $(shell \
-# sed -n \
-# 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
-# $(LOCAL_PATH)/event.logtags)
-# so make sure we do not regret hard-coding it as follows:
-liblog_cflags := -DLIBLOG_LOG_TAG=1005
-liblog_cflags += -DSNET_EVENT_LOG_TAG=1397638484
-
-liblog_sources := log_event_list.c log_event_write.c logger_write.c
-liblog_sources += config_write.c logger_name.c logger_lock.c
-liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
-liblog_host_sources += fake_writer.c
-liblog_target_sources := $(liblog_sources) event_tag_map.c
-liblog_target_sources += config_read.c log_time.cpp log_is_loggable.c logprint.c
-liblog_target_sources += pmsg_reader.c pmsg_writer.c
-liblog_target_sources += logd_reader.c logd_writer.c logger_read.c
-
-# Shared and static library for host
-# ========================================================
-LOCAL_MODULE := liblog
-LOCAL_SRC_FILES := $(liblog_host_sources)
-# some files must not be compiled when building against Mingw
-# they correspond to features not used by our host development tools
-# which are also hard or even impossible to port to native Win32
-LOCAL_SRC_FILES_darwin := event_tag_map.c
-LOCAL_SRC_FILES_linux := event_tag_map.c
-LOCAL_SRC_FILES_windows := uio.c
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror -fvisibility=hidden $(liblog_cflags)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_LDLIBS_linux := -lrt
-LOCAL_MULTILIB := both
-LOCAL_CXX_STL := none
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# Shared and static library for target
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
-# AddressSanitizer runtime library depends on liblog.
-LOCAL_SANITIZE := never
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
-
-# TODO: This is to work around b/24465209. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
-
-LOCAL_SANITIZE := never
-LOCAL_CXX_STL := none
-
-include $(BUILD_SHARED_LIBRARY)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/config_read.h b/liblog/config_read.h
index 67f4c20..49a3b75 100644
--- a/liblog/config_read.h
+++ b/liblog/config_read.h
@@ -27,21 +27,21 @@
extern LIBLOG_HIDDEN struct listnode __android_log_persist_read;
#define read_transport_for_each(transp, transports) \
- for (transp = node_to_item((transports)->next, \
+ for ((transp) = node_to_item((transports)->next, \
struct android_log_transport_read, node); \
- (transp != node_to_item(transports, \
+ ((transp) != node_to_item(transports, \
struct android_log_transport_read, node)); \
- transp = node_to_item(transp->node.next, \
+ (transp) = node_to_item((transp)->node.next, \
struct android_log_transport_read, node)) \
#define read_transport_for_each_safe(transp, n, transports) \
- for (transp = node_to_item((transports)->next, \
+ for ((transp) = node_to_item((transports)->next, \
struct android_log_transport_read, node), \
- n = transp->node.next; \
- (transp != node_to_item(transports, \
+ (n) = (transp)->node.next; \
+ ((transp) != node_to_item(transports, \
struct android_log_transport_read, node)); \
- transp = node_to_item(n, struct android_log_transport_read, node), \
- n = transp->node.next)
+ (transp) = node_to_item(n, struct android_log_transport_read, node), \
+ (n) = (transp)->node.next)
LIBLOG_HIDDEN void __android_log_config_read();
diff --git a/liblog/config_write.h b/liblog/config_write.h
index 3a02a4e..3b01a9a 100644
--- a/liblog/config_write.h
+++ b/liblog/config_write.h
@@ -27,21 +27,21 @@
extern LIBLOG_HIDDEN struct listnode __android_log_persist_write;
#define write_transport_for_each(transp, transports) \
- for (transp = node_to_item((transports)->next, \
- struct android_log_transport_write, node); \
- (transp != node_to_item(transports, \
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_write, node); \
+ ((transp) != node_to_item(transports, \
struct android_log_transport_write, node)); \
- transp = node_to_item(transp->node.next, \
- struct android_log_transport_write, node)) \
+ (transp) = node_to_item((transp)->node.next, \
+ struct android_log_transport_write, node)) \
#define write_transport_for_each_safe(transp, n, transports) \
- for (transp = node_to_item((transports)->next, \
- struct android_log_transport_write, node), \
- n = transp->node.next; \
- (transp != node_to_item(transports, \
- struct android_log_transport_write, node)); \
- transp = node_to_item(n, struct android_log_transport_write, node), \
- n = transp->node.next)
+ for ((transp) = node_to_item((transports)->next, \
+ struct android_log_transport_write, node), \
+ (n) = (transp)->node.next; \
+ ((transp) != node_to_item(transports, \
+ struct android_log_transport_write, node)); \
+ (transp) = node_to_item(n, struct android_log_transport_write, node), \
+ (n) = (transp)->node.next)
LIBLOG_HIDDEN void __android_log_config_write();
diff --git a/liblog/logger.h b/liblog/logger.h
index 0964756..2a4cfcb 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -124,23 +124,23 @@
/* assumes caller has structures read-locked, single threaded, or fenced */
#define transport_context_for_each(transp, logger_list) \
- for (transp = node_to_item((logger_list)->transport.next, \
+ for ((transp) = node_to_item((logger_list)->transport.next, \
struct android_log_transport_context, \
node); \
- (transp != node_to_item(&(logger_list)->transport, \
+ ((transp) != node_to_item(&(logger_list)->transport, \
struct android_log_transport_context, \
node)) && \
- (transp->parent == (logger_list)); \
- transp = node_to_item(transp->node.next, \
+ ((transp)->parent == (logger_list)); \
+ (transp) = node_to_item((transp)->node.next, \
struct android_log_transport_context, node))
#define logger_for_each(logp, logger_list) \
- for (logp = node_to_item((logger_list)->logger.next, \
+ for ((logp) = node_to_item((logger_list)->logger.next, \
struct android_log_logger, node); \
- (logp != node_to_item(&(logger_list)->logger, \
+ ((logp) != node_to_item(&(logger_list)->logger, \
struct android_log_logger, node)) && \
- (logp->parent == (logger_list)); \
- logp = node_to_item((logp)->node.next, \
+ ((logp)->parent == (logger_list)); \
+ (logp) = node_to_item((logp)->node.next, \
struct android_log_logger, node))
/* OS specific dribs and drabs */
diff --git a/liblog/logger_read.c b/liblog/logger_read.c
index 0d6ba08..00157b7 100644
--- a/liblog/logger_read.c
+++ b/liblog/logger_read.c
@@ -125,7 +125,7 @@
ssize_t ret = -EINVAL; \
struct android_log_transport_context *transp; \
struct android_log_logger *logger_internal = \
- (struct android_log_logger *)logger; \
+ (struct android_log_logger *)(logger); \
\
if (!logger_internal) { \
return ret; \
@@ -186,7 +186,7 @@
#define LOGGER_LIST_FUNCTION(logger_list, def, func, args...) \
struct android_log_transport_context *transp; \
struct android_log_logger_list *logger_list_internal = \
- (struct android_log_logger_list *)logger_list; \
+ (struct android_log_logger_list *)(logger_list); \
\
ssize_t ret = init_transport_context(logger_list_internal); \
if (ret < 0) { \
@@ -341,6 +341,43 @@
return logger_list;
}
+/* Validate log_msg packet, read function has already been null checked */
+static int android_transport_read(struct android_log_logger_list *logger_list,
+ struct android_log_transport_context *transp,
+ struct log_msg *log_msg)
+{
+ int ret = (*transp->transport->read)(logger_list, transp, log_msg);
+
+ if (ret > (int)sizeof(*log_msg)) {
+ ret = sizeof(*log_msg);
+ }
+
+ transp->ret = ret;
+
+ /* propagate errors, or make sure len & hdr_size members visible */
+ if (ret < (int)(sizeof(log_msg->entry.len) +
+ sizeof(log_msg->entry.hdr_size))) {
+ if (ret >= (int)sizeof(log_msg->entry.len)) {
+ log_msg->entry.len = 0;
+ }
+ return ret;
+ }
+
+ /* hdr_size correction (logger_entry -> logger_entry_v2+ conversion) */
+ if (log_msg->entry_v2.hdr_size == 0) {
+ log_msg->entry_v2.hdr_size = sizeof(struct logger_entry);
+ }
+
+ /* len validation */
+ if (ret <= log_msg->entry_v2.hdr_size) {
+ log_msg->entry.len = 0;
+ } else {
+ log_msg->entry.len = ret - log_msg->entry_v2.hdr_size;
+ }
+
+ return ret;
+}
+
/* Read from the selected logs */
LIBLOG_ABI_PUBLIC int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
@@ -378,7 +415,7 @@
} else if ((logger_list_internal->mode &
ANDROID_LOG_NONBLOCK) ||
!transp->transport->poll) {
- retval = transp->ret = (*transp->transport->read)(
+ retval = android_transport_read(
logger_list_internal,
transp,
&transp->logMsg);
@@ -397,7 +434,7 @@
}
retval = transp->ret = pollval;
} else if (pollval > 0) {
- retval = transp->ret = (*transp->transport->read)(
+ retval = android_transport_read(
logger_list_internal,
transp,
&transp->logMsg);
@@ -434,16 +471,22 @@
if (!oldest) {
return ret;
}
- memcpy(log_msg, &oldest->logMsg, oldest->logMsg.entry.len +
- (oldest->logMsg.entry.hdr_size ?
- oldest->logMsg.entry.hdr_size :
- sizeof(struct logger_entry)));
+ // ret is a positive value less than sizeof(struct log_msg)
+ ret = oldest->ret;
+ if (ret < oldest->logMsg.entry.hdr_size) {
+ // zero truncated header fields.
+ memset(log_msg, 0,
+ (oldest->logMsg.entry.hdr_size > sizeof(oldest->logMsg) ?
+ sizeof(oldest->logMsg) :
+ oldest->logMsg.entry.hdr_size));
+ }
+ memcpy(log_msg, &oldest->logMsg, ret);
oldest->logMsg.entry.len = 0; /* Mark it as copied */
- return oldest->ret;
+ return ret;
}
/* if only one, no need to copy into transport_context and merge-sort */
- return (transp->transport->read)(logger_list_internal, transp, log_msg);
+ return android_transport_read(logger_list_internal, transp, log_msg);
}
/* Close all the logs */
diff --git a/liblog/logprint.c b/liblog/logprint.c
index c8457f4..59bd479 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -21,6 +21,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <pwd.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -28,11 +29,11 @@
#include <string.h>
#include <inttypes.h>
#include <sys/param.h>
+#include <sys/types.h>
#include <cutils/list.h>
#include <log/logd.h>
#include <log/logprint.h>
-#include <private/android_filesystem_config.h>
#include "log_portability.h"
@@ -1352,17 +1353,17 @@
uid[0] = '\0';
if (p_format->uid_output) {
if (entry->uid >= 0) {
- const struct android_id_info *info = android_ids;
- size_t i;
- for (i = 0; i < android_id_count; ++i) {
- if (info->aid == (unsigned int)entry->uid) {
- break;
- }
- ++info;
- }
- if ((i < android_id_count) && (strlen(info->name) <= 5)) {
- snprintf(uid, sizeof(uid), "%5s:", info->name);
+ /*
+ * This code is Android specific, bionic guarantees that
+ * calls to non-reentrant getpwuid() are thread safe.
+ */
+#ifndef __BIONIC__
+#warning "This code assumes that getpwuid is thread safe, only true with Bionic!"
+#endif
+ struct passwd* pwd = getpwuid(entry->uid);
+ if (pwd && (strlen(pwd->pw_name) <= 5)) {
+ snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
} else {
// Not worth parsing package list, names all longer than 5
snprintf(uid, sizeof(uid), "%5d:", entry->uid);
diff --git a/liblog/pmsg_reader.c b/liblog/pmsg_reader.c
index 2e4fc5d..a4eec65 100644
--- a/liblog/pmsg_reader.c
+++ b/liblog/pmsg_reader.c
@@ -144,6 +144,7 @@
struct __attribute__((__packed__)) {
android_pmsg_log_header_t p;
android_log_header_t l;
+ uint8_t prio;
} buf;
static uint8_t preread_count;
bool is_system;
@@ -180,11 +181,16 @@
if (preread_count != sizeof(buf)) {
return preread_count ? -EIO : -EAGAIN;
}
- if ((buf.p.magic != LOGGER_MAGIC)
- || (buf.p.len <= sizeof(buf))
- || (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD))
- || (buf.l.id >= LOG_ID_MAX)
- || (buf.l.realtime.tv_nsec >= NS_PER_SEC)) {
+ if ((buf.p.magic != LOGGER_MAGIC) ||
+ (buf.p.len <= sizeof(buf)) ||
+ (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) ||
+ (buf.l.id >= LOG_ID_MAX) ||
+ (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
+ ((buf.l.id != LOG_ID_EVENTS) &&
+ (buf.l.id != LOG_ID_SECURITY) &&
+ ((buf.prio == ANDROID_LOG_UNKNOWN) ||
+ (buf.prio == ANDROID_LOG_DEFAULT) ||
+ (buf.prio >= ANDROID_LOG_SILENT)))) {
do {
memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
} while (preread_count && (buf.p.magic != LOGGER_MAGIC));
@@ -202,10 +208,12 @@
uid = get_best_effective_uid();
is_system = uid_has_log_permission(uid);
if (is_system || (uid == buf.p.uid)) {
+ char *msg = is_system ?
+ log_msg->entry_v4.msg :
+ log_msg->entry_v3.msg;
+ *msg = buf.prio;
ret = TEMP_FAILURE_RETRY(read(transp->context.fd,
- is_system ?
- log_msg->entry_v4.msg :
- log_msg->entry_v3.msg,
+ msg + sizeof(buf.prio),
buf.p.len - sizeof(buf)));
if (ret < 0) {
return -errno;
@@ -214,7 +222,7 @@
return -EIO;
}
- log_msg->entry_v4.len = buf.p.len - sizeof(buf);
+ log_msg->entry_v4.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
log_msg->entry_v4.hdr_size = is_system ?
sizeof(log_msg->entry_v4) :
sizeof(log_msg->entry_v3);
@@ -227,7 +235,7 @@
log_msg->entry_v4.uid = buf.p.uid;
}
- return ret + log_msg->entry_v4.hdr_size;
+ return ret + sizeof(buf.prio) + log_msg->entry_v4.hdr_size;
}
}
diff --git a/liblog/tests/benchmark.h b/liblog/tests/benchmark.h
index 7f96e6d..e9280f6 100644
--- a/liblog/tests/benchmark.h
+++ b/liblog/tests/benchmark.h
@@ -38,7 +38,7 @@
Benchmark(const char* name, void (*fn)(int)) : name_(strdup(name)), fn_(fn) {
BenchmarkRegister(this);
}
- Benchmark(const char* name) : name_(strdup(name)), fn_(NULL) {}
+ explicit Benchmark(const char* name) : name_(strdup(name)), fn_(NULL) {}
virtual ~Benchmark() {
free(name_);
@@ -141,7 +141,7 @@
void StopBenchmarkTiming(uint64_t);
#define BENCHMARK(f) \
- static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = \
- (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f)
+ static ::testing::Benchmark* _benchmark_##f __attribute__((unused)) = /* NOLINT */ \
+ (::testing::Benchmark*)::testing::BenchmarkFactory(#f, f) /* NOLINT */
#endif // BIONIC_BENCHMARK_H_
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 9dd6f03..3d58147 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -14,126 +14,9 @@
* limitations under the License.
*/
-#include <fcntl.h>
-#include <sys/cdefs.h>
-
#include <gtest/gtest.h>
-// Should be in bionic test suite, *but* we are using liblog to confirm
-// end-to-end logging, so let the overly cute oedipus complex begin ...
-#include "../../../../bionic/libc/bionic/libc_logging.cpp" // not Standalone
-#define _ANDROID_LOG_H // Priorities redefined
-#define _LIBS_LOG_LOG_H // log ids redefined
-typedef unsigned char log_id_t; // log_id_t missing as a result
-#define _LIBS_LOG_LOG_READ_H // log_time redefined
-
-#include <log/log.h>
-#include <log/logger.h>
-#include <log/log_read.h>
-
-TEST(libc, __libc_android_log_event_int) {
- struct logger_list *logger_list;
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- int value = ts.tv_nsec;
-
- __libc_android_log_event_int(0, value);
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != (4 + 1 + 4))
- || ((int)log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- char *eventData = log_msg.msg();
-
- int incoming = (eventData[0] & 0xFF) |
- ((eventData[1] & 0xFF) << 8) |
- ((eventData[2] & 0xFF) << 16) |
- ((eventData[3] & 0xFF) << 24);
-
- if (incoming != 0) {
- continue;
- }
-
- if (eventData[4] != EVENT_TYPE_INT) {
- continue;
- }
-
- incoming = (eventData[4 + 1 + 0] & 0xFF) |
- ((eventData[4 + 1 + 1] & 0xFF) << 8) |
- ((eventData[4 + 1 + 2] & 0xFF) << 16) |
- ((eventData[4 + 1 + 3] & 0xFF) << 24);
-
- if (incoming == value) {
- ++count;
- }
- }
-
- EXPECT_EQ(1, count);
-
- android_logger_list_close(logger_list);
-}
-
-TEST(libc, __libc_fatal_no_abort) {
- struct logger_list *logger_list;
-
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- (log_id_t)LOG_ID_CRASH, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
-
- char b[80];
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
-
- __libc_fatal_no_abort("%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
- snprintf(b, sizeof(b),"%u.%09u", (unsigned)ts.tv_sec, (unsigned)ts.tv_nsec);
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((int)log_msg.id() != LOG_ID_CRASH) {
- continue;
- }
-
- char *data = log_msg.msg();
-
- if ((*data == ANDROID_LOG_FATAL)
- && !strcmp(data + 1, "libc")
- && !strcmp(data + 1 + strlen(data + 1) + 1, b)) {
- ++count;
- }
- }
-
- EXPECT_EQ(1, count);
-
- android_logger_list_close(logger_list);
-}
+#include <stdio.h>
TEST(libc, __pstore_append) {
FILE *fp;
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 01fb50f..1b66a56 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -205,7 +205,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
if (((uintptr_t)&buffer->pmsg_header) & 7) {
@@ -281,7 +281,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
@@ -357,7 +357,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
if (((uintptr_t)&buffer->pmsg_header) & 7) {
@@ -430,7 +430,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 6aa4fb7..df2c766 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -174,7 +174,7 @@
return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
}
-TEST(liblog, __android_log_bswrite) {
+static void bswrite_test(const char *message) {
struct logger_list *logger_list;
pid_t pid = getpid();
@@ -182,10 +182,30 @@
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
- static const char buffer[] = "Hello World";
log_time ts(android_log_clockid());
- ASSERT_LT(0, __android_log_bswrite(0, buffer));
+ ASSERT_LT(0, __android_log_bswrite(0, message));
+ size_t num_lines = 1, size = 0, length = 0, total = 0;
+ const char *cp = message;
+ while (*cp) {
+ if (*cp == '\n') {
+ if (cp[1]) {
+ ++num_lines;
+ }
+ } else {
+ ++size;
+ }
+ ++cp;
+ ++total;
+ ++length;
+ if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
+ break;
+ }
+ }
+ while (*cp) {
+ ++cp;
+ ++total;
+ }
usleep(1000000);
int count = 0;
@@ -200,7 +220,7 @@
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
- || (log_msg.entry.len != (4 + 1 + 4 + sizeof(buffer) - 1))
+ || ((size_t)log_msg.entry.len != (4 + 1 + 4 + length))
|| (log_msg.id() != LOG_ID_EVENTS)) {
continue;
}
@@ -211,21 +231,22 @@
continue;
}
- int len = get4LE(eventData + 4 + 1);
- if (len == (sizeof(buffer) - 1)) {
+ size_t len = get4LE(eventData + 4 + 1);
+ if (len == total) {
++count;
AndroidLogFormat *logformat = android_log_format_new();
EXPECT_TRUE(NULL != logformat);
AndroidLogEntry entry;
char msgBuf[1024];
- EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
- &entry,
- NULL,
- msgBuf,
- sizeof(msgBuf)));
- fflush(stderr);
- EXPECT_EQ(31, android_log_printLogLine(logformat, fileno(stderr), &entry));
+ int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
+ &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
+ EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
+ if (processBinaryLogBuffer == 0) {
+ fflush(stderr);
+ EXPECT_EQ((int)((20 * num_lines) + size),
+ android_log_printLogLine(logformat, fileno(stderr), &entry));
+ }
android_log_format_free(logformat);
}
}
@@ -235,18 +256,55 @@
android_logger_list_close(logger_list);
}
-TEST(liblog, __android_log_bswrite__empty_string) {
+TEST(liblog, __android_log_bswrite_and_print) {
+ bswrite_test("Hello World");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__empty_string) {
+ bswrite_test("");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__newline_prefix) {
+ bswrite_test("\nHello World\n");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__newline_space_prefix) {
+ bswrite_test("\n Hello World \n");
+}
+
+TEST(liblog, __android_log_bswrite_and_print__multiple_newline) {
+ bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
+}
+
+static void buf_write_test(const char *message) {
struct logger_list *logger_list;
pid_t pid = getpid();
ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
- LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+ LOG_ID_MAIN, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
- static const char buffer[] = "";
+ static const char tag[] = "TEST__android_log_buf_write";
log_time ts(android_log_clockid());
- ASSERT_LT(0, __android_log_bswrite(0, buffer));
+ EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
+ tag, message));
+ size_t num_lines = 1, size = 0, length = 0;
+ const char *cp = message;
+ while (*cp) {
+ if (*cp == '\n') {
+ if (cp[1]) {
+ ++num_lines;
+ }
+ } else {
+ ++size;
+ }
+ ++length;
+ if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
+ break;
+ }
+ ++cp;
+ }
usleep(1000000);
int count = 0;
@@ -261,34 +319,25 @@
if ((log_msg.entry.sec < (ts.tv_sec - 1))
|| ((ts.tv_sec + 1) < log_msg.entry.sec)
- || (log_msg.entry.len != (4 + 1 + 4))
- || (log_msg.id() != LOG_ID_EVENTS)) {
+ || ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2))
+ || (log_msg.id() != LOG_ID_MAIN)) {
continue;
}
- char *eventData = log_msg.msg();
+ ++count;
- if (eventData[4] != EVENT_TYPE_STRING) {
- continue;
- }
-
- int len = get4LE(eventData + 4 + 1);
- if (len == 0) {
- ++count;
-
- AndroidLogFormat *logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- char msgBuf[1024];
- EXPECT_EQ(0, android_log_processBinaryLogBuffer(&log_msg.entry_v1,
- &entry,
- NULL,
- msgBuf,
- sizeof(msgBuf)));
+ AndroidLogFormat *logformat = android_log_format_new();
+ EXPECT_TRUE(NULL != logformat);
+ AndroidLogEntry entry;
+ int processLogBuffer = android_log_processLogBuffer(&log_msg.entry_v1,
+ &entry);
+ EXPECT_EQ(0, processLogBuffer);
+ if (processLogBuffer == 0) {
fflush(stderr);
- EXPECT_EQ(20, android_log_printLogLine(logformat, fileno(stderr), &entry));
- android_log_format_free(logformat);
+ EXPECT_EQ((int)(((11 + sizeof(tag)) * num_lines) + size),
+ android_log_printLogLine(logformat, fileno(stderr), &entry));
}
+ android_log_format_free(logformat);
}
EXPECT_EQ(1, count);
@@ -296,6 +345,18 @@
android_logger_list_close(logger_list);
}
+TEST(liblog, __android_log_buf_write_and_print__empty) {
+ buf_write_test("");
+}
+
+TEST(liblog, __android_log_buf_write_and_print__newline_prefix) {
+ buf_write_test("\nHello World\n");
+}
+
+TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) {
+ buf_write_test("\n Hello World \n");
+}
+
TEST(liblog, __security) {
static const char persist_key[] = "persist.logd.security";
static const char readonly_key[] = "ro.device_owner";
@@ -767,7 +828,7 @@
EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
}
-static const char max_payload_tag[] = "TEST_max_payload_XXXX";
+static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
sizeof(max_payload_tag) - 1)
static const char max_payload_buf[] = "LEONATO\n\
@@ -1307,6 +1368,7 @@
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
i, j, key, buf);
+ usleep(20000);
property_set(key, buf);
bool android_log_is_loggable = __android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG);
@@ -1332,6 +1394,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key, "");
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1361,6 +1424,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key + base_offset, "");
strcpy(key, log_namespace);
@@ -1392,6 +1456,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key, "");
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1421,6 +1486,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key + base_offset, "");
}
}
@@ -1428,6 +1494,7 @@
// All combinations of level and tag properties, but with global set to INFO
strcpy(key, log_namespace);
key[sizeof(log_namespace) - 2] = '\0';
+ usleep(20000);
property_set(key, "I");
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
@@ -1441,6 +1508,7 @@
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
i, j, key, buf);
+ usleep(20000);
property_set(key, buf);
bool android_log_is_loggable = __android_log_is_loggable(
levels[i].level, tag, ANDROID_LOG_DEBUG);
@@ -1466,6 +1534,7 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key, "");
fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
@@ -1495,12 +1564,14 @@
levels[i].level, tag, ANDROID_LOG_DEBUG));
}
}
+ usleep(20000);
property_set(key + base_offset, "");
}
}
// reset parms
snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ usleep(20000);
property_set(key, hold[0]);
property_set(key + base_offset, hold[1]);
strcpy(key, log_namespace);
@@ -1802,6 +1873,14 @@
android_logger_list_close(logger_list);
}
+TEST(liblog, __android_log_bswrite_and_print___max) {
+ bswrite_test(max_payload_buf);
+}
+
+TEST(liblog, __android_log_buf_write_and_print__max) {
+ buf_write_test(max_payload_buf);
+}
+
TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
const int TAG = 123456785;
const char SUBTAG[] = "test-subtag";
diff --git a/libmemtrack/Android.bp b/libmemtrack/Android.bp
new file mode 100644
index 0000000..98413dd
--- /dev/null
+++ b/libmemtrack/Android.bp
@@ -0,0 +1,30 @@
+// Copyright 2013 The Android Open Source Project
+
+cc_library_shared {
+ name: "libmemtrack",
+ srcs: ["memtrack.c"],
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+ include_dirs: ["hardware/libhardware/include"],
+ shared_libs: [
+ "libhardware",
+ "liblog",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_binary {
+ name: "memtrack_test",
+ srcs: ["memtrack_test.c"],
+ shared_libs: [
+ "libmemtrack",
+ "libpagemap",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
diff --git a/libmemtrack/Android.mk b/libmemtrack/Android.mk
deleted file mode 100644
index 7b170f5..0000000
--- a/libmemtrack/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := memtrack.c
-LOCAL_MODULE := libmemtrack
-LOCAL_C_INCLUDES += hardware/libhardware/include
-LOCAL_SHARED_LIBRARIES := libhardware liblog
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := memtrack_test.c
-LOCAL_MODULE := memtrack_test
-LOCAL_SHARED_LIBRARIES := libmemtrack libpagemap
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_EXECUTABLE)
diff --git a/include/memtrack/memtrack.h b/libmemtrack/include/memtrack/memtrack.h
similarity index 98%
rename from include/memtrack/memtrack.h
rename to libmemtrack/include/memtrack/memtrack.h
index 3917300..8c0ab89 100644
--- a/include/memtrack/memtrack.h
+++ b/libmemtrack/include/memtrack/memtrack.h
@@ -19,7 +19,6 @@
#include <sys/types.h>
#include <stddef.h>
-#include <cutils/compiler.h>
#ifdef __cplusplus
extern "C" {
diff --git a/libmemtrack/memtrack.c b/libmemtrack/memtrack.c
index 21d9ebd..b528214 100644
--- a/libmemtrack/memtrack.c
+++ b/libmemtrack/memtrack.c
@@ -26,7 +26,7 @@
#include <hardware/memtrack.h>
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
static const memtrack_module_t *module;
diff --git a/libmemunreachable/Allocator.cpp b/libmemunreachable/Allocator.cpp
index 68f654c..6fe67a4 100644
--- a/libmemunreachable/Allocator.cpp
+++ b/libmemunreachable/Allocator.cpp
@@ -52,8 +52,6 @@
return (x + y - 1) / y;
}
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
-
static constexpr size_t kPageSize = 4096;
static constexpr size_t kChunkSize = 256 * 1024;
static constexpr size_t kUsableChunkSize = kChunkSize - kPageSize;
@@ -258,7 +256,7 @@
unsigned int i = first_free_bitmap_;
while (free_bitmap_[i] == 0)
i++;
- assert(i < ARRAY_SIZE(free_bitmap_));
+ assert(i < arraysize(free_bitmap_));
unsigned int bit = __builtin_ffs(free_bitmap_[i]) - 1;
assert(free_bitmap_[i] & (1U << bit));
free_bitmap_[i] &= ~(1U << bit);
@@ -266,7 +264,7 @@
assert(n < max_allocations_);
unsigned int page = n * allocation_size_ / kPageSize;
- assert(page / 32 < ARRAY_SIZE(dirty_pages_));
+ assert(page / 32 < arraysize(dirty_pages_));
dirty_pages_[page / 32] |= 1U << (page % 32);
free_count_--;
@@ -285,7 +283,7 @@
unsigned int i = n / 32;
unsigned int bit = n % 32;
- assert(i < ARRAY_SIZE(free_bitmap_));
+ assert(i < arraysize(free_bitmap_));
assert(!(free_bitmap_[i] & (1U << bit)));
free_bitmap_[i] |= 1U << bit;
free_count_++;
diff --git a/libmemunreachable/Allocator.h b/libmemunreachable/Allocator.h
index a8f579e..5390739 100644
--- a/libmemunreachable/Allocator.h
+++ b/libmemunreachable/Allocator.h
@@ -109,13 +109,13 @@
}
// Construct an STLAllocator on top of a Heap
- STLAllocator(const Heap& heap) :
+ STLAllocator(const Heap& heap) : // NOLINT, implicit
heap_(heap) {
}
// Rebind an STLAllocator from an another STLAllocator
template<typename U>
- STLAllocator(const STLAllocator<U>& other) :
+ STLAllocator(const STLAllocator<U>& other) : // NOLINT, implicit
heap_(other.heap_) {
}
@@ -155,12 +155,12 @@
public:
~Allocator() {}
- Allocator(const Heap& other) :
+ Allocator(const Heap& other) : // NOLINT, implicit
STLAllocator<T>(other) {
}
template<typename U>
- Allocator(const STLAllocator<U>& other) :
+ Allocator(const STLAllocator<U>& other) : // NOLINT, implicit
STLAllocator<T>(other) {
}
diff --git a/libmemunreachable/HeapWalker.h b/libmemunreachable/HeapWalker.h
index 3c1b513..b25696f 100644
--- a/libmemunreachable/HeapWalker.h
+++ b/libmemunreachable/HeapWalker.h
@@ -48,7 +48,7 @@
class HeapWalker {
public:
- HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
+ explicit HeapWalker(Allocator<HeapWalker> allocator) : allocator_(allocator),
allocations_(allocator), allocation_bytes_(0),
roots_(allocator), root_vals_(allocator),
segv_handler_(allocator), walking_ptr_(0) {
diff --git a/libmemunreachable/LeakFolding.h b/libmemunreachable/LeakFolding.h
index 732d3f2..9c6a525 100644
--- a/libmemunreachable/LeakFolding.h
+++ b/libmemunreachable/LeakFolding.h
@@ -54,7 +54,7 @@
bool dominator;
SCCInfo* accumulator;
- SCCInfo(Allocator<SCCInfo> allocator) : node(this, allocator),
+ explicit SCCInfo(Allocator<SCCInfo> allocator) : node(this, allocator),
count(0), size(0), cuumulative_count(0), cuumulative_size(0),
dominator(false), accumulator(nullptr) {}
private:
diff --git a/libmemunreachable/LinkedList.h b/libmemunreachable/LinkedList.h
index 3e44035..132842d 100644
--- a/libmemunreachable/LinkedList.h
+++ b/libmemunreachable/LinkedList.h
@@ -21,7 +21,7 @@
class LinkedList {
public:
LinkedList() : next_(this), prev_(this), data_() {}
- LinkedList(T data) : LinkedList() {
+ explicit LinkedList(T data) : LinkedList() {
data_ = data;
}
~LinkedList() {}
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index aa5b344..4e3c41e 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -37,7 +37,7 @@
class Stack {
public:
- Stack(size_t size) : size_(size) {
+ explicit Stack(size_t size) : size_(size) {
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_PRIVATE | MAP_ANONYMOUS;
page_size_ = sysconf(_SC_PAGE_SIZE);
diff --git a/libmemunreachable/PtracerThread.h b/libmemunreachable/PtracerThread.h
index 4d6ca9a..f88b599 100644
--- a/libmemunreachable/PtracerThread.h
+++ b/libmemunreachable/PtracerThread.h
@@ -32,7 +32,7 @@
// the parent.
class PtracerThread {
public:
- PtracerThread(const std::function<int()>& func);
+ explicit PtracerThread(const std::function<int()>& func);
~PtracerThread();
bool Start();
int Join();
diff --git a/libmemunreachable/ScopedDisableMalloc.h b/libmemunreachable/ScopedDisableMalloc.h
index 4f96376..758d317 100644
--- a/libmemunreachable/ScopedDisableMalloc.h
+++ b/libmemunreachable/ScopedDisableMalloc.h
@@ -74,7 +74,7 @@
class ScopedDisableMallocTimeout {
public:
- ScopedDisableMallocTimeout(std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)) :
+ explicit ScopedDisableMallocTimeout(std::chrono::milliseconds timeout = std::chrono::milliseconds(2000)) :
timeout_(timeout), timed_out_(false), disable_malloc_() {
Disable();
}
diff --git a/libmemunreachable/ScopedSignalHandler.h b/libmemunreachable/ScopedSignalHandler.h
index e006d43..1fd9d4d 100644
--- a/libmemunreachable/ScopedSignalHandler.h
+++ b/libmemunreachable/ScopedSignalHandler.h
@@ -30,7 +30,7 @@
public:
using Fn = std::function<void(ScopedSignalHandler&, int, siginfo_t*, void*)>;
- ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
+ explicit ScopedSignalHandler(Allocator<Fn> allocator) : allocator_(allocator), signal_(-1) {}
~ScopedSignalHandler() {
reset();
}
diff --git a/libmemunreachable/Semaphore.h b/libmemunreachable/Semaphore.h
index 45e8c81..6bcf4ea 100644
--- a/libmemunreachable/Semaphore.h
+++ b/libmemunreachable/Semaphore.h
@@ -24,7 +24,7 @@
class Semaphore {
public:
- Semaphore(int count = 0) : count_(count) {}
+ explicit Semaphore(int count = 0) : count_(count) {}
~Semaphore() = default;
void Wait(std::chrono::milliseconds ms) {
diff --git a/libmemunreachable/Tarjan.h b/libmemunreachable/Tarjan.h
index d7ecdb9..dcd139a 100644
--- a/libmemunreachable/Tarjan.h
+++ b/libmemunreachable/Tarjan.h
@@ -62,7 +62,7 @@
template<class T>
class TarjanAlgorithm {
public:
- TarjanAlgorithm(Allocator<void> allocator) : index_(0),
+ explicit TarjanAlgorithm(Allocator<void> allocator) : index_(0),
stack_(allocator), components_(allocator) {}
void Execute(Graph<T>& graph, SCCList<T>& out);
diff --git a/libmemunreachable/tests/Allocator_test.cpp b/libmemunreachable/tests/Allocator_test.cpp
index fa76ae0..21c8218 100644
--- a/libmemunreachable/tests/Allocator_test.cpp
+++ b/libmemunreachable/tests/Allocator_test.cpp
@@ -160,7 +160,7 @@
Allocator<int>::shared_ptr ptr = allocator.make_shared(0);
{
- auto ptr2 = ptr;
+ auto ptr2 = ptr; // NOLINT, test copy of ptr
}
ASSERT_NE(ptr, nullptr);
}
diff --git a/libmemunreachable/tests/LeakFolding_test.cpp b/libmemunreachable/tests/LeakFolding_test.cpp
index 879a3a0..e85df5f 100644
--- a/libmemunreachable/tests/LeakFolding_test.cpp
+++ b/libmemunreachable/tests/LeakFolding_test.cpp
@@ -37,10 +37,10 @@
Heap heap_;
};
-#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&buffer[0])
-#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&buffer[0]) + sizeof(buffer))
+#define buffer_begin(buffer) reinterpret_cast<uintptr_t>(&(buffer)[0])
+#define buffer_end(buffer) (reinterpret_cast<uintptr_t>(&(buffer)[0]) + sizeof(buffer))
#define ALLOCATION(heap_walker, buffer) \
- ASSERT_EQ(true, heap_walker.Allocation(buffer_begin(buffer), buffer_end(buffer)))
+ ASSERT_EQ(true, (heap_walker).Allocation(buffer_begin(buffer), buffer_end(buffer)))
TEST_F(LeakFoldingTest, one) {
void* buffer1[1] = {nullptr};
diff --git a/libmemunreachable/tests/MemUnreachable_test.cpp b/libmemunreachable/tests/MemUnreachable_test.cpp
index 0747b12..2ae3db8 100644
--- a/libmemunreachable/tests/MemUnreachable_test.cpp
+++ b/libmemunreachable/tests/MemUnreachable_test.cpp
@@ -27,7 +27,7 @@
class HiddenPointer {
public:
- HiddenPointer(size_t size = 256) {
+ explicit HiddenPointer(size_t size = 256) {
Set(malloc(size));
}
~HiddenPointer() {
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
deleted file mode 100644
index 7906986..0000000
--- a/libmincrypt/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2008 The Android Open Source Project
-#
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libmincrypt
-LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
-LOCAL_CFLAGS := -Wall -Werror
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(LOCAL_PATH)/tools/Android.mk \
- $(LOCAL_PATH)/test/Android.mk
diff --git a/libmincrypt/NOTICE b/libmincrypt/NOTICE
deleted file mode 100644
index 430d3d6..0000000
--- a/libmincrypt/NOTICE
+++ /dev/null
@@ -1,23 +0,0 @@
- Copyright 2008, The Android Open Source Project
-
- 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.
- * Neither the name of Google Inc. nor the names of its contributors may
- be used to endorse or promote products derived from this software
- without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
diff --git a/libmincrypt/dsa_sig.c b/libmincrypt/dsa_sig.c
deleted file mode 100644
index 101314b..0000000
--- a/libmincrypt/dsa_sig.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <string.h>
-
-#include "mincrypt/dsa_sig.h"
-#include "mincrypt/p256.h"
-
-/**
- * Trims off the leading zero bytes and copy it to a buffer aligning it to the end.
- */
-static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src,
- int src_len) {
- int dst_offset;
- while (*src == '\0' && src_len > 0) {
- src++;
- src_len--;
- }
- if (src_len > P256_NBYTES || src_len < 1) {
- return 0;
- }
- dst_offset = P256_NBYTES - src_len;
- memset(dst, 0, dst_offset);
- memcpy(dst + dst_offset, src, src_len);
- return 1;
-}
-
-/**
- * Unpacks the ASN.1 DSA signature sequence.
- */
-int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) {
- /*
- * Structure is:
- * 0x30 0xNN SEQUENCE + s_length
- * 0x02 0xNN INTEGER + r_length
- * 0xAA 0xBB .. r_length bytes of "r" (offset 4)
- * 0x02 0xNN INTEGER + s_length
- * 0xMM 0xNN .. s_length bytes of "s" (offset 6 + r_len)
- */
- int seq_len;
- unsigned char r_bytes[P256_NBYTES];
- unsigned char s_bytes[P256_NBYTES];
- int r_len;
- int s_len;
-
- memset(r_bytes, 0, sizeof(r_bytes));
- memset(s_bytes, 0, sizeof(s_bytes));
-
- /*
- * Must have at least:
- * 2 bytes sequence header and length
- * 2 bytes R integer header and length
- * 1 byte of R
- * 2 bytes S integer header and length
- * 1 byte of S
- *
- * 8 bytes total
- */
- if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) {
- return 0;
- }
-
- seq_len = sig[1];
- if ((seq_len <= 0) || (seq_len + 2 != sig_len)) {
- return 0;
- }
-
- r_len = sig[3];
- /*
- * Must have at least:
- * 2 bytes for R header and length
- * 2 bytes S integer header and length
- * 1 byte of S
- */
- if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) {
- return 0;
- }
- s_len = sig[5 + r_len];
-
- /**
- * Must have:
- * 2 bytes for R header and length
- * r_len bytes for R
- * 2 bytes S integer header and length
- */
- if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) {
- return 0;
- }
-
- /*
- * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have
- * a correctly-sized buffer and that the resulting integer isn't too large.
- */
- if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len)
- || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) {
- return 0;
- }
-
- p256_from_bin(r_bytes, r_int);
- p256_from_bin(s_bytes, s_int);
-
- return 1;
-}
diff --git a/libmincrypt/p256.c b/libmincrypt/p256.c
deleted file mode 100644
index 555a07a..0000000
--- a/libmincrypt/p256.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-
-// This is an implementation of the P256 elliptic curve group. It's written to
-// be portable 32-bit, although it's still constant-time.
-//
-// WARNING: Implementing these functions in a constant-time manner is far from
-// obvious. Be careful when touching this code.
-//
-// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
-
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
-#include <stdio.h>
-
-#include "mincrypt/p256.h"
-
-const p256_int SECP256r1_n = // curve order
- {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}};
-
-const p256_int SECP256r1_p = // curve field size
- {{-1, -1, -1, 0, 0, 0, 1, -1 }};
-
-const p256_int SECP256r1_b = // curve b
- {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
- 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}};
-
-void p256_init(p256_int* a) {
- memset(a, 0, sizeof(*a));
-}
-
-void p256_clear(p256_int* a) { p256_init(a); }
-
-int p256_get_bit(const p256_int* scalar, int bit) {
- return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
- >> (bit & (P256_BITSPERDIGIT - 1))) & 1;
-}
-
-int p256_is_zero(const p256_int* a) {
- int i, result = 0;
- for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i);
- return !result;
-}
-
-// top, c[] += a[] * b
-// Returns new top
-static p256_digit mulAdd(const p256_int* a,
- p256_digit b,
- p256_digit top,
- p256_digit* c) {
- int i;
- p256_ddigit carry = 0;
-
- for (i = 0; i < P256_NDIGITS; ++i) {
- carry += *c;
- carry += (p256_ddigit)P256_DIGIT(a, i) * b;
- *c++ = (p256_digit)carry;
- carry >>= P256_BITSPERDIGIT;
- }
- return top + (p256_digit)carry;
-}
-
-// top, c[] -= top_a, a[]
-static p256_digit subTop(p256_digit top_a,
- const p256_digit* a,
- p256_digit top_c,
- p256_digit* c) {
- int i;
- p256_sddigit borrow = 0;
-
- for (i = 0; i < P256_NDIGITS; ++i) {
- borrow += *c;
- borrow -= *a++;
- *c++ = (p256_digit)borrow;
- borrow >>= P256_BITSPERDIGIT;
- }
- borrow += top_c;
- borrow -= top_a;
- top_c = (p256_digit)borrow;
- assert((borrow >> P256_BITSPERDIGIT) == 0);
- return top_c;
-}
-
-// top, c[] -= MOD[] & mask (0 or -1)
-// returns new top.
-static p256_digit subM(const p256_int* MOD,
- p256_digit top,
- p256_digit* c,
- p256_digit mask) {
- int i;
- p256_sddigit borrow = 0;
- for (i = 0; i < P256_NDIGITS; ++i) {
- borrow += *c;
- borrow -= P256_DIGIT(MOD, i) & mask;
- *c++ = (p256_digit)borrow;
- borrow >>= P256_BITSPERDIGIT;
- }
- return top + (p256_digit)borrow;
-}
-
-// top, c[] += MOD[] & mask (0 or -1)
-// returns new top.
-static p256_digit addM(const p256_int* MOD,
- p256_digit top,
- p256_digit* c,
- p256_digit mask) {
- int i;
- p256_ddigit carry = 0;
- for (i = 0; i < P256_NDIGITS; ++i) {
- carry += *c;
- carry += P256_DIGIT(MOD, i) & mask;
- *c++ = (p256_digit)carry;
- carry >>= P256_BITSPERDIGIT;
- }
- return top + (p256_digit)carry;
-}
-
-// c = a * b mod MOD. c can be a and/or b.
-void p256_modmul(const p256_int* MOD,
- const p256_int* a,
- const p256_digit top_b,
- const p256_int* b,
- p256_int* c) {
- p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
- p256_digit top = 0;
- int i;
-
- // Multiply/add into tmp.
- for (i = 0; i < P256_NDIGITS; ++i) {
- if (i) tmp[i + P256_NDIGITS - 1] = top;
- top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i);
- }
-
- // Multiply/add top digit
- tmp[i + P256_NDIGITS - 1] = top;
- top = mulAdd(a, top_b, 0, tmp + i);
-
- // Reduce tmp, digit by digit.
- for (; i >= 0; --i) {
- p256_digit reducer[P256_NDIGITS] = { 0 };
- p256_digit top_reducer;
-
- // top can be any value at this point.
- // Guestimate reducer as top * MOD, since msw of MOD is -1.
- top_reducer = mulAdd(MOD, top, 0, reducer);
-
- // Subtract reducer from top | tmp.
- top = subTop(top_reducer, reducer, top, tmp + i);
-
- // top is now either 0 or 1. Make it 0, fixed-timing.
- assert(top <= 1);
-
- top = subM(MOD, top, tmp + i, ~(top - 1));
-
- assert(top == 0);
-
- // We have now reduced the top digit off tmp. Fetch new top digit.
- top = tmp[i + P256_NDIGITS - 1];
- }
-
- // tmp might still be larger than MOD, yet same bit length.
- // Make sure it is less, fixed-timing.
- addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1));
-
- memcpy(c, tmp, P256_NBYTES);
-}
-int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; }
-int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); }
-
-p256_digit p256_shl(const p256_int* a, int n, p256_int* b) {
- int i;
- p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
-
- n %= P256_BITSPERDIGIT;
- for (i = P256_NDIGITS - 1; i > 0; --i) {
- p256_digit accu = (P256_DIGIT(a, i) << n);
- accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
- P256_DIGIT(b, i) = accu;
- }
- P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
-
- top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT);
-
- return top;
-}
-
-void p256_shr(const p256_int* a, int n, p256_int* b) {
- int i;
-
- n %= P256_BITSPERDIGIT;
- for (i = 0; i < P256_NDIGITS - 1; ++i) {
- p256_digit accu = (P256_DIGIT(a, i) >> n);
- accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
- P256_DIGIT(b, i) = accu;
- }
- P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
-}
-
-static void p256_shr1(const p256_int* a, int highbit, p256_int* b) {
- int i;
-
- for (i = 0; i < P256_NDIGITS - 1; ++i) {
- p256_digit accu = (P256_DIGIT(a, i) >> 1);
- accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
- P256_DIGIT(b, i) = accu;
- }
- P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
- (highbit << (P256_BITSPERDIGIT - 1));
-}
-
-// Return -1, 0, 1 for a < b, a == b or a > b respectively.
-int p256_cmp(const p256_int* a, const p256_int* b) {
- int i;
- p256_sddigit borrow = 0;
- p256_digit notzero = 0;
-
- for (i = 0; i < P256_NDIGITS; ++i) {
- borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
- // Track whether any result digit is ever not zero.
- // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1.
- notzero |= !!((p256_digit)borrow);
- borrow >>= P256_BITSPERDIGIT;
- }
- return (int)borrow | notzero;
-}
-
-// c = a - b. Returns borrow: 0 or -1.
-int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) {
- int i;
- p256_sddigit borrow = 0;
-
- for (i = 0; i < P256_NDIGITS; ++i) {
- borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i);
- if (c) P256_DIGIT(c, i) = (p256_digit)borrow;
- borrow >>= P256_BITSPERDIGIT;
- }
- return (int)borrow;
-}
-
-// c = a + b. Returns carry: 0 or 1.
-int p256_add(const p256_int* a, const p256_int* b, p256_int* c) {
- int i;
- p256_ddigit carry = 0;
-
- for (i = 0; i < P256_NDIGITS; ++i) {
- carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i);
- if (c) P256_DIGIT(c, i) = (p256_digit)carry;
- carry >>= P256_BITSPERDIGIT;
- }
- return (int)carry;
-}
-
-// b = a + d. Returns carry, 0 or 1.
-int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) {
- int i;
- p256_ddigit carry = d;
-
- for (i = 0; i < P256_NDIGITS; ++i) {
- carry += (p256_ddigit)P256_DIGIT(a, i);
- if (b) P256_DIGIT(b, i) = (p256_digit)carry;
- carry >>= P256_BITSPERDIGIT;
- }
- return (int)carry;
-}
-
-// b = 1/a mod MOD, binary euclid.
-void p256_modinv_vartime(const p256_int* MOD,
- const p256_int* a,
- p256_int* b) {
- p256_int R = P256_ZERO;
- p256_int S = P256_ONE;
- p256_int U = *MOD;
- p256_int V = *a;
-
- for (;;) {
- if (p256_is_even(&U)) {
- p256_shr1(&U, 0, &U);
- if (p256_is_even(&R)) {
- p256_shr1(&R, 0, &R);
- } else {
- // R = (R+MOD)/2
- p256_shr1(&R, p256_add(&R, MOD, &R), &R);
- }
- } else if (p256_is_even(&V)) {
- p256_shr1(&V, 0, &V);
- if (p256_is_even(&S)) {
- p256_shr1(&S, 0, &S);
- } else {
- // S = (S+MOD)/2
- p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
- }
- } else { // U,V both odd.
- if (!p256_sub(&V, &U, NULL)) {
- p256_sub(&V, &U, &V);
- if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S);
- if (p256_is_zero(&V)) break; // done.
- } else {
- p256_sub(&U, &V, &U);
- if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R);
- }
- }
- }
-
- p256_mod(MOD, &R, b);
-}
-
-void p256_mod(const p256_int* MOD,
- const p256_int* in,
- p256_int* out) {
- if (out != in) *out = *in;
- addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1));
-}
-
-// Verify y^2 == x^3 - 3x + b mod p
-// and 0 < x < p and 0 < y < p
-int p256_is_valid_point(const p256_int* x, const p256_int* y) {
- p256_int y2, x3;
-
- if (p256_cmp(&SECP256r1_p, x) <= 0 ||
- p256_cmp(&SECP256r1_p, y) <= 0 ||
- p256_is_zero(x) ||
- p256_is_zero(y)) return 0;
-
- p256_modmul(&SECP256r1_p, y, 0, y, &y2); // y^2
-
- p256_modmul(&SECP256r1_p, x, 0, x, &x3); // x^2
- p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); // x^3
- if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - x
- if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 2x
- if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x
- if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b
- p256_sub(&x3, &SECP256r1_p, &x3);
-
- return p256_cmp(&y2, &x3) == 0;
-}
-
-void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) {
- int i;
- const uint8_t* p = &src[0];
-
- for (i = P256_NDIGITS - 1; i >= 0; --i) {
- P256_DIGIT(dst, i) =
- (p[0] << 24) |
- (p[1] << 16) |
- (p[2] << 8) |
- p[3];
- p += 4;
- }
-}
diff --git a/libmincrypt/p256_ec.c b/libmincrypt/p256_ec.c
deleted file mode 100644
index 90262cc..0000000
--- a/libmincrypt/p256_ec.c
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
- */
-
-// This is an implementation of the P256 elliptic curve group. It's written to
-// be portable 32-bit, although it's still constant-time.
-//
-// WARNING: Implementing these functions in a constant-time manner is far from
-// obvious. Be careful when touching this code.
-//
-// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background.
-
-#include <stdint.h>
-#include <stdio.h>
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "mincrypt/p256.h"
-
-typedef uint8_t u8;
-typedef uint32_t u32;
-typedef int32_t s32;
-typedef uint64_t u64;
-
-/* Our field elements are represented as nine 32-bit limbs.
- *
- * The value of an felem (field element) is:
- * x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228)
- *
- * That is, each limb is alternately 29 or 28-bits wide in little-endian
- * order.
- *
- * This means that an felem hits 2**257, rather than 2**256 as we would like. A
- * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems
- * when multiplying as terms end up one bit short of a limb which would require
- * much bit-shifting to correct.
- *
- * Finally, the values stored in an felem are in Montgomery form. So the value
- * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257.
- */
-typedef u32 limb;
-#define NLIMBS 9
-typedef limb felem[NLIMBS];
-
-static const limb kBottom28Bits = 0xfffffff;
-static const limb kBottom29Bits = 0x1fffffff;
-
-/* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and
- * 28-bit words. */
-static const felem kOne = {
- 2, 0, 0, 0xffff800,
- 0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff,
- 0
-};
-static const felem kZero = {0};
-static const felem kP = {
- 0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff,
- 0, 0, 0x200000, 0xf000000,
- 0xfffffff
-};
-static const felem k2P = {
- 0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff,
- 0, 0, 0x400000, 0xe000000,
- 0x1fffffff
-};
-/* kPrecomputed contains precomputed values to aid the calculation of scalar
- * multiples of the base point, G. It's actually two, equal length, tables
- * concatenated.
- *
- * The first table contains (x,y) felem pairs for 16 multiples of the base
- * point, G.
- *
- * Index | Index (binary) | Value
- * 0 | 0000 | 0G (all zeros, omitted)
- * 1 | 0001 | G
- * 2 | 0010 | 2**64G
- * 3 | 0011 | 2**64G + G
- * 4 | 0100 | 2**128G
- * 5 | 0101 | 2**128G + G
- * 6 | 0110 | 2**128G + 2**64G
- * 7 | 0111 | 2**128G + 2**64G + G
- * 8 | 1000 | 2**192G
- * 9 | 1001 | 2**192G + G
- * 10 | 1010 | 2**192G + 2**64G
- * 11 | 1011 | 2**192G + 2**64G + G
- * 12 | 1100 | 2**192G + 2**128G
- * 13 | 1101 | 2**192G + 2**128G + G
- * 14 | 1110 | 2**192G + 2**128G + 2**64G
- * 15 | 1111 | 2**192G + 2**128G + 2**64G + G
- *
- * The second table follows the same style, but the terms are 2**32G,
- * 2**96G, 2**160G, 2**224G.
- *
- * This is ~2KB of data. */
-static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = {
- 0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee,
- 0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3,
- 0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c,
- 0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22,
- 0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050,
- 0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b,
- 0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa,
- 0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2,
- 0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609,
- 0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581,
- 0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca,
- 0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33,
- 0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6,
- 0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd,
- 0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0,
- 0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881,
- 0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a,
- 0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26,
- 0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b,
- 0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023,
- 0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133,
- 0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa,
- 0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29,
- 0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc,
- 0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8,
- 0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59,
- 0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39,
- 0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689,
- 0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa,
- 0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3,
- 0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1,
- 0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f,
- 0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72,
- 0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d,
- 0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b,
- 0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a,
- 0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a,
- 0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f,
- 0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb,
- 0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc,
- 0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9,
- 0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce,
- 0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2,
- 0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca,
- 0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229,
- 0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57,
- 0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c,
- 0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa,
- 0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651,
- 0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec,
- 0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7,
- 0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c,
- 0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927,
- 0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298,
- 0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8,
- 0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2,
- 0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d,
- 0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4,
- 0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8,
- 0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78,
-};
-
-
-/* Field element operations: */
-
-/* NON_ZERO_TO_ALL_ONES returns:
- * 0xffffffff for 0 < x <= 2**31
- * 0 for x == 0 or x > 2**31.
- *
- * x must be a u32 or an equivalent type such as limb. */
-#define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1)
-
-/* felem_reduce_carry adds a multiple of p in order to cancel |carry|,
- * which is a term at 2**257.
- *
- * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28.
- * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */
-static void felem_reduce_carry(felem inout, limb carry) {
- const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry);
-
- inout[0] += carry << 1;
- inout[3] += 0x10000000 & carry_mask;
- /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the
- * previous line therefore this doesn't underflow. */
- inout[3] -= carry << 11;
- inout[4] += (0x20000000 - 1) & carry_mask;
- inout[5] += (0x10000000 - 1) & carry_mask;
- inout[6] += (0x20000000 - 1) & carry_mask;
- inout[6] -= carry << 22;
- /* This may underflow if carry is non-zero but, if so, we'll fix it in the
- * next line. */
- inout[7] -= 1 & carry_mask;
- inout[7] += carry << 25;
-}
-
-/* felem_sum sets out = in+in2.
- *
- * On entry, in[i]+in2[i] must not overflow a 32-bit word.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
-static void felem_sum(felem out, const felem in, const felem in2) {
- limb carry = 0;
- unsigned i;
-
- for (i = 0;; i++) {
- out[i] = in[i] + in2[i];
- out[i] += carry;
- carry = out[i] >> 29;
- out[i] &= kBottom29Bits;
-
- i++;
- if (i == NLIMBS)
- break;
-
- out[i] = in[i] + in2[i];
- out[i] += carry;
- carry = out[i] >> 28;
- out[i] &= kBottom28Bits;
- }
-
- felem_reduce_carry(out, carry);
-}
-
-#define two31m3 (((limb)1) << 31) - (((limb)1) << 3)
-#define two30m2 (((limb)1) << 30) - (((limb)1) << 2)
-#define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2)
-#define two31m2 (((limb)1) << 31) - (((limb)1) << 2)
-#define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2)
-#define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2)
-
-/* zero31 is 0 mod p. */
-static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 };
-
-/* felem_diff sets out = in-in2.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
- * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_diff(felem out, const felem in, const felem in2) {
- limb carry = 0;
- unsigned i;
-
- for (i = 0;; i++) {
- out[i] = in[i] - in2[i];
- out[i] += zero31[i];
- out[i] += carry;
- carry = out[i] >> 29;
- out[i] &= kBottom29Bits;
-
- i++;
- if (i == NLIMBS)
- break;
-
- out[i] = in[i] - in2[i];
- out[i] += zero31[i];
- out[i] += carry;
- carry = out[i] >> 28;
- out[i] &= kBottom28Bits;
- }
-
- felem_reduce_carry(out, carry);
-}
-
-/* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words
- * with the same 29,28,... bit positions as an felem.
- *
- * The values in felems are in Montgomery form: x*R mod p where R = 2**257.
- * Since we just multiplied two Montgomery values together, the result is
- * x*y*R*R mod p. We wish to divide by R in order for the result also to be
- * in Montgomery form.
- *
- * On entry: tmp[i] < 2**64
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */
-static void felem_reduce_degree(felem out, u64 tmp[17]) {
- /* The following table may be helpful when reading this code:
- *
- * Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10...
- * Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29
- * Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285
- * (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */
- limb tmp2[18], carry, x, xMask;
- unsigned i;
-
- /* tmp contains 64-bit words with the same 29,28,29-bit positions as an
- * felem. So the top of an element of tmp might overlap with another
- * element two positions down. The following loop eliminates this
- * overlap. */
- tmp2[0] = (limb)(tmp[0] & kBottom29Bits);
-
- /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try
- * and hint to the compiler that it can do a single-word shift by selecting
- * the right register rather than doing a double-word shift and truncating
- * afterwards. */
- tmp2[1] = ((limb) tmp[0]) >> 29;
- tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits;
- tmp2[1] += ((limb) tmp[1]) & kBottom28Bits;
- carry = tmp2[1] >> 28;
- tmp2[1] &= kBottom28Bits;
-
- for (i = 2; i < 17; i++) {
- tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
- tmp2[i] += ((limb)(tmp[i - 1])) >> 28;
- tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits;
- tmp2[i] += ((limb) tmp[i]) & kBottom29Bits;
- tmp2[i] += carry;
- carry = tmp2[i] >> 29;
- tmp2[i] &= kBottom29Bits;
-
- i++;
- if (i == 17)
- break;
- tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25;
- tmp2[i] += ((limb)(tmp[i - 1])) >> 29;
- tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits;
- tmp2[i] += ((limb) tmp[i]) & kBottom28Bits;
- tmp2[i] += carry;
- carry = tmp2[i] >> 28;
- tmp2[i] &= kBottom28Bits;
- }
-
- tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25;
- tmp2[17] += ((limb)(tmp[16])) >> 29;
- tmp2[17] += (((limb)(tmp[16] >> 32)) << 3);
- tmp2[17] += carry;
-
- /* Montgomery elimination of terms.
- *
- * Since R is 2**257, we can divide by R with a bitwise shift if we can
- * ensure that the right-most 257 bits are all zero. We can make that true by
- * adding multiplies of p without affecting the value.
- *
- * So we eliminate limbs from right to left. Since the bottom 29 bits of p
- * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0.
- * We can do that for 8 further limbs and then right shift to eliminate the
- * extra factor of R. */
- for (i = 0;; i += 2) {
- tmp2[i + 1] += tmp2[i] >> 29;
- x = tmp2[i] & kBottom29Bits;
- xMask = NON_ZERO_TO_ALL_ONES(x);
- tmp2[i] = 0;
-
- /* The bounds calculations for this loop are tricky. Each iteration of
- * the loop eliminates two words by adding values to words to their
- * right.
- *
- * The following table contains the amounts added to each word (as an
- * offset from the value of i at the top of the loop). The amounts are
- * accounted for from the first and second half of the loop separately
- * and are written as, for example, 28 to mean a value <2**28.
- *
- * Word: 3 4 5 6 7 8 9 10
- * Added in top half: 28 11 29 21 29 28
- * 28 29
- * 29
- * Added in bottom half: 29 10 28 21 28 28
- * 29
- *
- * The value that is currently offset 7 will be offset 5 for the next
- * iteration and then offset 3 for the iteration after that. Therefore
- * the total value added will be the values added at 7, 5 and 3.
- *
- * The following table accumulates these values. The sums at the bottom
- * are written as, for example, 29+28, to mean a value < 2**29+2**28.
- *
- * Word: 3 4 5 6 7 8 9 10 11 12 13
- * 28 11 10 29 21 29 28 28 28 28 28
- * 29 28 11 28 29 28 29 28 29 28
- * 29 28 21 21 29 21 29 21
- * 10 29 28 21 28 21 28
- * 28 29 28 29 28 29 28
- * 11 10 29 10 29 10
- * 29 28 11 28 11
- * 29 29
- * --------------------------------------------
- * 30+ 31+ 30+ 31+ 30+
- * 28+ 29+ 28+ 29+ 21+
- * 21+ 28+ 21+ 28+ 10
- * 10 21+ 10 21+
- * 11 11
- *
- * So the greatest amount is added to tmp2[10] and tmp2[12]. If
- * tmp2[10/12] has an initial value of <2**29, then the maximum value
- * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32,
- * as required. */
- tmp2[i + 3] += (x << 10) & kBottom28Bits;
- tmp2[i + 4] += (x >> 18);
-
- tmp2[i + 6] += (x << 21) & kBottom29Bits;
- tmp2[i + 7] += x >> 8;
-
- /* At position 200, which is the starting bit position for word 7, we
- * have a factor of 0xf000000 = 2**28 - 2**24. */
- tmp2[i + 7] += 0x10000000 & xMask;
- /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */
- tmp2[i + 8] += (x - 1) & xMask;
- tmp2[i + 7] -= (x << 24) & kBottom28Bits;
- tmp2[i + 8] -= x >> 4;
-
- tmp2[i + 8] += 0x20000000 & xMask;
- tmp2[i + 8] -= x;
- tmp2[i + 8] += (x << 28) & kBottom29Bits;
- tmp2[i + 9] += ((x >> 1) - 1) & xMask;
-
- if (i+1 == NLIMBS)
- break;
- tmp2[i + 2] += tmp2[i + 1] >> 28;
- x = tmp2[i + 1] & kBottom28Bits;
- xMask = NON_ZERO_TO_ALL_ONES(x);
- tmp2[i + 1] = 0;
-
- tmp2[i + 4] += (x << 11) & kBottom29Bits;
- tmp2[i + 5] += (x >> 18);
-
- tmp2[i + 7] += (x << 21) & kBottom28Bits;
- tmp2[i + 8] += x >> 7;
-
- /* At position 199, which is the starting bit of the 8th word when
- * dealing with a context starting on an odd word, we have a factor of
- * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th
- * word from i+1 is i+8. */
- tmp2[i + 8] += 0x20000000 & xMask;
- tmp2[i + 9] += (x - 1) & xMask;
- tmp2[i + 8] -= (x << 25) & kBottom29Bits;
- tmp2[i + 9] -= x >> 4;
-
- tmp2[i + 9] += 0x10000000 & xMask;
- tmp2[i + 9] -= x;
- tmp2[i + 10] += (x - 1) & xMask;
- }
-
- /* We merge the right shift with a carry chain. The words above 2**257 have
- * widths of 28,29,... which we need to correct when copying them down. */
- carry = 0;
- for (i = 0; i < 8; i++) {
- /* The maximum value of tmp2[i + 9] occurs on the first iteration and
- * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is
- * therefore safe. */
- out[i] = tmp2[i + 9];
- out[i] += carry;
- out[i] += (tmp2[i + 10] << 28) & kBottom29Bits;
- carry = out[i] >> 29;
- out[i] &= kBottom29Bits;
-
- i++;
- out[i] = tmp2[i + 9] >> 1;
- out[i] += carry;
- carry = out[i] >> 28;
- out[i] &= kBottom28Bits;
- }
-
- out[8] = tmp2[17];
- out[8] += carry;
- carry = out[8] >> 29;
- out[8] &= kBottom29Bits;
-
- felem_reduce_carry(out, carry);
-}
-
-/* felem_square sets out=in*in.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_square(felem out, const felem in) {
- u64 tmp[17];
-
- tmp[0] = ((u64) in[0]) * in[0];
- tmp[1] = ((u64) in[0]) * (in[1] << 1);
- tmp[2] = ((u64) in[0]) * (in[2] << 1) +
- ((u64) in[1]) * (in[1] << 1);
- tmp[3] = ((u64) in[0]) * (in[3] << 1) +
- ((u64) in[1]) * (in[2] << 1);
- tmp[4] = ((u64) in[0]) * (in[4] << 1) +
- ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2];
- tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) *
- (in[4] << 1) + ((u64) in[2]) * (in[3] << 1);
- tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) *
- (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) +
- ((u64) in[3]) * (in[3] << 1);
- tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) *
- (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) +
- ((u64) in[3]) * (in[4] << 1);
- /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60,
- * which is < 2**64 as required. */
- tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) *
- (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) +
- ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4];
- tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) *
- (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) +
- ((u64) in[4]) * (in[5] << 1);
- tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) *
- (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) +
- ((u64) in[5]) * (in[5] << 1);
- tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) *
- (in[7] << 1) + ((u64) in[5]) * (in[6] << 1);
- tmp[12] = ((u64) in[4]) * (in[8] << 1) +
- ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6];
- tmp[13] = ((u64) in[5]) * (in[8] << 1) +
- ((u64) in[6]) * (in[7] << 1);
- tmp[14] = ((u64) in[6]) * (in[8] << 1) +
- ((u64) in[7]) * (in[7] << 1);
- tmp[15] = ((u64) in[7]) * (in[8] << 1);
- tmp[16] = ((u64) in[8]) * in[8];
-
- felem_reduce_degree(out, tmp);
-}
-
-/* felem_mul sets out=in*in2.
- *
- * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and
- * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_mul(felem out, const felem in, const felem in2) {
- u64 tmp[17];
-
- tmp[0] = ((u64) in[0]) * in2[0];
- tmp[1] = ((u64) in[0]) * (in2[1] << 0) +
- ((u64) in[1]) * (in2[0] << 0);
- tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) *
- (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0);
- tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) *
- (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) +
- ((u64) in[3]) * (in2[0] << 0);
- tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) *
- (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) +
- ((u64) in[3]) * (in2[1] << 1) +
- ((u64) in[4]) * (in2[0] << 0);
- tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) *
- (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) +
- ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) *
- (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0);
- tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) *
- (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) +
- ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) *
- (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) +
- ((u64) in[6]) * (in2[0] << 0);
- tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) *
- (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) +
- ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) *
- (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) +
- ((u64) in[6]) * (in2[1] << 0) +
- ((u64) in[7]) * (in2[0] << 0);
- /* tmp[8] has the greatest value but doesn't overflow. See logic in
- * felem_square. */
- tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) *
- (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) +
- ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) *
- (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) +
- ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) *
- (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0);
- tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) *
- (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) +
- ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) *
- (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) +
- ((u64) in[7]) * (in2[2] << 0) +
- ((u64) in[8]) * (in2[1] << 0);
- tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) *
- (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) +
- ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) *
- (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) +
- ((u64) in[8]) * (in2[2] << 0);
- tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) *
- (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) +
- ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) *
- (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0);
- tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) *
- (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) +
- ((u64) in[7]) * (in2[5] << 1) +
- ((u64) in[8]) * (in2[4] << 0);
- tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) *
- (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) +
- ((u64) in[8]) * (in2[5] << 0);
- tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) *
- (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0);
- tmp[15] = ((u64) in[7]) * (in2[8] << 0) +
- ((u64) in[8]) * (in2[7] << 0);
- tmp[16] = ((u64) in[8]) * (in2[8] << 0);
-
- felem_reduce_degree(out, tmp);
-}
-
-static void felem_assign(felem out, const felem in) {
- memcpy(out, in, sizeof(felem));
-}
-
-/* felem_inv calculates |out| = |in|^{-1}
- *
- * Based on Fermat's Little Theorem:
- * a^p = a (mod p)
- * a^{p-1} = 1 (mod p)
- * a^{p-2} = a^{-1} (mod p)
- */
-static void felem_inv(felem out, const felem in) {
- felem ftmp, ftmp2;
- /* each e_I will hold |in|^{2^I - 1} */
- felem e2, e4, e8, e16, e32, e64;
- unsigned i;
-
- felem_square(ftmp, in); /* 2^1 */
- felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */
- felem_assign(e2, ftmp);
- felem_square(ftmp, ftmp); /* 2^3 - 2^1 */
- felem_square(ftmp, ftmp); /* 2^4 - 2^2 */
- felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */
- felem_assign(e4, ftmp);
- felem_square(ftmp, ftmp); /* 2^5 - 2^1 */
- felem_square(ftmp, ftmp); /* 2^6 - 2^2 */
- felem_square(ftmp, ftmp); /* 2^7 - 2^3 */
- felem_square(ftmp, ftmp); /* 2^8 - 2^4 */
- felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */
- felem_assign(e8, ftmp);
- for (i = 0; i < 8; i++) {
- felem_square(ftmp, ftmp);
- } /* 2^16 - 2^8 */
- felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */
- felem_assign(e16, ftmp);
- for (i = 0; i < 16; i++) {
- felem_square(ftmp, ftmp);
- } /* 2^32 - 2^16 */
- felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */
- felem_assign(e32, ftmp);
- for (i = 0; i < 32; i++) {
- felem_square(ftmp, ftmp);
- } /* 2^64 - 2^32 */
- felem_assign(e64, ftmp);
- felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */
- for (i = 0; i < 192; i++) {
- felem_square(ftmp, ftmp);
- } /* 2^256 - 2^224 + 2^192 */
-
- felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */
- for (i = 0; i < 16; i++) {
- felem_square(ftmp2, ftmp2);
- } /* 2^80 - 2^16 */
- felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */
- for (i = 0; i < 8; i++) {
- felem_square(ftmp2, ftmp2);
- } /* 2^88 - 2^8 */
- felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */
- for (i = 0; i < 4; i++) {
- felem_square(ftmp2, ftmp2);
- } /* 2^92 - 2^4 */
- felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */
- felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */
- felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */
- felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */
- felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */
- felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */
- felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */
-
- felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */
-}
-
-/* felem_scalar_3 sets out=3*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_3(felem out) {
- limb carry = 0;
- unsigned i;
-
- for (i = 0;; i++) {
- out[i] *= 3;
- out[i] += carry;
- carry = out[i] >> 29;
- out[i] &= kBottom29Bits;
-
- i++;
- if (i == NLIMBS)
- break;
-
- out[i] *= 3;
- out[i] += carry;
- carry = out[i] >> 28;
- out[i] &= kBottom28Bits;
- }
-
- felem_reduce_carry(out, carry);
-}
-
-/* felem_scalar_4 sets out=4*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_4(felem out) {
- limb carry = 0, next_carry;
- unsigned i;
-
- for (i = 0;; i++) {
- next_carry = out[i] >> 27;
- out[i] <<= 2;
- out[i] &= kBottom29Bits;
- out[i] += carry;
- carry = next_carry + (out[i] >> 29);
- out[i] &= kBottom29Bits;
-
- i++;
- if (i == NLIMBS)
- break;
-
- next_carry = out[i] >> 26;
- out[i] <<= 2;
- out[i] &= kBottom28Bits;
- out[i] += carry;
- carry = next_carry + (out[i] >> 28);
- out[i] &= kBottom28Bits;
- }
-
- felem_reduce_carry(out, carry);
-}
-
-/* felem_scalar_8 sets out=8*out.
- *
- * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29.
- * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */
-static void felem_scalar_8(felem out) {
- limb carry = 0, next_carry;
- unsigned i;
-
- for (i = 0;; i++) {
- next_carry = out[i] >> 26;
- out[i] <<= 3;
- out[i] &= kBottom29Bits;
- out[i] += carry;
- carry = next_carry + (out[i] >> 29);
- out[i] &= kBottom29Bits;
-
- i++;
- if (i == NLIMBS)
- break;
-
- next_carry = out[i] >> 25;
- out[i] <<= 3;
- out[i] &= kBottom28Bits;
- out[i] += carry;
- carry = next_carry + (out[i] >> 28);
- out[i] &= kBottom28Bits;
- }
-
- felem_reduce_carry(out, carry);
-}
-
-/* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of
- * time depending on the value of |in|. */
-static char felem_is_zero_vartime(const felem in) {
- limb carry;
- int i;
- limb tmp[NLIMBS];
-
- felem_assign(tmp, in);
-
- /* First, reduce tmp to a minimal form. */
- do {
- carry = 0;
- for (i = 0;; i++) {
- tmp[i] += carry;
- carry = tmp[i] >> 29;
- tmp[i] &= kBottom29Bits;
-
- i++;
- if (i == NLIMBS)
- break;
-
- tmp[i] += carry;
- carry = tmp[i] >> 28;
- tmp[i] &= kBottom28Bits;
- }
-
- felem_reduce_carry(tmp, carry);
- } while (carry);
-
- /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */
- return memcmp(tmp, kZero, sizeof(tmp)) == 0 ||
- memcmp(tmp, kP, sizeof(tmp)) == 0 ||
- memcmp(tmp, k2P, sizeof(tmp)) == 0;
-}
-
-
-/* Group operations:
- *
- * Elements of the elliptic curve group are represented in Jacobian
- * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in
- * Jacobian form. */
-
-/* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */
-static void point_double(felem x_out, felem y_out, felem z_out, const felem x,
- const felem y, const felem z) {
- felem delta, gamma, alpha, beta, tmp, tmp2;
-
- felem_square(delta, z);
- felem_square(gamma, y);
- felem_mul(beta, x, gamma);
-
- felem_sum(tmp, x, delta);
- felem_diff(tmp2, x, delta);
- felem_mul(alpha, tmp, tmp2);
- felem_scalar_3(alpha);
-
- felem_sum(tmp, y, z);
- felem_square(tmp, tmp);
- felem_diff(tmp, tmp, gamma);
- felem_diff(z_out, tmp, delta);
-
- felem_scalar_4(beta);
- felem_square(x_out, alpha);
- felem_diff(x_out, x_out, beta);
- felem_diff(x_out, x_out, beta);
-
- felem_diff(tmp, beta, x_out);
- felem_mul(tmp, alpha, tmp);
- felem_square(tmp2, gamma);
- felem_scalar_8(tmp2);
- felem_diff(y_out, tmp, tmp2);
-}
-
-/* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}.
- * (i.e. the second point is affine.)
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * Note that this function does not handle P+P, infinity+P nor P+infinity
- * correctly. */
-static void point_add_mixed(felem x_out, felem y_out, felem z_out,
- const felem x1, const felem y1, const felem z1,
- const felem x2, const felem y2) {
- felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp;
-
- felem_square(z1z1, z1);
- felem_sum(tmp, z1, z1);
-
- felem_mul(u2, x2, z1z1);
- felem_mul(z1z1z1, z1, z1z1);
- felem_mul(s2, y2, z1z1z1);
- felem_diff(h, u2, x1);
- felem_sum(i, h, h);
- felem_square(i, i);
- felem_mul(j, h, i);
- felem_diff(r, s2, y1);
- felem_sum(r, r, r);
- felem_mul(v, x1, i);
-
- felem_mul(z_out, tmp, h);
- felem_square(rr, r);
- felem_diff(x_out, rr, j);
- felem_diff(x_out, x_out, v);
- felem_diff(x_out, x_out, v);
-
- felem_diff(tmp, v, x_out);
- felem_mul(y_out, tmp, r);
- felem_mul(tmp, y1, j);
- felem_diff(y_out, y_out, tmp);
- felem_diff(y_out, y_out, tmp);
-}
-
-/* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * Note that this function does not handle P+P, infinity+P nor P+infinity
- * correctly. */
-static void point_add(felem x_out, felem y_out, felem z_out, const felem x1,
- const felem y1, const felem z1, const felem x2,
- const felem y2, const felem z2) {
- felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
-
- felem_square(z1z1, z1);
- felem_square(z2z2, z2);
- felem_mul(u1, x1, z2z2);
-
- felem_sum(tmp, z1, z2);
- felem_square(tmp, tmp);
- felem_diff(tmp, tmp, z1z1);
- felem_diff(tmp, tmp, z2z2);
-
- felem_mul(z2z2z2, z2, z2z2);
- felem_mul(s1, y1, z2z2z2);
-
- felem_mul(u2, x2, z1z1);
- felem_mul(z1z1z1, z1, z1z1);
- felem_mul(s2, y2, z1z1z1);
- felem_diff(h, u2, u1);
- felem_sum(i, h, h);
- felem_square(i, i);
- felem_mul(j, h, i);
- felem_diff(r, s2, s1);
- felem_sum(r, r, r);
- felem_mul(v, u1, i);
-
- felem_mul(z_out, tmp, h);
- felem_square(rr, r);
- felem_diff(x_out, rr, j);
- felem_diff(x_out, x_out, v);
- felem_diff(x_out, x_out, v);
-
- felem_diff(tmp, v, x_out);
- felem_mul(y_out, tmp, r);
- felem_mul(tmp, s1, j);
- felem_diff(y_out, y_out, tmp);
- felem_diff(y_out, y_out, tmp);
-}
-
-/* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} +
- * {x2,y2,z2}.
- *
- * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
- *
- * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */
-static void point_add_or_double_vartime(
- felem x_out, felem y_out, felem z_out, const felem x1, const felem y1,
- const felem z1, const felem x2, const felem y2, const felem z2) {
- felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp;
- char x_equal, y_equal;
-
- felem_square(z1z1, z1);
- felem_square(z2z2, z2);
- felem_mul(u1, x1, z2z2);
-
- felem_sum(tmp, z1, z2);
- felem_square(tmp, tmp);
- felem_diff(tmp, tmp, z1z1);
- felem_diff(tmp, tmp, z2z2);
-
- felem_mul(z2z2z2, z2, z2z2);
- felem_mul(s1, y1, z2z2z2);
-
- felem_mul(u2, x2, z1z1);
- felem_mul(z1z1z1, z1, z1z1);
- felem_mul(s2, y2, z1z1z1);
- felem_diff(h, u2, u1);
- x_equal = felem_is_zero_vartime(h);
- felem_sum(i, h, h);
- felem_square(i, i);
- felem_mul(j, h, i);
- felem_diff(r, s2, s1);
- y_equal = felem_is_zero_vartime(r);
- if (x_equal && y_equal) {
- point_double(x_out, y_out, z_out, x1, y1, z1);
- return;
- }
- felem_sum(r, r, r);
- felem_mul(v, u1, i);
-
- felem_mul(z_out, tmp, h);
- felem_square(rr, r);
- felem_diff(x_out, rr, j);
- felem_diff(x_out, x_out, v);
- felem_diff(x_out, x_out, v);
-
- felem_diff(tmp, v, x_out);
- felem_mul(y_out, tmp, r);
- felem_mul(tmp, s1, j);
- felem_diff(y_out, y_out, tmp);
- felem_diff(y_out, y_out, tmp);
-}
-
-/* copy_conditional sets out=in if mask = 0xffffffff in constant time.
- *
- * On entry: mask is either 0 or 0xffffffff. */
-static void copy_conditional(felem out, const felem in, limb mask) {
- int i;
-
- for (i = 0; i < NLIMBS; i++) {
- const limb tmp = mask & (in[i] ^ out[i]);
- out[i] ^= tmp;
- }
-}
-
-/* select_affine_point sets {out_x,out_y} to the index'th entry of table.
- * On entry: index < 16, table[0] must be zero. */
-static void select_affine_point(felem out_x, felem out_y, const limb* table,
- limb index) {
- limb i, j;
-
- memset(out_x, 0, sizeof(felem));
- memset(out_y, 0, sizeof(felem));
-
- for (i = 1; i < 16; i++) {
- limb mask = i ^ index;
- mask |= mask >> 2;
- mask |= mask >> 1;
- mask &= 1;
- mask--;
- for (j = 0; j < NLIMBS; j++, table++) {
- out_x[j] |= *table & mask;
- }
- for (j = 0; j < NLIMBS; j++, table++) {
- out_y[j] |= *table & mask;
- }
- }
-}
-
-/* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of
- * table. On entry: index < 16, table[0] must be zero. */
-static void select_jacobian_point(felem out_x, felem out_y, felem out_z,
- const limb* table, limb index) {
- limb i, j;
-
- memset(out_x, 0, sizeof(felem));
- memset(out_y, 0, sizeof(felem));
- memset(out_z, 0, sizeof(felem));
-
- /* The implicit value at index 0 is all zero. We don't need to perform that
- * iteration of the loop because we already set out_* to zero. */
- table += 3 * NLIMBS;
-
- // Hit all entries to obscure cache profiling.
- for (i = 1; i < 16; i++) {
- limb mask = i ^ index;
- mask |= mask >> 2;
- mask |= mask >> 1;
- mask &= 1;
- mask--;
- for (j = 0; j < NLIMBS; j++, table++) {
- out_x[j] |= *table & mask;
- }
- for (j = 0; j < NLIMBS; j++, table++) {
- out_y[j] |= *table & mask;
- }
- for (j = 0; j < NLIMBS; j++, table++) {
- out_z[j] |= *table & mask;
- }
- }
-}
-
-/* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian
- * number. Note that the value of scalar must be less than the order of the
- * group. */
-static void scalar_base_mult(felem nx, felem ny, felem nz,
- const p256_int* scalar) {
- int i, j;
- limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask;
- u32 table_offset;
-
- felem px, py;
- felem tx, ty, tz;
-
- memset(nx, 0, sizeof(felem));
- memset(ny, 0, sizeof(felem));
- memset(nz, 0, sizeof(felem));
-
- /* The loop adds bits at positions 0, 64, 128 and 192, followed by
- * positions 32,96,160 and 224 and does this 32 times. */
- for (i = 0; i < 32; i++) {
- if (i) {
- point_double(nx, ny, nz, nx, ny, nz);
- }
- table_offset = 0;
- for (j = 0; j <= 32; j += 32) {
- char bit0 = p256_get_bit(scalar, 31 - i + j);
- char bit1 = p256_get_bit(scalar, 95 - i + j);
- char bit2 = p256_get_bit(scalar, 159 - i + j);
- char bit3 = p256_get_bit(scalar, 223 - i + j);
- limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3);
-
- select_affine_point(px, py, kPrecomputed + table_offset, index);
- table_offset += 30 * NLIMBS;
-
- /* Since scalar is less than the order of the group, we know that
- * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle
- * below. */
- point_add_mixed(tx, ty, tz, nx, ny, nz, px, py);
- /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero
- * (a.k.a. the point at infinity). We handle that situation by
- * copying the point from the table. */
- copy_conditional(nx, px, n_is_infinity_mask);
- copy_conditional(ny, py, n_is_infinity_mask);
- copy_conditional(nz, kOne, n_is_infinity_mask);
-
- /* Equally, the result is also wrong if the point from the table is
- * zero, which happens when the index is zero. We handle that by
- * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */
- p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
- mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
- copy_conditional(nx, tx, mask);
- copy_conditional(ny, ty, mask);
- copy_conditional(nz, tz, mask);
- /* If p was not zero, then n is now non-zero. */
- n_is_infinity_mask &= ~p_is_noninfinite_mask;
- }
- }
-}
-
-/* point_to_affine converts a Jacobian point to an affine point. If the input
- * is the point at infinity then it returns (0, 0) in constant time. */
-static void point_to_affine(felem x_out, felem y_out, const felem nx,
- const felem ny, const felem nz) {
- felem z_inv, z_inv_sq;
- felem_inv(z_inv, nz);
- felem_square(z_inv_sq, z_inv);
- felem_mul(x_out, nx, z_inv_sq);
- felem_mul(z_inv, z_inv, z_inv_sq);
- felem_mul(y_out, ny, z_inv);
-}
-
-/* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */
-static void scalar_mult(felem nx, felem ny, felem nz, const felem x,
- const felem y, const p256_int* scalar) {
- int i;
- felem px, py, pz, tx, ty, tz;
- felem precomp[16][3];
- limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask;
-
- /* We precompute 0,1,2,... times {x,y}. */
- memset(precomp, 0, sizeof(felem) * 3);
- memcpy(&precomp[1][0], x, sizeof(felem));
- memcpy(&precomp[1][1], y, sizeof(felem));
- memcpy(&precomp[1][2], kOne, sizeof(felem));
-
- for (i = 2; i < 16; i += 2) {
- point_double(precomp[i][0], precomp[i][1], precomp[i][2],
- precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]);
-
- point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2],
- precomp[i][0], precomp[i][1], precomp[i][2], x, y);
- }
-
- memset(nx, 0, sizeof(felem));
- memset(ny, 0, sizeof(felem));
- memset(nz, 0, sizeof(felem));
- n_is_infinity_mask = -1;
-
- /* We add in a window of four bits each iteration and do this 64 times. */
- for (i = 0; i < 256; i += 4) {
- if (i) {
- point_double(nx, ny, nz, nx, ny, nz);
- point_double(nx, ny, nz, nx, ny, nz);
- point_double(nx, ny, nz, nx, ny, nz);
- point_double(nx, ny, nz, nx, ny, nz);
- }
-
- index = (p256_get_bit(scalar, 255 - i - 0) << 3) |
- (p256_get_bit(scalar, 255 - i - 1) << 2) |
- (p256_get_bit(scalar, 255 - i - 2) << 1) |
- p256_get_bit(scalar, 255 - i - 3);
-
- /* See the comments in scalar_base_mult about handling infinities. */
- select_jacobian_point(px, py, pz, precomp[0][0], index);
- point_add(tx, ty, tz, nx, ny, nz, px, py, pz);
- copy_conditional(nx, px, n_is_infinity_mask);
- copy_conditional(ny, py, n_is_infinity_mask);
- copy_conditional(nz, pz, n_is_infinity_mask);
-
- p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index);
- mask = p_is_noninfinite_mask & ~n_is_infinity_mask;
-
- copy_conditional(nx, tx, mask);
- copy_conditional(ny, ty, mask);
- copy_conditional(nz, tz, mask);
- n_is_infinity_mask &= ~p_is_noninfinite_mask;
- }
-}
-
-#define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p
-
-#define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff} // 1 / 2^257 mod p256.p
-
-static const p256_int kR = { kRDigits };
-static const p256_int kRInv = { kRInvDigits };
-
-/* to_montgomery sets out = R*in. */
-static void to_montgomery(felem out, const p256_int* in) {
- p256_int in_shifted;
- int i;
-
- p256_init(&in_shifted);
- p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted);
-
- for (i = 0; i < NLIMBS; i++) {
- if ((i & 1) == 0) {
- out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits;
- p256_shr(&in_shifted, 29, &in_shifted);
- } else {
- out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits;
- p256_shr(&in_shifted, 28, &in_shifted);
- }
- }
-
- p256_clear(&in_shifted);
-}
-
-/* from_montgomery sets out=in/R. */
-static void from_montgomery(p256_int* out, const felem in) {
- p256_int result, tmp;
- int i, top;
-
- p256_init(&result);
- p256_init(&tmp);
-
- p256_add_d(&tmp, in[NLIMBS - 1], &result);
- for (i = NLIMBS - 2; i >= 0; i--) {
- if ((i & 1) == 0) {
- top = p256_shl(&result, 29, &tmp);
- } else {
- top = p256_shl(&result, 28, &tmp);
- }
- top |= p256_add_d(&tmp, in[i], &result);
- }
-
- p256_modmul(&SECP256r1_p, &kRInv, top, &result, out);
-
- p256_clear(&result);
- p256_clear(&tmp);
-}
-
-/* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the
- * order of the group. */
-void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) {
- felem x, y, z;
-
- scalar_base_mult(x, y, z, n);
-
- {
- felem x_affine, y_affine;
-
- point_to_affine(x_affine, y_affine, x, y, z);
- from_montgomery(out_x, x_affine);
- from_montgomery(out_y, y_affine);
- }
-}
-
-/* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where
- * n1 and n2 are < the order of the group.
- *
- * As indicated by the name, this function operates in variable time. This
- * is safe because it's used for signature validation which doesn't deal
- * with secrets. */
-void p256_points_mul_vartime(
- const p256_int* n1, const p256_int* n2, const p256_int* in_x,
- const p256_int* in_y, p256_int* out_x, p256_int* out_y) {
- felem x1, y1, z1, x2, y2, z2, px, py;
-
- /* If both scalars are zero, then the result is the point at infinity. */
- if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) {
- p256_clear(out_x);
- p256_clear(out_y);
- return;
- }
-
- to_montgomery(px, in_x);
- to_montgomery(py, in_y);
- scalar_base_mult(x1, y1, z1, n1);
- scalar_mult(x2, y2, z2, px, py, n2);
-
- if (p256_is_zero(n2) != 0) {
- /* If n2 == 0, then {x2,y2,z2} is zero and the result is just
- * {x1,y1,z1}. */
- } else if (p256_is_zero(n1) != 0) {
- /* If n1 == 0, then {x1,y1,z1} is zero and the result is just
- * {x2,y2,z2}. */
- memcpy(x1, x2, sizeof(x2));
- memcpy(y1, y2, sizeof(y2));
- memcpy(z1, z2, sizeof(z2));
- } else {
- /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */
- point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2);
- }
-
- point_to_affine(px, py, x1, y1, z1);
- from_montgomery(out_x, px);
- from_montgomery(out_y, py);
-}
diff --git a/libmincrypt/p256_ecdsa.c b/libmincrypt/p256_ecdsa.c
deleted file mode 100644
index f2264b0..0000000
--- a/libmincrypt/p256_ecdsa.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <string.h>
-
-#include "mincrypt/p256_ecdsa.h"
-#include "mincrypt/p256.h"
-
-int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y,
- const p256_int* message,
- const p256_int* r, const p256_int* s) {
- p256_int u, v;
-
- // Check public key.
- if (!p256_is_valid_point(key_x, key_y)) return 0;
-
- // Check r and s are != 0 % n.
- p256_mod(&SECP256r1_n, r, &u);
- p256_mod(&SECP256r1_n, s, &v);
- if (p256_is_zero(&u) || p256_is_zero(&v)) return 0;
-
- p256_modinv_vartime(&SECP256r1_n, s, &v);
- p256_modmul(&SECP256r1_n, message, 0, &v, &u); // message / s % n
- p256_modmul(&SECP256r1_n, r, 0, &v, &v); // r / s % n
-
- p256_points_mul_vartime(&u, &v,
- key_x, key_y,
- &u, &v);
-
- p256_mod(&SECP256r1_n, &u, &u); // (x coord % p) % n
- return p256_cmp(r, &u) == 0;
-}
-
diff --git a/libmincrypt/rsa.c b/libmincrypt/rsa.c
deleted file mode 100644
index 9061b3a..0000000
--- a/libmincrypt/rsa.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/* rsa.c
-**
-** Copyright 2012, The Android Open Source Project
-**
-** 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.
-** * Neither the name of Google Inc. nor the names of its contributors may
-** be used to endorse or promote products derived from this software
-** without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-#include "mincrypt/sha256.h"
-
-// a[] -= mod
-static void subM(const RSAPublicKey* key,
- uint32_t* a) {
- int64_t A = 0;
- int i;
- for (i = 0; i < key->len; ++i) {
- A += (uint64_t)a[i] - key->n[i];
- a[i] = (uint32_t)A;
- A >>= 32;
- }
-}
-
-// return a[] >= mod
-static int geM(const RSAPublicKey* key,
- const uint32_t* a) {
- int i;
- for (i = key->len; i;) {
- --i;
- if (a[i] < key->n[i]) return 0;
- if (a[i] > key->n[i]) return 1;
- }
- return 1; // equal
-}
-
-// montgomery c[] += a * b[] / R % mod
-static void montMulAdd(const RSAPublicKey* key,
- uint32_t* c,
- const uint32_t a,
- const uint32_t* b) {
- uint64_t A = (uint64_t)a * b[0] + c[0];
- uint32_t d0 = (uint32_t)A * key->n0inv;
- uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A;
- int i;
-
- for (i = 1; i < key->len; ++i) {
- A = (A >> 32) + (uint64_t)a * b[i] + c[i];
- B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A;
- c[i - 1] = (uint32_t)B;
- }
-
- A = (A >> 32) + (B >> 32);
-
- c[i - 1] = (uint32_t)A;
-
- if (A >> 32) {
- subM(key, c);
- }
-}
-
-// montgomery c[] = a[] * b[] / R % mod
-static void montMul(const RSAPublicKey* key,
- uint32_t* c,
- const uint32_t* a,
- const uint32_t* b) {
- int i;
- for (i = 0; i < key->len; ++i) {
- c[i] = 0;
- }
- for (i = 0; i < key->len; ++i) {
- montMulAdd(key, c, a[i], b);
- }
-}
-
-// In-place public exponentiation.
-// Input and output big-endian byte array in inout.
-static void modpow(const RSAPublicKey* key,
- uint8_t* inout) {
- uint32_t a[RSANUMWORDS];
- uint32_t aR[RSANUMWORDS];
- uint32_t aaR[RSANUMWORDS];
- uint32_t* aaa = 0;
- int i;
-
- // Convert from big endian byte array to little endian word array.
- for (i = 0; i < key->len; ++i) {
- uint32_t tmp =
- (inout[((key->len - 1 - i) * 4) + 0] << 24) |
- (inout[((key->len - 1 - i) * 4) + 1] << 16) |
- (inout[((key->len - 1 - i) * 4) + 2] << 8) |
- (inout[((key->len - 1 - i) * 4) + 3] << 0);
- a[i] = tmp;
- }
-
- if (key->exponent == 65537) {
- aaa = aaR; // Re-use location.
- montMul(key, aR, a, key->rr); // aR = a * RR / R mod M
- for (i = 0; i < 16; i += 2) {
- montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M
- montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M
- }
- montMul(key, aaa, aR, a); // aaa = aR * a / R mod M
- } else if (key->exponent == 3) {
- aaa = aR; // Re-use location.
- montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */
- montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */
- montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */
- }
-
- // Make sure aaa < mod; aaa is at most 1x mod too large.
- if (geM(key, aaa)) {
- subM(key, aaa);
- }
-
- // Convert to bigendian byte array
- for (i = key->len - 1; i >= 0; --i) {
- uint32_t tmp = aaa[i];
- *inout++ = tmp >> 24;
- *inout++ = tmp >> 16;
- *inout++ = tmp >> 8;
- *inout++ = tmp >> 0;
- }
-}
-
-// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature.
-// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the
-// other flavor which omits the optional parameter entirely). This code does not
-// accept signatures without the optional parameter.
-
-/*
-static const uint8_t sha_padding[RSANUMBYTES] = {
- 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30,
- 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a,
- 0x05, 0x00, 0x04, 0x14,
-
- // 20 bytes of hash go here.
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-};
-*/
-
-// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above.
-// At the location of the bytes of the hash all 00 are hashed.
-static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = {
- 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e,
- 0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68,
- 0x7c, 0xfb, 0xf1, 0x67
-};
-
-/*
-static const uint8_t sha256_padding[RSANUMBYTES] = {
- 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30,
- 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
- 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
-
- // 32 bytes of hash go here.
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-};
-*/
-
-// SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above.
-// At the location of the bytes of the hash all 00 are hashed.
-static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = {
- 0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92,
- 0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e,
- 0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd,
- 0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59,
-};
-
-// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash.
-// Both e=3 and e=65537 are supported. hash_len may be
-// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or
-// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash. No other
-// values are supported.
-//
-// Returns 1 on successful verification, 0 on failure.
-int RSA_verify(const RSAPublicKey *key,
- const uint8_t *signature,
- const int len,
- const uint8_t *hash,
- const int hash_len) {
- uint8_t buf[RSANUMBYTES];
- int i;
- const uint8_t* padding_hash;
-
- if (key->len != RSANUMWORDS) {
- return 0; // Wrong key passed in.
- }
-
- if (len != sizeof(buf)) {
- return 0; // Wrong input length.
- }
-
- if (hash_len != SHA_DIGEST_SIZE &&
- hash_len != SHA256_DIGEST_SIZE) {
- return 0; // Unsupported hash.
- }
-
- if (key->exponent != 3 && key->exponent != 65537) {
- return 0; // Unsupported exponent.
- }
-
- for (i = 0; i < len; ++i) { // Copy input to local workspace.
- buf[i] = signature[i];
- }
-
- modpow(key, buf); // In-place exponentiation.
-
- // Xor sha portion, so it all becomes 00 iff equal.
- for (i = len - hash_len; i < len; ++i) {
- buf[i] ^= *hash++;
- }
-
- // Hash resulting buf, in-place.
- switch (hash_len) {
- case SHA_DIGEST_SIZE:
- padding_hash = kExpectedPadShaRsa2048;
- SHA_hash(buf, len, buf);
- break;
- case SHA256_DIGEST_SIZE:
- padding_hash = kExpectedPadSha256Rsa2048;
- SHA256_hash(buf, len, buf);
- break;
- default:
- return 0;
- }
-
- // Compare against expected hash value.
- for (i = 0; i < hash_len; ++i) {
- if (buf[i] != padding_hash[i]) {
- return 0;
- }
- }
-
- return 1; // All checked out OK.
-}
diff --git a/libmincrypt/sha.c b/libmincrypt/sha.c
deleted file mode 100644
index 5bef32e..0000000
--- a/libmincrypt/sha.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/* sha.c
-**
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-** * Neither the name of Google Inc. nor the names of its contributors may
-** be used to endorse or promote products derived from this software
-** without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
-*/
-
-// Optimized for minimal code size.
-
-#include "mincrypt/sha.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-static void SHA1_Transform(SHA_CTX* ctx) {
- uint32_t W[80];
- uint32_t A, B, C, D, E;
- uint8_t* p = ctx->buf;
- int t;
-
- for(t = 0; t < 16; ++t) {
- uint32_t tmp = *p++ << 24;
- tmp |= *p++ << 16;
- tmp |= *p++ << 8;
- tmp |= *p++;
- W[t] = tmp;
- }
-
- for(; t < 80; t++) {
- W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
- }
-
- A = ctx->state[0];
- B = ctx->state[1];
- C = ctx->state[2];
- D = ctx->state[3];
- E = ctx->state[4];
-
- for(t = 0; t < 80; t++) {
- uint32_t tmp = rol(5,A) + E + W[t];
-
- if (t < 20)
- tmp += (D^(B&(C^D))) + 0x5A827999;
- else if ( t < 40)
- tmp += (B^C^D) + 0x6ED9EBA1;
- else if ( t < 60)
- tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC;
- else
- tmp += (B^C^D) + 0xCA62C1D6;
-
- E = D;
- D = C;
- C = rol(30,B);
- B = A;
- A = tmp;
- }
-
- ctx->state[0] += A;
- ctx->state[1] += B;
- ctx->state[2] += C;
- ctx->state[3] += D;
- ctx->state[4] += E;
-}
-
-static const HASH_VTAB SHA_VTAB = {
- SHA_init,
- SHA_update,
- SHA_final,
- SHA_hash,
- SHA_DIGEST_SIZE
-};
-
-void SHA_init(SHA_CTX* ctx) {
- ctx->f = &SHA_VTAB;
- ctx->state[0] = 0x67452301;
- ctx->state[1] = 0xEFCDAB89;
- ctx->state[2] = 0x98BADCFE;
- ctx->state[3] = 0x10325476;
- ctx->state[4] = 0xC3D2E1F0;
- ctx->count = 0;
-}
-
-
-void SHA_update(SHA_CTX* ctx, const void* data, int len) {
- int i = (int) (ctx->count & 63);
- const uint8_t* p = (const uint8_t*)data;
-
- ctx->count += len;
-
- while (len--) {
- ctx->buf[i++] = *p++;
- if (i == 64) {
- SHA1_Transform(ctx);
- i = 0;
- }
- }
-}
-
-
-const uint8_t* SHA_final(SHA_CTX* ctx) {
- uint8_t *p = ctx->buf;
- uint64_t cnt = ctx->count * 8;
- int i;
-
- SHA_update(ctx, (uint8_t*)"\x80", 1);
- while ((ctx->count & 63) != 56) {
- SHA_update(ctx, (uint8_t*)"\0", 1);
- }
- for (i = 0; i < 8; ++i) {
- uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
- SHA_update(ctx, &tmp, 1);
- }
-
- for (i = 0; i < 5; i++) {
- uint32_t tmp = ctx->state[i];
- *p++ = tmp >> 24;
- *p++ = tmp >> 16;
- *p++ = tmp >> 8;
- *p++ = tmp >> 0;
- }
-
- return ctx->buf;
-}
-
-/* Convenience function */
-const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) {
- SHA_CTX ctx;
- SHA_init(&ctx);
- SHA_update(&ctx, data, len);
- memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE);
- return digest;
-}
diff --git a/libmincrypt/sha256.c b/libmincrypt/sha256.c
deleted file mode 100644
index eb6e308..0000000
--- a/libmincrypt/sha256.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/* sha256.c
-**
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-** * Neither the name of Google Inc. nor the names of its contributors may
-** be used to endorse or promote products derived from this software
-** without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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.
-*/
-
-// Optimized for minimal code size.
-
-#include "mincrypt/sha256.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-
-#define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits))))
-#define shr(value, bits) ((value) >> (bits))
-
-static const uint32_t K[64] = {
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
- 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
- 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
- 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
- 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
- 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
- 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
- 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
- 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };
-
-static void SHA256_Transform(SHA256_CTX* ctx) {
- uint32_t W[64];
- uint32_t A, B, C, D, E, F, G, H;
- uint8_t* p = ctx->buf;
- int t;
-
- for(t = 0; t < 16; ++t) {
- uint32_t tmp = *p++ << 24;
- tmp |= *p++ << 16;
- tmp |= *p++ << 8;
- tmp |= *p++;
- W[t] = tmp;
- }
-
- for(; t < 64; t++) {
- uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3);
- uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10);
- W[t] = W[t-16] + s0 + W[t-7] + s1;
- }
-
- A = ctx->state[0];
- B = ctx->state[1];
- C = ctx->state[2];
- D = ctx->state[3];
- E = ctx->state[4];
- F = ctx->state[5];
- G = ctx->state[6];
- H = ctx->state[7];
-
- for(t = 0; t < 64; t++) {
- uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22);
- uint32_t maj = (A & B) ^ (A & C) ^ (B & C);
- uint32_t t2 = s0 + maj;
- uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25);
- uint32_t ch = (E & F) ^ ((~E) & G);
- uint32_t t1 = H + s1 + ch + K[t] + W[t];
-
- H = G;
- G = F;
- F = E;
- E = D + t1;
- D = C;
- C = B;
- B = A;
- A = t1 + t2;
- }
-
- ctx->state[0] += A;
- ctx->state[1] += B;
- ctx->state[2] += C;
- ctx->state[3] += D;
- ctx->state[4] += E;
- ctx->state[5] += F;
- ctx->state[6] += G;
- ctx->state[7] += H;
-}
-
-static const HASH_VTAB SHA256_VTAB = {
- SHA256_init,
- SHA256_update,
- SHA256_final,
- SHA256_hash,
- SHA256_DIGEST_SIZE
-};
-
-void SHA256_init(SHA256_CTX* ctx) {
- ctx->f = &SHA256_VTAB;
- ctx->state[0] = 0x6a09e667;
- ctx->state[1] = 0xbb67ae85;
- ctx->state[2] = 0x3c6ef372;
- ctx->state[3] = 0xa54ff53a;
- ctx->state[4] = 0x510e527f;
- ctx->state[5] = 0x9b05688c;
- ctx->state[6] = 0x1f83d9ab;
- ctx->state[7] = 0x5be0cd19;
- ctx->count = 0;
-}
-
-
-void SHA256_update(SHA256_CTX* ctx, const void* data, int len) {
- int i = (int) (ctx->count & 63);
- const uint8_t* p = (const uint8_t*)data;
-
- ctx->count += len;
-
- while (len--) {
- ctx->buf[i++] = *p++;
- if (i == 64) {
- SHA256_Transform(ctx);
- i = 0;
- }
- }
-}
-
-
-const uint8_t* SHA256_final(SHA256_CTX* ctx) {
- uint8_t *p = ctx->buf;
- uint64_t cnt = ctx->count * 8;
- int i;
-
- SHA256_update(ctx, (uint8_t*)"\x80", 1);
- while ((ctx->count & 63) != 56) {
- SHA256_update(ctx, (uint8_t*)"\0", 1);
- }
- for (i = 0; i < 8; ++i) {
- uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8));
- SHA256_update(ctx, &tmp, 1);
- }
-
- for (i = 0; i < 8; i++) {
- uint32_t tmp = ctx->state[i];
- *p++ = tmp >> 24;
- *p++ = tmp >> 16;
- *p++ = tmp >> 8;
- *p++ = tmp >> 0;
- }
-
- return ctx->buf;
-}
-
-/* Convenience function */
-const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) {
- SHA256_CTX ctx;
- SHA256_init(&ctx);
- SHA256_update(&ctx, data, len);
- memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE);
- return digest;
-}
diff --git a/libmincrypt/test/Android.mk b/libmincrypt/test/Android.mk
deleted file mode 100644
index 73ff7d0..0000000
--- a/libmincrypt/test/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := rsa_test
-LOCAL_SRC_FILES := rsa_test.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ecdsa_test
-LOCAL_SRC_FILES := ecdsa_test.c
-LOCAL_STATIC_LIBRARIES := libmincrypt
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libmincrypt/test/ecdsa_test.c b/libmincrypt/test/ecdsa_test.c
deleted file mode 100644
index 24ec013..0000000
--- a/libmincrypt/test/ecdsa_test.c
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright 2013 The Android Open Source Project
- *
- * 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.
- * * Neither the name of Google Inc. nor the names of its contributors may
- * be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-
-#include "mincrypt/dsa_sig.h"
-#include "mincrypt/p256.h"
-#include "mincrypt/p256_ecdsa.h"
-#include "mincrypt/sha256.h"
-
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
-
-/**
- * Messages signed using:
- *
------BEGIN EC PRIVATE KEY-----
-MHcCAQEEIDw6UiziVMbjlfSpOAIpA2tcL+v1OlznZLnpadO8BGi1oAoGCCqGSM49
-AwEHoUQDQgAEZw7VAOjAXYRFuhZWYBgjahdOvkwcAnjGkxQWytZW+iS1hI3ZGE24
-6XmNka9IGxAgj2n/ip+MuZJMFoJ9DRea3g==
------END EC PRIVATE KEY-----
- */
-
-p256_int key_x = {
- .a = {0xd656fa24u, 0x931416cau, 0x1c0278c6u, 0x174ebe4cu,
- 0x6018236au, 0x45ba1656u, 0xe8c05d84u, 0x670ed500u}
-};
-p256_int key_y = {
- .a = {0x0d179adeu, 0x4c16827du, 0x9f8cb992u, 0x8f69ff8au,
- 0x481b1020u, 0x798d91afu, 0x184db8e9u, 0xb5848dd9u}
-};
-
-char* message_1 =
- "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
- "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
- "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
- "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
- "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
- "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
- "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
- "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
- "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
- "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
- "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
- "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
- "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
- "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
- "d5 9d 73 be 12";
-
-char* signature_1 =
- "30 44 02 20 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
- "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
- "7c 98 25 d9 02 20 54 f3 7f 5a e9 36 9c a2 f0 51"
- "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
- "ea 57 7e 88 46 12";
-
-// Same as signature 1, but with leading zeroes.
-char* message_2 =
- "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
- "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
- "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
- "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
- "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
- "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
- "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
- "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
- "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
- "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
- "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
- "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
- "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
- "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
- "d5 9d 73 be 12";
-
-char* signature_2 =
- "30 46 02 21 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
- "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
- "7c 98 25 d9 02 21 00 54 f3 7f 5a e9 36 9c a2 f0 51"
- "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
- "ea 57 7e 88 46 12";
-
-// Excessive zeroes on the signature
-char* message_3 =
- "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
- "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
- "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
- "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
- "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
- "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
- "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
- "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
- "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
- "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
- "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
- "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
- "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
- "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
- "d5 9d 73 be 12";
-
-char* signature_3 =
- "30 4c 02 24 00 00 00 00 43 18 fc eb 3b a8 3a a8 a3 cf 41 b7"
- "81 4a f9 01 e1 8b 6e 95 c1 3a 83 25 9e a5 2e 66"
- "7c 98 25 d9 02 24 00 00 00 00 54 f3 7f 5a e9 36 9c a2 f0 51"
- "e0 6e 78 48 60 a3 f9 8a d5 2c 37 5a 0a 29 c9 f7"
- "ea 57 7e 88 46 12";
-
-
-char* good_dsa_signature_1 =
- "30 0D 02 01 01 02 08 00 A5 55 5A 01 FF A5 01";
-p256_int good_dsa_signature_1_r = {
- .a = {0x00000001U, 0x00000000U, 0x00000000U, 0x00000000U,
- 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
-};
-p256_int good_dsa_signature_1_s = {
- .a = {0x01FFA501U, 0x00A5555AU, 0x00000000U, 0x00000000U,
- 0x00000000U, 0x00000000U, 0x00000000U, 0x00000000U}
-};
-
-
-char* bad_dsa_signature_1 =
- "a0 06 02 01 01 02 01 01";
-
-char* bad_dsa_signature_2 =
- "30 07 02 01 01 02 01 01";
-
-char* bad_dsa_signature_3 =
- "30 06 82 01 01 02 01 01";
-
-char* bad_dsa_signature_4 =
- "30 06 02 00 01 02 01 01";
-
-char* bad_dsa_signature_5 =
- "30 06 02 01 01 82 01 01";
-
-char* bad_dsa_signature_6 =
- "30 05 02 01 01 02 00";
-
-char* bad_dsa_signature_7 =
- "30 06 02 01 01 02 00 01";
-
-unsigned char* parsehex(char* str, int* len) {
- // result can't be longer than input
- unsigned char* result = malloc(strlen(str));
-
- unsigned char* p = result;
- *len = 0;
-
- while (*str) {
- int b;
-
- while (isspace(*str)) str++;
-
- switch (*str) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- b = (*str - '0') << 4; break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- b = (*str - 'a' + 10) << 4; break;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- b = (*str - 'A' + 10) << 4; break;
- case '\0':
- return result;
- default:
- return NULL;
- }
- str++;
-
- while (isspace(*str)) str++;
-
- switch (*str) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- b |= *str - '0'; break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- b |= *str - 'a' + 10; break;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- b |= *str - 'A' + 10; break;
- default:
- return NULL;
- }
- str++;
-
- *p++ = b;
- ++*len;
- }
-
- return result;
-}
-
-int main(int arg __unused, char** argv __unused) {
-
- unsigned char hash_buf[SHA256_DIGEST_SIZE];
-
- unsigned char* message;
- int mlen;
- unsigned char* signature;
- int slen;
-
- p256_int hash;
- p256_int r;
- p256_int s;
-
- int success = 1;
-
-#define CHECK_DSA_SIG(sig, good) do {\
- message = parsehex(sig, &mlen); \
- int result = dsa_sig_unpack(message, mlen, &r, &s); \
- printf(#sig ": %s\n", result ? "good" : "bad"); \
- success = success && !(good ^ result); \
- free(message); \
- } while(0)
-#define CHECK_GOOD_DSA_SIG(n) do {\
- CHECK_DSA_SIG(good_dsa_signature_##n, 1); \
- int result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_r), P256_DIGITS(&r), \
- P256_NBYTES); \
- success = success && result; \
- printf(" R value %s\n", result ? "good" : "bad"); \
- result = !memcmp(P256_DIGITS(&good_dsa_signature_##n##_s), P256_DIGITS(&s), \
- P256_NBYTES); \
- success = success && result; \
- printf(" S value %s\n", result ? "good" : "bad"); \
- } while (0)
-#define CHECK_BAD_DSA_SIG(n) \
- CHECK_DSA_SIG(bad_dsa_signature_##n, 0)
-
- CHECK_GOOD_DSA_SIG(1);
-
- CHECK_BAD_DSA_SIG(1);
- CHECK_BAD_DSA_SIG(2);
- CHECK_BAD_DSA_SIG(3);
- CHECK_BAD_DSA_SIG(4);
- CHECK_BAD_DSA_SIG(5);
- CHECK_BAD_DSA_SIG(6);
- CHECK_BAD_DSA_SIG(7);
-
-
-#define TEST_MESSAGE(n) do {\
- message = parsehex(message_##n, &mlen); \
- SHA256_hash(message, mlen, hash_buf); \
- p256_from_bin(hash_buf, &hash); \
- signature = parsehex(signature_##n, &slen); \
- int result = dsa_sig_unpack(signature, slen, &r, &s); \
- if (result) { result = p256_ecdsa_verify(&key_x, &key_y, &hash, &r, &s); } \
- printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
- success = success && result; \
- free(signature); \
- } while(0)
-
- TEST_MESSAGE(1);
- TEST_MESSAGE(2);
- TEST_MESSAGE(3);
-
- printf("\n%s\n\n", success ? "PASS" : "FAIL");
-
- return !success;
-}
diff --git a/libmincrypt/test/rsa_test.c b/libmincrypt/test/rsa_test.c
deleted file mode 100644
index 055138f..0000000
--- a/libmincrypt/test/rsa_test.c
+++ /dev/null
@@ -1,842 +0,0 @@
-/*
-** Copyright 2013, The Android Open Source Project
-**
-** 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.
-** * Neither the name of Google Inc. nor the names of its contributors may
-** be used to endorse or promote products derived from this software
-** without specific prior written permission.
-**
-** THIS SOFTWARE IS PROVIDED BY Google Inc. ``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 Google Inc. 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 <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-
-#include "mincrypt/rsa.h"
-#include "mincrypt/sha.h"
-
-#ifndef __unused
-#define __unused __attribute__((unused))
-#endif
-
-// RSA test data taken from:
-//
-// ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15sign-vectors.txt
-
-// This is the result (reformatted) of running DumpPublicKey on:
-//
-// # Example 15: A 2048-bit RSA key pair
-// # -----------------------------------
-//
-//
-// # Public key
-// # ----------
-//
-// # Modulus:
-// df 27 1f d2 5f 86 44 49 6b 0c 81 be 4b d5 02 97
-// ef 09 9b 00 2a 6f d6 77 27 eb 44 9c ea 56 6e d6
-// a3 98 1a 71 31 2a 14 1c ab c9 81 5c 12 09 e3 20
-// a2 5b 32 46 4e 99 99 f1 8c a1 3a 9f d3 89 25 58
-// f9 e0 ad ef dd 36 50 dd 23 a3 f0 36 d6 0f e3 98
-// 84 37 06 a4 0b 0b 84 62 c8 be e3 bc e1 2f 1f 28
-// 60 c2 44 4c dc 6a 44 47 6a 75 ff 4a a2 42 73 cc
-// be 3b f8 02 48 46 5f 8f f8 c3 a7 f3 36 7d fc 0d
-// f5 b6 50 9a 4f 82 81 1c ed d8 1c da aa 73 c4 91
-// da 41 21 70 d5 44 d4 ba 96 b9 7f 0a fc 80 65 49
-// 8d 3a 49 fd 91 09 92 a1 f0 72 5b e2 4f 46 5c fe
-// 7e 0e ab f6 78 99 6c 50 bc 5e 75 24 ab f7 3f 15
-// e5 be f7 d5 18 39 4e 31 38 ce 49 44 50 6a aa af
-// 3f 9b 23 6d ca b8 fc 00 f8 7a f5 96 fd c3 d9 d6
-// c7 5c d5 08 36 2f ae 2c be dd cc 4c 74 50 b1 7b
-// 77 6c 07 9e cc a1 f2 56 35 1a 43 b9 7d be 21 53
-//
-// # Exponent:
-// 01 00 01
-
-RSAPublicKey key_15 = {
- .len = 64,
- .n0inv = 0xf0053525,
- .n = {2109612371u,890913721u,3433165398u,2003568542u,
- 1951445371u,3202206796u,909094444u,3344749832u,
- 4257470934u,4168807830u,3401120768u,1067131757u,
- 1349167791u,953043268u,406408753u,3854497749u,
- 2885107477u,3160306980u,2023320656u,2114890742u,
- 1330011390u,4034026466u,2433323681u,2369407485u,
- 4236272969u,2528739082u,3578057914u,3661701488u,
- 2859713681u,3990363354u,1333952796u,4122366106u,
- 914226189u,4173572083u,1212571535u,3191601154u,
- 2722264012u,1786117962u,3697951815u,1623344204u,
- 3777961768u,3367953340u,185304162u,2218198692u,
- 3591365528u,597946422u,3711324381u,4192251375u,
- 3548980568u,2359376543u,1318689265u,2723885638u,
- 302637856u,2882109788u,824841244u,2744654449u,
- 3931533014u,669729948u,711972471u,4010384128u,
- 1272251031u,1795981758u,1602634825u,3743883218u},
- .rr = {820482522u,2494434288u,1082168230u,731376296u,
- 1306039452u,3139792975u,2575869288u,3874938710u,
- 3198185181u,153506080u,1236489694u,1061859740u,
- 1174461268u,115279508u,1782749185u,238124145u,
- 3587596076u,2259236093u,1112265915u,4048059865u,
- 3890381098u,999426242u,794481771u,3804065613u,
- 2786019148u,461403875u,3072256692u,4079652654u,
- 3056719901u,1871565394u,212974856u,3359008174u,
- 1397773937u,3796256698u,914342841u,1097174457u,
- 3322220191u,3170814748u,2439215020u,618719336u,
- 3629353460u,496817177u,317052742u,380264245u,
- 1976007217u,2697736152u,312540864u,4291855337u,
- 697006561u,4234182488u,3904590917u,2609582216u,
- 451424084u,1805773827u,776344974u,1064489733u,
- 2633377036u,1954826648u,3202815814u,2240368662u,
- 2618582484u,2211196815u,4107362845u,3640258615u},
- .exponent = 65537,
-};
-
-// PKCS#1 v1.5 Signature Example 15.1
-
-char* message_1 =
- "f4 5d 55 f3 55 51 e9 75 d6 a8 dc 7e a9 f4 88 59"
- "39 40 cc 75 69 4a 27 8f 27 e5 78 a1 63 d8 39 b3"
- "40 40 84 18 08 cf 9c 58 c9 b8 72 8b f5 f9 ce 8e"
- "e8 11 ea 91 71 4f 47 ba b9 2d 0f 6d 5a 26 fc fe"
- "ea 6c d9 3b 91 0c 0a 2c 96 3e 64 eb 18 23 f1 02"
- "75 3d 41 f0 33 59 10 ad 3a 97 71 04 f1 aa f6 c3"
- "74 27 16 a9 75 5d 11 b8 ee d6 90 47 7f 44 5c 5d"
- "27 20 8b 2e 28 43 30 fa 3d 30 14 23 fa 7f 2d 08"
- "6e 0a d0 b8 92 b9 db 54 4e 45 6d 3f 0d ab 85 d9"
- "53 c1 2d 34 0a a8 73 ed a7 27 c8 a6 49 db 7f a6"
- "37 40 e2 5e 9a f1 53 3b 30 7e 61 32 99 93 11 0e"
- "95 19 4e 03 93 99 c3 82 4d 24 c5 1f 22 b2 6b de"
- "10 24 cd 39 59 58 a2 df eb 48 16 a6 e8 ad ed b5"
- "0b 1f 6b 56 d0 b3 06 0f f0 f1 c4 cb 0d 0e 00 1d"
- "d5 9d 73 be 12";
-
-char* signature_1 =
- "b7 5a 54 66 b6 5d 0f 30 0e f5 38 33 f2 17 5c 8a"
- "34 7a 38 04 fc 63 45 1d c9 02 f0 b7 1f 90 83 45"
- "9e d3 7a 51 79 a3 b7 23 a5 3f 10 51 64 2d 77 37"
- "4c 4c 6c 8d bb 1c a2 05 25 f5 c9 f3 2d b7 76 95"
- "35 56 da 31 29 0e 22 19 74 82 ce b6 99 06 c4 6a"
- "75 8f b0 e7 40 9b a8 01 07 7d 2a 0a 20 ea e7 d1"
- "d6 d3 92 ab 49 57 e8 6b 76 f0 65 2d 68 b8 39 88"
- "a7 8f 26 e1 11 72 ea 60 9b f8 49 fb bd 78 ad 7e"
- "dc e2 1d e6 62 a0 81 36 8c 04 06 07 ce e2 9d b0"
- "62 72 27 f4 49 63 ad 17 1d 22 93 b6 33 a3 92 e3"
- "31 dc a5 4f e3 08 27 52 f4 3f 63 c1 61 b4 47 a4"
- "c6 5a 68 75 67 0d 5f 66 00 fc c8 60 a1 ca eb 0a"
- "88 f8 fd ec 4e 56 43 98 a5 c4 6c 87 f6 8c e0 70"
- "01 f6 21 3a be 0a b5 62 5f 87 d1 90 25 f0 8d 81"
- "da c7 bd 45 86 bc 93 82 19 1f 6d 28 80 f6 22 7e"
- "5d f3 ee d2 1e 77 92 d2 49 48 04 87 f3 65 52 61";
-
-// PKCS#1 v1.5 Signature Example 15.2
-
-char *message_2 =
- "c1 4b 4c 60 75 b2 f9 aa d6 61 de f4 ec fd 3c b9 "
- "33 c6 23 f4 e6 3b f5 34 10 d2 f0 16 d1 ab 98 e2 "
- "72 9e cc f8 00 6c d8 e0 80 50 73 7d 95 fd bf 29 "
- "6b 66 f5 b9 79 2a 90 29 36 c4 f7 ac 69 f5 14 53 "
- "ce 43 69 45 2d c2 2d 96 f0 37 74 81 14 66 20 00 "
- "dd 9c d3 a5 e1 79 f4 e0 f8 1f a6 a0 31 1c a1 ae "
- "e6 51 9a 0f 63 ce c7 8d 27 bb 72 63 93 fb 7f 1f "
- "88 cd e7 c9 7f 8a 66 cd 66 30 12 81 da c3 f3 a4 "
- "33 24 8c 75 d6 c2 dc d7 08 b6 a9 7b 0a 3f 32 5e "
- "0b 29 64 f8 a5 81 9e 47 9b ";
-
-char* signature_2 =
- "af a7 34 34 62 be a1 22 cc 14 9f ca 70 ab da e7"
- "94 46 67 7d b5 37 36 66 af 7d c3 13 01 5f 4d e7"
- "86 e6 e3 94 94 6f ad 3c c0 e2 b0 2b ed ba 50 47"
- "fe 9e 2d 7d 09 97 05 e4 a3 9f 28 68 32 79 cf 0a"
- "c8 5c 15 30 41 22 42 c0 e9 18 95 3b e0 00 e9 39"
- "cf 3b f1 82 52 5e 19 93 70 fa 79 07 eb a6 9d 5d"
- "b4 63 10 17 c0 e3 6d f7 03 79 b5 db 8d 4c 69 5a"
- "97 9a 8e 61 73 22 40 65 d7 dc 15 13 2e f2 8c d8"
- "22 79 51 63 06 3b 54 c6 51 14 1b e8 6d 36 e3 67"
- "35 bc 61 f3 1f ca 57 4e 53 09 f3 a3 bb df 91 ef"
- "f1 2b 99 e9 cc 17 44 f1 ee 9a 1b d2 2c 5b ad 96"
- "ad 48 19 29 25 1f 03 43 fd 36 bc f0 ac de 7f 11"
- "e5 ad 60 97 77 21 20 27 96 fe 06 1f 9a da 1f c4"
- "c8 e0 0d 60 22 a8 35 75 85 ff e9 fd d5 93 31 a2"
- "8c 4a a3 12 15 88 fb 6c f6 83 96 d8 ac 05 46 59"
- "95 00 c9 70 85 00 a5 97 2b d5 4f 72 cf 8d b0 c8";
-
-// PKCS#1 v1.5 Signature Example 15.3
-
-char* message_3 =
- "d0 23 71 ad 7e e4 8b bf db 27 63 de 7a 84 3b 94 "
- "08 ce 5e b5 ab f8 47 ca 3d 73 59 86 df 84 e9 06 "
- "0b db cd d3 a5 5b a5 5d de 20 d4 76 1e 1a 21 d2 "
- "25 c1 a1 86 f4 ac 4b 30 19 d3 ad f7 8f e6 33 46 "
- "67 f5 6f 70 c9 01 a0 a2 70 0c 6f 0d 56 ad d7 19 "
- "59 2d c8 8f 6d 23 06 c7 00 9f 6e 7a 63 5b 4c b3 "
- "a5 02 df e6 8d dc 58 d0 3b e1 0a 11 70 00 4f e7 "
- "4d d3 e4 6b 82 59 1f f7 54 14 f0 c4 a0 3e 60 5e "
- "20 52 4f 24 16 f1 2e ca 58 9f 11 1b 75 d6 39 c6 "
- "1b aa 80 ca fd 05 cf 35 00 24 4a 21 9e d9 ce d9 "
- "f0 b1 02 97 18 2b 65 3b 52 6f 40 0f 29 53 ba 21 "
- "4d 5b cd 47 88 41 32 87 2a e9 0d 4d 6b 1f 42 15 "
- "39 f9 f3 46 62 a5 6d c0 e7 b4 b9 23 b6 23 1e 30 "
- "d2 67 67 97 81 7f 7c 33 7b 5a c8 24 ba 93 14 3b "
- "33 81 fa 3d ce 0e 6a eb d3 8e 67 73 51 87 b1 eb "
- "d9 5c 02 ";
-
-char* signature_3 =
- "3b ac 63 f8 6e 3b 70 27 12 03 10 6b 9c 79 aa bd"
- "9f 47 7c 56 e4 ee 58 a4 fc e5 ba f2 ca b4 96 0f"
- "88 39 1c 9c 23 69 8b e7 5c 99 ae df 9e 1a bf 17"
- "05 be 1d ac 33 14 0a db 48 eb 31 f4 50 bb 9e fe"
- "83 b7 b9 0d b7 f1 57 6d 33 f4 0c 1c ba 4b 8d 6b"
- "1d 33 23 56 4b 0f 17 74 11 4f a7 c0 8e 6d 1e 20"
- "dd 8f bb a9 b6 ac 7a d4 1e 26 b4 56 8f 4a 8a ac"
- "bf d1 78 a8 f8 d2 c9 d5 f5 b8 81 12 93 5a 8b c9"
- "ae 32 cd a4 0b 8d 20 37 55 10 73 50 96 53 68 18"
- "ce 2b 2d b7 1a 97 72 c9 b0 dd a0 9a e1 01 52 fa"
- "11 46 62 18 d0 91 b5 3d 92 54 30 61 b7 29 4a 55"
- "be 82 ff 35 d5 c3 2f a2 33 f0 5a aa c7 58 50 30"
- "7e cf 81 38 3c 11 16 74 39 7b 1a 1b 9d 3b f7 61"
- "2c cb e5 ba cd 2b 38 f0 a9 83 97 b2 4c 83 65 8f"
- "b6 c0 b4 14 0e f1 19 70 c4 63 0d 44 34 4e 76 ea"
- "ed 74 dc be e8 11 db f6 57 59 41 f0 8a 65 23 b8";
-
-// PKCS#1 v1.5 Signature Example 15.4
-
-char* message_4 =
- "29 03 55 84 ab 7e 02 26 a9 ec 4b 02 e8 dc f1 27 "
- "2d c9 a4 1d 73 e2 82 00 07 b0 f6 e2 1f ec cd 5b "
- "d9 db b9 ef 88 cd 67 58 76 9e e1 f9 56 da 7a d1 "
- "84 41 de 6f ab 83 86 db c6 93 ";
-
-char* signature_4 =
- "28 d8 e3 fc d5 dd db 21 ff bd 8d f1 63 0d 73 77"
- "aa 26 51 e1 4c ad 1c 0e 43 cc c5 2f 90 7f 94 6d"
- "66 de 72 54 e2 7a 6c 19 0e b0 22 ee 89 ec f6 22"
- "4b 09 7b 71 06 8c d6 07 28 a1 ae d6 4b 80 e5 45"
- "7b d3 10 6d d9 17 06 c9 37 c9 79 5f 2b 36 36 7f"
- "f1 53 dc 25 19 a8 db 9b df 2c 80 74 30 c4 51 de"
- "17 bb cd 0c e7 82 b3 e8 f1 02 4d 90 62 4d ea 7f"
- "1e ed c7 42 0b 7e 7c aa 65 77 ce f4 31 41 a7 26"
- "42 06 58 0e 44 a1 67 df 5e 41 ee a0 e6 9a 80 54"
- "54 c4 0e ef c1 3f 48 e4 23 d7 a3 2d 02 ed 42 c0"
- "ab 03 d0 a7 cf 70 c5 86 0a c9 2e 03 ee 00 5b 60"
- "ff 35 03 42 4b 98 cc 89 45 68 c7 c5 6a 02 33 55"
- "1c eb e5 88 cf 8b 01 67 b7 df 13 ad ca d8 28 67"
- "68 10 49 9c 70 4d a7 ae 23 41 4d 69 e3 c0 d2 db"
- "5d cb c2 61 3b c1 20 42 1f 9e 36 53 c5 a8 76 72"
- "97 64 3c 7e 07 40 de 01 63 55 45 3d 6c 95 ae 72";
-
-// PKCS#1 v1.5 Signature Example 15.5
-
-char* message_5 =
- "bd a3 a1 c7 90 59 ea e5 98 30 8d 3d f6 09 ";
-
-char* signature_5 =
- "a1 56 17 6c b9 67 77 c7 fb 96 10 5d bd 91 3b c4"
- "f7 40 54 f6 80 7c 60 08 a1 a9 56 ea 92 c1 f8 1c"
- "b8 97 dc 4b 92 ef 9f 4e 40 66 8d c7 c5 56 90 1a"
- "cb 6c f2 69 fe 61 5b 0f b7 2b 30 a5 13 38 69 23"
- "14 b0 e5 87 8a 88 c2 c7 77 4b d1 69 39 b5 ab d8"
- "2b 44 29 d6 7b d7 ac 8e 5e a7 fe 92 4e 20 a6 ec"
- "66 22 91 f2 54 8d 73 4f 66 34 86 8b 03 9a a5 f9"
- "d4 d9 06 b2 d0 cb 85 85 bf 42 85 47 af c9 1c 6e"
- "20 52 dd cd 00 1c 3e f8 c8 ee fc 3b 6b 2a 82 b6"
- "f9 c8 8c 56 f2 e2 c3 cb 0b e4 b8 0d a9 5e ba 37"
- "1d 8b 5f 60 f9 25 38 74 3d db b5 da 29 72 c7 1f"
- "e7 b9 f1 b7 90 26 8a 0e 77 0f c5 eb 4d 5d d8 52"
- "47 d4 8a e2 ec 3f 26 25 5a 39 85 52 02 06 a1 f2"
- "68 e4 83 e9 db b1 d5 ca b1 90 91 76 06 de 31 e7"
- "c5 18 2d 8f 15 1b f4 1d fe cc ae d7 cd e6 90 b2"
- "16 47 10 6b 49 0c 72 9d 54 a8 fe 28 02 a6 d1 26";
-
-// PKCS#1 v1.5 Signature Example 15.6
-
-char* message_6 =
- "c1 87 91 5e 4e 87 da 81 c0 8e d4 35 6a 0c ce ac "
- "1c 4f b5 c0 46 b4 52 81 b3 87 ec 28 f1 ab fd 56 "
- "7e 54 6b 23 6b 37 d0 1a e7 1d 3b 28 34 36 5d 3d "
- "f3 80 b7 50 61 b7 36 b0 13 0b 07 0b e5 8a e8 a4 "
- "6d 12 16 63 61 b6 13 db c4 7d fa eb 4c a7 46 45 "
- "6c 2e 88 83 85 52 5c ca 9d d1 c3 c7 a9 ad a7 6d "
- "6c ";;
-
-char* signature_6 =
- "9c ab 74 16 36 08 66 9f 75 55 a3 33 cf 19 6f e3"
- "a0 e9 e5 eb 1a 32 d3 4b b5 c8 5f f6 89 aa ab 0e"
- "3e 65 66 8e d3 b1 15 3f 94 eb 3d 8b e3 79 b8 ee"
- "f0 07 c4 a0 2c 70 71 ce 30 d8 bb 34 1e 58 c6 20"
- "f7 3d 37 b4 ec bf 48 be 29 4f 6c 9e 0e cb 5e 63"
- "fe c4 1f 12 0e 55 53 df a0 eb eb bb 72 64 0a 95"
- "37 ba dc b4 51 33 02 29 d9 f7 10 f6 2e 3e d8 ec"
- "78 4e 50 ee 1d 92 62 b4 26 71 34 00 11 d7 d0 98"
- "c6 f2 55 7b 21 31 fa 9b d0 25 46 36 59 7e 88 ec"
- "b3 5a 24 0e f0 fd 85 95 71 24 df 80 80 fe e1 e1"
- "49 af 93 99 89 e8 6b 26 c8 5a 58 81 fa e8 67 3d"
- "9f d4 08 00 dd 13 4e b9 bd b6 41 0f 42 0b 0a a9"
- "7b 20 ef cf 2e b0 c8 07 fa eb 83 a3 cc d9 b5 1d"
- "45 53 e4 1d fc 0d f6 ca 80 a1 e8 1d c2 34 bb 83"
- "89 dd 19 5a 38 b4 2d e4 ed c4 9d 34 64 78 b9 f1"
- "1f 05 57 20 5f 5b 0b d7 ff e9 c8 50 f3 96 d7 c4";;
-
-// PKCS#1 v1.5 Signature Example 15.7
-
-char* message_7 =
- "ab fa 2e cb 7d 29 bd 5b cb 99 31 ce 2b ad 2f 74 "
- "38 3e 95 68 3c ee 11 02 2f 08 e8 e7 d0 b8 fa 05 "
- "8b f9 eb 7e b5 f9 88 68 b5 bb 1f b5 c3 1c ed a3 "
- "a6 4f 1a 12 cd f2 0f cd 0e 5a 24 6d 7a 17 73 d8 "
- "db a0 e3 b2 77 54 5b ab e5 8f 2b 96 e3 f4 ed c1 "
- "8e ab f5 cd 2a 56 0f ca 75 fe 96 e0 7d 85 9d ef "
- "b2 56 4f 3a 34 f1 6f 11 e9 1b 3a 71 7b 41 af 53 "
- "f6 60 53 23 00 1a a4 06 c6 ";
-
-char* signature_7 =
- "c4 b4 37 bc f7 03 f3 52 e1 fa f7 4e b9 62 20 39"
- "42 6b 56 72 ca f2 a7 b3 81 c6 c4 f0 19 1e 7e 4a"
- "98 f0 ee bc d6 f4 17 84 c2 53 7f f0 f9 9e 74 98"
- "2c 87 20 1b fb c6 5e ae 83 2d b7 1d 16 da ca db"
- "09 77 e5 c5 04 67 9e 40 be 0f 9d b0 6f fd 84 8d"
- "d2 e5 c3 8a 7e c0 21 e7 f6 8c 47 df d3 8c c3 54"
- "49 3d 53 39 b4 59 5a 5b f3 1e 3f 8f 13 81 68 07"
- "37 3d f6 ad 0d c7 e7 31 e5 1a d1 9e b4 75 4b 13"
- "44 85 84 2f e7 09 d3 78 44 4d 8e 36 b1 72 4a 4f"
- "da 21 ca fe e6 53 ab 80 74 7f 79 52 ee 80 4d ea"
- "b1 03 9d 84 13 99 45 bb f4 be 82 00 87 53 f3 c5"
- "4c 78 21 a1 d2 41 f4 21 79 c7 94 ef 70 42 bb f9"
- "95 56 56 22 2e 45 c3 43 69 a3 84 69 7b 6a e7 42"
- "e1 8f a5 ca 7a ba d2 7d 9f e7 10 52 e3 31 0d 0f"
- "52 c8 d1 2e a3 3b f0 53 a3 00 f4 af c4 f0 98 df"
- "4e 6d 88 67 79 d6 45 94 d3 69 15 8f db c1 f6 94";
-
-// PKCS#1 v1.5 Signature Example 15.8
-
-char* message_8 =
- "df 40 44 a8 9a 83 e9 fc bf 12 62 54 0a e3 03 8b "
- "bc 90 f2 b2 62 8b f2 a4 46 7a c6 77 22 d8 54 6b "
- "3a 71 cb 0e a4 16 69 d5 b4 d6 18 59 c1 b4 e4 7c "
- "ec c5 93 3f 75 7e c8 6d b0 64 4e 31 18 12 d0 0f "
- "b8 02 f0 34 00 63 9c 0e 36 4d ae 5a eb c5 79 1b "
- "c6 55 76 23 61 bc 43 c5 3d 3c 78 86 76 8f 79 68 "
- "c1 c5 44 c6 f7 9f 7b e8 20 c7 e2 bd 2f 9d 73 e6 "
- "2d ed 6d 2e 93 7e 6a 6d ae f9 0e e3 7a 1a 52 a5 "
- "4f 00 e3 1a dd d6 48 94 cf 4c 02 e1 60 99 e2 9f "
- "9e b7 f1 a7 bb 7f 84 c4 7a 2b 59 48 13 be 02 a1 "
- "7b 7f c4 3b 34 c2 2c 91 92 52 64 12 6c 89 f8 6b "
- "b4 d8 7f 3e f1 31 29 6c 53 a3 08 e0 33 1d ac 8b "
- "af 3b 63 42 22 66 ec ef 2b 90 78 15 35 db da 41 "
- "cb d0 cf 22 a8 cb fb 53 2e c6 8f c6 af b2 ac 06 ";
-
-char* signature_8 =
- "14 14 b3 85 67 ae 6d 97 3e de 4a 06 84 2d cc 0e"
- "05 59 b1 9e 65 a4 88 9b db ab d0 fd 02 80 68 29"
- "13 ba cd 5d c2 f0 1b 30 bb 19 eb 81 0b 7d 9d ed"
- "32 b2 84 f1 47 bb e7 71 c9 30 c6 05 2a a7 34 13"
- "90 a8 49 f8 1d a9 cd 11 e5 ec cf 24 6d ba e9 5f"
- "a9 58 28 e9 ae 0c a3 55 03 25 32 6d ee f9 f4 95"
- "30 ba 44 1b ed 4a c2 9c 02 9c 9a 27 36 b1 a4 19"
- "0b 85 08 4a d1 50 42 6b 46 d7 f8 5b d7 02 f4 8d"
- "ac 5f 71 33 0b c4 23 a7 66 c6 5c c1 dc ab 20 d3"
- "d3 bb a7 2b 63 b3 ef 82 44 d4 2f 15 7c b7 e3 a8"
- "ba 5c 05 27 2c 64 cc 1a d2 1a 13 49 3c 39 11 f6"
- "0b 4e 9f 4e cc 99 00 eb 05 6e e5 9d 6f e4 b8 ff"
- "6e 80 48 cc c0 f3 8f 28 36 fd 3d fe 91 bf 4a 38"
- "6e 1e cc 2c 32 83 9f 0c a4 d1 b2 7a 56 8f a9 40"
- "dd 64 ad 16 bd 01 25 d0 34 8e 38 30 85 f0 88 94"
- "86 1c a1 89 87 22 7d 37 b4 2b 58 4a 83 57 cb 04";
-
-// PKCS#1 v1.5 Signature Example 15.9
-
-char* message_9 =
- "ea 94 1f f0 6f 86 c2 26 92 7f cf 0e 3b 11 b0 87 "
- "26 76 17 0c 1b fc 33 bd a8 e2 65 c7 77 71 f9 d0 "
- "85 01 64 a5 ee cb cc 5c e8 27 fb fa 07 c8 52 14 "
- "79 6d 81 27 e8 ca a8 18 94 ea 61 ce b1 44 9e 72 "
- "fe a0 a4 c9 43 b2 da 6d 9b 10 5f e0 53 b9 03 9a "
- "9c c5 3d 42 0b 75 39 fa b2 23 9c 6b 51 d1 7e 69 "
- "4c 95 7d 4b 0f 09 84 46 18 79 a0 75 9c 44 01 be "
- "ec d4 c6 06 a0 af bd 7a 07 6f 50 a2 df c2 80 7f "
- "24 f1 91 9b aa 77 46 d3 a6 4e 26 8e d3 f5 f8 e6 "
- "da 83 a2 a5 c9 15 2f 83 7c b0 78 12 bd 5b a7 d3 "
- "a0 79 85 de 88 11 3c 17 96 e9 b4 66 ec 29 9c 5a "
- "c1 05 9e 27 f0 94 15 ";
-
-char* signature_9 =
- "ce eb 84 cc b4 e9 09 92 65 65 07 21 ee a0 e8 ec"
- "89 ca 25 bd 35 4d 4f 64 56 49 67 be 9d 4b 08 b3"
- "f1 c0 18 53 9c 9d 37 1c f8 96 1f 22 91 fb e0 dc"
- "2f 2f 95 fe a4 7b 63 9f 1e 12 f4 bc 38 1c ef 0c"
- "2b 7a 7b 95 c3 ad f2 76 05 b7 f6 39 98 c3 cb ad"
- "54 28 08 c3 82 2e 06 4d 4a d1 40 93 67 9e 6e 01"
- "41 8a 6d 5c 05 96 84 cd 56 e3 4e d6 5a b6 05 b8"
- "de 4f cf a6 40 47 4a 54 a8 25 1b bb 73 26 a4 2d"
- "08 58 5c fc fc 95 67 69 b1 5b 6d 7f df 7d a8 4f"
- "81 97 6e aa 41 d6 92 38 0f f1 0e ae cf e0 a5 79"
- "68 29 09 b5 52 1f ad e8 54 d7 97 b8 a0 34 5b 9a"
- "86 4e 05 88 f6 ca dd bf 65 f1 77 99 8e 18 0d 1f"
- "10 24 43 e6 dc a5 3a 94 82 3c aa 9c 3b 35 f3 22"
- "58 3c 70 3a f6 74 76 15 9e c7 ec 93 d1 76 9b 30"
- "0a f0 e7 15 7d c2 98 c6 cd 2d ee 22 62 f8 cd dc"
- "10 f1 1e 01 74 14 71 bb fd 65 18 a1 75 73 45 75";
-
-// PKCS#1 v1.5 Signature Example 15.10
-
-char* message_10 =
- "d8 b8 16 45 c1 3c d7 ec f5 d0 0e d2 c9 1b 9a cd "
- "46 c1 55 68 e5 30 3c 4a 97 75 ed e7 6b 48 40 3d "
- "6b e5 6c 05 b6 b1 cf 77 c6 e7 5d e0 96 c5 cb 35 "
- "51 cb 6f a9 64 f3 c8 79 cf 58 9d 28 e1 da 2f 9d "
- "ec ";
-
-char* signature_10 =
- "27 45 07 4c a9 71 75 d9 92 e2 b4 47 91 c3 23 c5"
- "71 67 16 5c dd 8d a5 79 cd ef 46 86 b9 bb 40 4b"
- "d3 6a 56 50 4e b1 fd 77 0f 60 bf a1 88 a7 b2 4b"
- "0c 91 e8 81 c2 4e 35 b0 4d c4 dd 4c e3 85 66 bc"
- "c9 ce 54 f4 9a 17 5f c9 d0 b2 25 22 d9 57 90 47"
- "f9 ed 42 ec a8 3f 76 4a 10 16 39 97 94 7e 7d 2b"
- "52 ff 08 98 0e 7e 7c 22 57 93 7b 23 f3 d2 79 d4"
- "cd 17 d6 f4 95 54 63 73 d9 83 d5 36 ef d7 d1 b6"
- "71 81 ca 2c b5 0a c6 16 c5 c7 ab fb b9 26 0b 91"
- "b1 a3 8e 47 24 20 01 ff 45 2f 8d e1 0c a6 ea ea"
- "dc af 9e dc 28 95 6f 28 a7 11 29 1f c9 a8 08 78"
- "b8 ba 4c fe 25 b8 28 1c b8 0b c9 cd 6d 2b d1 82"
- "52 46 ee be 25 2d 99 57 ef 93 70 73 52 08 4e 6d"
- "36 d4 23 55 1b f2 66 a8 53 40 fb 4a 6a f3 70 88"
- "0a ab 07 15 3d 01 f4 8d 08 6d f0 bf be c0 5e 7b"
- "44 3b 97 e7 17 18 97 0e 2f 4b f6 20 23 e9 5b 67";
-
-// PKCS#1 v1.5 Signature Example 15.11
-
-char* message_11 =
- "e5 73 9b 6c 14 c9 2d 51 0d 95 b8 26 93 33 37 ff "
- "0d 24 ef 72 1a c4 ef 64 c2 ba d2 64 be 8b 44 ef "
- "a1 51 6e 08 a2 7e b6 b6 11 d3 30 1d f0 06 2d ae "
- "fc 73 a8 c0 d9 2e 2c 52 1f ac bc 7b 26 47 38 76 "
- "7e a6 fc 97 d5 88 a0 ba f6 ce 50 ad f7 9e 60 0b "
- "d2 9e 34 5f cb 1d ba 71 ac 5c 02 89 02 3f e4 a8 "
- "2b 46 a5 40 77 19 19 7d 2e 95 8e 35 31 fd 54 ae "
- "f9 03 aa bb 43 55 f8 83 18 99 4e d3 c3 dd 62 f4 "
- "20 a7 ";
-
-char* signature_11 =
- "be 40 a5 fb 94 f1 13 e1 b3 ef f6 b6 a3 39 86 f2"
- "02 e3 63 f0 74 83 b7 92 e6 8d fa 55 54 df 04 66"
- "cc 32 15 09 50 78 3b 4d 96 8b 63 9a 04 fd 2f b9"
- "7f 6e b9 67 02 1f 5a dc cb 9f ca 95 ac c8 f2 cd"
- "88 5a 38 0b 0a 4e 82 bc 76 07 64 db ab 88 c1 e6"
- "c0 25 5c aa 94 f2 32 19 9d 6f 59 7c c9 14 5b 00"
- "e3 d4 ba 34 6b 55 9a 88 33 ad 15 16 ad 51 63 f0"
- "16 af 6a 59 83 1c 82 ea 13 c8 22 4d 84 d0 76 5a"
- "9d 12 38 4d a4 60 a8 53 1b 4c 40 7e 04 f4 f3 50"
- "70 9e b9 f0 8f 5b 22 0f fb 45 ab f6 b7 5d 15 79"
- "fd 3f 1e b5 5f c7 5b 00 af 8b a3 b0 87 82 7f e9"
- "ae 9f b4 f6 c5 fa 63 03 1f e5 82 85 2f e2 83 4f"
- "9c 89 bf f5 3e 25 52 21 6b c7 c1 d4 a3 d5 dc 2b"
- "a6 95 5c d9 b1 7d 13 63 e7 fe e8 ed 76 29 75 3f"
- "f3 12 5e dd 48 52 1a e3 b9 b0 32 17 f4 49 6d 0d"
- "8e de 57 ac bc 5b d4 de ae 74 a5 6f 86 67 1d e2";
-
-// PKCS#1 v1.5 Signature Example 15.12
-
-char* message_12 =
- "7a f4 28 35 91 7a 88 d6 b3 c6 71 6b a2 f5 b0 d5 "
- "b2 0b d4 e2 e6 e5 74 e0 6a f1 ee f7 c8 11 31 be "
- "22 bf 81 28 b9 cb c6 ec 00 27 5b a8 02 94 a5 d1 "
- "17 2d 08 24 a7 9e 8f dd 83 01 83 e4 c0 0b 96 78 "
- "28 67 b1 22 7f ea 24 9a ad 32 ff c5 fe 00 7b c5 "
- "1f 21 79 2f 72 8d ed a8 b5 70 8a a9 9c ab ab 20 "
- "a4 aa 78 3e d8 6f 0f 27 b5 d5 63 f4 2e 07 15 8c "
- "ea 72 d0 97 aa 68 87 ec 41 1d d0 12 91 2a 5e 03 "
- "2b bf a6 78 50 71 44 bc c9 5f 39 b5 8b e7 bf d1 "
- "75 9a db 9a 91 fa 1d 6d 82 26 a8 34 3a 8b 84 9d "
- "ae 76 f7 b9 82 24 d5 9e 28 f7 81 f1 3e ce 60 5f "
- "84 f6 c9 0b ae 5f 8c f3 78 81 6f 40 20 a7 dd a1 "
- "be d9 0c 92 a2 36 34 d2 03 fa c3 fc d8 6d 68 d3 "
- "18 2a 7d 9c ca be 7b 07 95 f5 c6 55 e9 ac c4 e3 "
- "ec 18 51 40 d1 0c ef 05 34 64 ab 17 5c 83 bd 83 "
- "93 5e 3d ab af 34 62 ee be 63 d1 5f 57 3d 26 9a ";
-
-char* signature_12 =
- "4e 78 c5 90 2b 80 79 14 d1 2f a5 37 ae 68 71 c8"
- "6d b8 02 1e 55 d1 ad b8 eb 0c cf 1b 8f 36 ab 7d"
- "ad 1f 68 2e 94 7a 62 70 72 f0 3e 62 73 71 78 1d"
- "33 22 1d 17 4a be 46 0d bd 88 56 0c 22 f6 90 11"
- "6e 2f bb e6 e9 64 36 3a 3e 52 83 bb 5d 94 6e f1"
- "c0 04 7e ba 03 8c 75 6c 40 be 79 23 05 58 09 b0"
- "e9 f3 4a 03 a5 88 15 eb dd e7 67 93 1f 01 8f 6f"
- "18 78 f2 ef 4f 47 dd 37 40 51 dd 48 68 5d ed 6e"
- "fb 3e a8 02 1f 44 be 1d 7d 14 93 98 f9 8e a9 c0"
- "8d 62 88 8e bb 56 19 2d 17 74 7b 6b 8e 17 09 54"
- "31 f1 25 a8 a8 e9 96 2a a3 1c 28 52 64 e0 8f b2"
- "1a ac 33 6c e6 c3 8a a3 75 e4 2b c9 2a b0 ab 91"
- "03 84 31 e1 f9 2c 39 d2 af 5d ed 7e 43 bc 15 1e"
- "6e be a4 c3 e2 58 3a f3 43 7e 82 c4 3c 5e 3b 5b"
- "07 cf 03 59 68 3d 22 98 e3 59 48 ed 80 6c 06 3c"
- "60 6e a1 78 15 0b 1e fc 15 85 69 34 c7 25 5c fe";
-
-// PKCS#1 v1.5 Signature Example 15.13
-
-char* message_13 =
- "eb ae f3 f9 f2 3b df e5 fa 6b 8a f4 c2 08 c1 89 "
- "f2 25 1b f3 2f 5f 13 7b 9d e4 40 63 78 68 6b 3f "
- "07 21 f6 2d 24 cb 86 88 d6 fc 41 a2 7c ba e2 1d "
- "30 e4 29 fe ac c7 11 19 41 c2 77 ";
-
-char* signature_13 =
- "c4 8d be f5 07 11 4f 03 c9 5f af be b4 df 1b fa"
- "88 e0 18 4a 33 cc 4f 8a 9a 10 35 ff 7f 82 2a 5e"
- "38 cd a1 87 23 91 5f f0 78 24 44 29 e0 f6 08 1c"
- "14 fd 83 33 1f a6 5c 6b a7 bb 9a 12 db f6 62 23"
- "74 cd 0c a5 7d e3 77 4e 2b d7 ae 82 36 77 d0 61"
- "d5 3a e9 c4 04 0d 2d a7 ef 70 14 f3 bb dc 95 a3"
- "61 a4 38 55 c8 ce 9b 97 ec ab ce 17 4d 92 62 85"
- "14 2b 53 4a 30 87 f9 f4 ef 74 51 1e c7 42 b0 d5"
- "68 56 03 fa f4 03 b5 07 2b 98 5d f4 6a df 2d 25"
- "29 a0 2d 40 71 1e 21 90 91 70 52 37 1b 79 b7 49"
- "b8 3a bf 0a e2 94 86 c3 f2 f6 24 77 b2 bd 36 2b"
- "03 9c 01 3c 0c 50 76 ef 52 0d bb 40 5f 42 ce e9"
- "54 25 c3 73 a9 75 e1 cd d0 32 c4 96 22 c8 50 79"
- "b0 9e 88 da b2 b1 39 69 ef 7a 72 39 73 78 10 40"
- "45 9f 57 d5 01 36 38 48 3d e2 d9 1c b3 c4 90 da"
- "81 c4 6d e6 cd 76 ea 8a 0c 8f 6f e3 31 71 2d 24";
-
-// PKCS#1 v1.5 Signature Example 15.14
-
-char* message_14 =
- "c5 a2 71 12 78 76 1d fc dd 4f 0c 99 e6 f5 61 9d "
- "6c 48 b5 d4 c1 a8 09 82 fa a6 b4 cf 1c f7 a6 0f "
- "f3 27 ab ef 93 c8 01 42 9e fd e0 86 40 85 81 46 "
- "10 56 ac c3 3f 3d 04 f5 ad a2 12 16 ca cd 5f d1 "
- "f9 ed 83 20 3e 0e 2f e6 13 8e 3e ae 84 24 e5 91 "
- "5a 08 3f 3f 7a b7 60 52 c8 be 55 ae 88 2d 6e c1 "
- "48 2b 1e 45 c5 da e9 f4 10 15 40 53 27 02 2e c3 "
- "2f 0e a2 42 97 63 b2 55 04 3b 19 58 ee 3c f6 d6 "
- "39 83 59 6e b3 85 84 4f 85 28 cc 9a 98 65 83 5d "
- "c5 11 3c 02 b8 0d 0f ca 68 aa 25 e7 2b ca ae b3 "
- "cf 9d 79 d8 4f 98 4f d4 17 ";
-
-char* signature_14 =
- "6b d5 25 7a a0 66 11 fb 46 60 08 7c b4 bc 4a 9e"
- "44 91 59 d3 16 52 bd 98 08 44 da f3 b1 c7 b3 53"
- "f8 e5 61 42 f7 ea 98 57 43 3b 18 57 3b 4d ee de"
- "81 8a 93 b0 29 02 97 78 3f 1a 2f 23 cb c7 27 97"
- "a6 72 53 7f 01 f6 24 84 cd 41 62 c3 21 4b 9a c6"
- "28 22 4c 5d e0 1f 32 bb 9b 76 b2 73 54 f2 b1 51"
- "d0 e8 c4 21 3e 46 15 ad 0b c7 1f 51 5e 30 0d 6a"
- "64 c6 74 34 11 ff fd e8 e5 ff 19 0e 54 92 30 43"
- "12 6e cf c4 c4 53 90 22 66 8f b6 75 f2 5c 07 e2"
- "00 99 ee 31 5b 98 d6 af ec 4b 1a 9a 93 dc 33 49"
- "6a 15 bd 6f de 16 63 a7 d4 9b 9f 1e 63 9d 38 66"
- "4b 37 a0 10 b1 f3 5e 65 86 82 d9 cd 63 e5 7d e0"
- "f1 5e 8b dd 09 65 58 f0 7e c0 ca a2 18 a8 c0 6f"
- "47 88 45 39 40 28 7c 9d 34 b6 d4 0a 3f 09 bf 77"
- "99 fe 98 ae 4e b4 9f 3f f4 1c 50 40 a5 0c ef c9"
- "bd f2 39 4b 74 9c f1 64 48 0d f1 ab 68 80 27 3b";
-
-// PKCS#1 v1.5 Signature Example 15.15
-
-char* message_15 =
- "9b f8 aa 25 3b 87 2e a7 7a 7e 23 47 6b e2 6b 23 "
- "29 57 8c f6 ac 9e a2 80 5b 35 7f 6f c3 ad 13 0d "
- "ba eb 3d 86 9a 13 cc e7 a8 08 bb bb c9 69 85 7e "
- "03 94 5c 7b b6 1d f1 b5 c2 58 9b 8e 04 6c 2a 5d "
- "7e 40 57 b1 a7 4f 24 c7 11 21 63 64 28 85 29 ec "
- "95 70 f2 51 97 21 3b e1 f5 c2 e5 96 f8 bf 8b 2c "
- "f3 cb 38 aa 56 ff e5 e3 1d f7 39 58 20 e9 4e cf "
- "3b 11 89 a9 65 dc f9 a9 cb 42 98 d3 c8 8b 29 23 "
- "c1 9f c6 bc 34 aa ce ca d4 e0 93 1a 7c 4e 5d 73 "
- "dc 86 df a7 98 a8 47 6d 82 46 3e ef aa 90 a8 a9 "
- "19 2a b0 8b 23 08 8d d5 8e 12 80 f7 d7 2e 45 48 "
- "39 6b aa c1 12 25 2d d5 c5 34 6a db 20 04 a2 f7 "
- "10 1c cc 89 9c c7 fa fa e8 bb e2 95 73 88 96 a5 "
- "b2 01 22 85 01 4e f6 ";
-
-char* signature_15 =
- "27 f7 f4 da 9b d6 10 10 6e f5 7d 32 38 3a 44 8a"
- "8a 62 45 c8 3d c1 30 9c 6d 77 0d 35 7b a8 9e 73"
- "f2 ad 08 32 06 2e b0 fe 0a c9 15 57 5b cd 6b 8b"
- "ca db 4e 2b a6 fa 9d a7 3a 59 17 51 52 b2 d4 fe"
- "72 b0 70 c9 b7 37 9e 50 00 0e 55 e6 c2 69 f6 65"
- "8c 93 79 72 79 7d 3a dd 69 f1 30 e3 4b 85 bd ec"
- "9f 3a 9b 39 22 02 d6 f3 e4 30 d0 9c ac a8 22 77"
- "59 ab 82 5f 70 12 d2 ff 4b 5b 62 c8 50 4d ba d8"
- "55 c0 5e dd 5c ab 5a 4c cc dc 67 f0 1d d6 51 7c"
- "7d 41 c4 3e 2a 49 57 af f1 9d b6 f1 8b 17 85 9a"
- "f0 bc 84 ab 67 14 6e c1 a4 a6 0a 17 d7 e0 5f 8b"
- "4f 9c ed 6a d1 09 08 d8 d7 8f 7f c8 8b 76 ad c8"
- "29 0f 87 da f2 a7 be 10 ae 40 85 21 39 5d 54 ed"
- "25 56 fb 76 61 85 4a 73 0c e3 d8 2c 71 a8 d4 93"
- "ec 49 a3 78 ac 8a 3c 74 43 9f 7c c5 55 ba 13 f8"
- "59 07 08 90 ee 18 ff 65 8f a4 d7 41 96 9d 70 a5";
-
-// PKCS#1 v1.5 Signature Example 15.16
-
-char* message_16 =
- "32 47 48 30 e2 20 37 54 c8 bf 06 81 dc 4f 84 2a "
- "fe 36 09 30 37 86 16 c1 08 e8 33 65 6e 56 40 c8 "
- "68 56 88 5b b0 5d 1e b9 43 8e fe de 67 92 63 de "
- "07 cb 39 55 3f 6a 25 e0 06 b0 a5 23 11 a0 63 ca "
- "08 82 66 d2 56 4f f6 49 0c 46 b5 60 98 18 54 8f "
- "88 76 4d ad 34 a2 5e 3a 85 d5 75 02 3f 0b 9e 66 "
- "50 48 a0 3c 35 05 79 a9 d3 24 46 c7 bb 96 cc 92 "
- "e0 65 ab 94 d3 c8 95 2e 8d f6 8e f0 d9 fa 45 6b "
- "3a 06 bb 80 e3 bb c4 b2 8e 6a 94 b6 d0 ff 76 96 "
- "a6 4e fe 05 e7 35 fe a0 25 d7 bd bc 41 39 f3 a3 "
- "b5 46 07 5c ba 7e fa 94 73 74 d3 f0 ac 80 a6 8d "
- "76 5f 5d f6 21 0b ca 06 9a 2d 88 64 7a f7 ea 04 "
- "2d ac 69 0c b5 73 78 ec 07 77 61 4f b8 b6 5f f4 "
- "53 ca 6b 7d ce 60 98 45 1a 2f 8c 0d a9 bf ec f1 "
- "fd f3 91 bb aa 4e 2a 91 ca 18 a1 12 1a 75 23 a2 "
- "ab d4 25 14 f4 89 e8 ";
-
-char* signature_16 =
- "69 17 43 72 57 c2 2c cb 54 03 29 0c 3d ee 82 d9"
- "cf 75 50 b3 1b d3 1c 51 bd 57 bf d3 5d 45 2a b4"
- "db 7c 4b e6 b2 e2 5a c9 a5 9a 1d 2a 7f eb 62 7f"
- "0a fd 49 76 b3 00 3c c9 cf fd 88 96 50 5e c3 82"
- "f2 65 10 4d 4c f8 c9 32 fa 9f e8 6e 00 87 07 95"
- "99 12 38 9d a4 b2 d6 b3 69 b3 6a 5e 72 e2 9d 24"
- "c9 a9 8c 9d 31 a3 ab 44 e6 43 e6 94 12 66 a4 7a"
- "45 e3 44 6c e8 77 6a be 24 1a 8f 5f c6 42 3b 24"
- "b1 ff 25 0d c2 c3 a8 17 23 53 56 10 77 e8 50 a7"
- "69 b2 5f 03 25 da c8 89 65 a3 b9 b4 72 c4 94 e9"
- "5f 71 9b 4e ac 33 2c aa 7a 65 c7 df e4 6d 9a a7"
- "e6 e0 0f 52 5f 30 3d d6 3a b7 91 92 18 90 18 68"
- "f9 33 7f 8c d2 6a af e6 f3 3b 7f b2 c9 88 10 af"
- "19 f7 fc b2 82 ba 15 77 91 2c 1d 36 89 75 fd 5d"
- "44 0b 86 e1 0c 19 97 15 fa 0b 6f 42 50 b5 33 73"
- "2d 0b ef e1 54 51 50 fc 47 b8 76 de 09 b0 0a 94";
-
-// PKCS#1 v1.5 Signature Example 15.17
-
-char* message_17 =
- "00 8e 59 50 5e af b5 50 aa e5 e8 45 58 4c eb b0 "
- "0b 6d e1 73 3e 9f 95 d4 2c 88 2a 5b be b5 ce 1c "
- "57 e1 19 e7 c0 d4 da ca 9f 1f f7 87 02 17 f7 cf "
- "d8 a6 b3 73 97 7c ac 9c ab 8e 71 e4 20 ";
-
-char* signature_17 =
- "92 25 03 b6 73 ee 5f 3e 69 1e 1c a8 5e 9f f4 17"
- "3c f7 2b 05 ac 2c 13 1d a5 60 35 93 e3 bc 25 9c"
- "94 c1 f7 d3 a0 6a 5b 98 91 bf 11 3f a3 9e 59 ff"
- "7c 1e d6 46 5e 90 80 49 cb 89 e4 e1 25 cd 37 d2"
- "ff d9 22 7a 41 b4 a0 a1 9c 0a 44 fb bf 3d e5 5b"
- "ab 80 20 87 a3 bb 8d 4f f6 68 ee 6b bb 8a d8 9e"
- "68 57 a7 9a 9c 72 78 19 90 df cf 92 cd 51 94 04"
- "c9 50 f1 3d 11 43 c3 18 4f 1d 25 0c 90 e1 7a c6"
- "ce 36 16 3b 98 95 62 7a d6 ff ec 14 22 44 1f 55"
- "e4 49 9d ba 9b e8 95 46 ae 8b c6 3c ca 01 dd 08"
- "46 3a e7 f1 fc e3 d8 93 99 69 38 77 8c 18 12 e6"
- "74 ad 9c 30 9c 5a cc a3 fd e4 4e 7d d8 69 59 93"
- "e9 c1 fa 87 ac da 99 ec e5 c8 49 9e 46 89 57 ad"
- "66 35 9b f1 2a 51 ad be 78 d3 a2 13 b4 49 bf 0b"
- "5f 8d 4d 49 6a cf 03 d3 03 3b 7c cd 19 6b c2 2f"
- "68 fb 7b ef 4f 69 7c 5e a2 b3 50 62 f4 8a 36 dd";
-
-// PKCS#1 v1.5 Signature Example 15.18
-
-char* message_18 =
- "6a bc 54 cf 8d 1d ff 1f 53 b1 7d 81 60 36 88 78 "
- "a8 78 8c c6 d2 2f a5 c2 25 8c 88 e6 60 b0 9a 89 "
- "33 f9 f2 c0 50 4d da dc 21 f6 e7 5e 0b 83 3b eb "
- "55 52 29 de e6 56 b9 04 7b 92 f6 2e 76 b8 ff cc "
- "60 da b0 6b 80 ";
-
-char* signature_18 =
- "0b 6d af 42 f7 a8 62 14 7e 41 74 93 c2 c4 01 ef"
- "ae 32 63 6a b4 cb d4 41 92 bb f5 f1 95 b5 0a e0"
- "96 a4 75 a1 61 4f 0a 9f a8 f7 a0 26 cb 46 c6 50"
- "6e 51 8e 33 d8 3e 56 47 7a 87 5a ca 8c 7e 71 4c"
- "e1 bd bd 61 ef 5d 53 52 39 b3 3f 2b fd d6 17 71"
- "ba b6 27 76 d7 81 71 a1 42 3c ea 87 31 f8 2e 60"
- "76 6d 64 54 26 56 20 b1 5f 5c 5a 58 4f 55 f9 5b"
- "80 2f e7 8c 57 4e d5 da cf c8 31 f3 cf 2b 05 02"
- "c0 b2 98 f2 5c cf 11 f9 73 b3 1f 85 e4 74 42 19"
- "85 f3 cf f7 02 df 39 46 ef 0a 66 05 68 21 11 b2"
- "f5 5b 1f 8a b0 d2 ea 3a 68 3c 69 98 5e ad 93 ed"
- "44 9e a4 8f 03 58 dd f7 08 02 cb 41 de 2f d8 3f"
- "3c 80 80 82 d8 49 36 94 8e 0c 84 a1 31 b4 92 78"
- "27 46 05 27 bb 5c d2 4b fa b7 b4 8e 07 1b 24 17"
- "19 30 f9 97 63 27 2f 97 97 bc b7 6f 1d 24 81 57"
- "55 58 fc f2 60 b1 f0 e5 54 eb b3 df 3c fc b9 58";
-
-// PKCS#1 v1.5 Signature Example 15.19
-
-char* message_19 =
- "af 2d 78 15 2c f1 0e fe 01 d2 74 f2 17 b1 77 f6 "
- "b0 1b 5e 74 9f 15 67 71 5d a3 24 85 9c d3 dd 88 "
- "db 84 8e c7 9f 48 db ba 7b 6f 1d 33 11 1e f3 1b "
- "64 89 9e 73 91 c2 bf fd 69 f4 90 25 cf 20 1f c5 "
- "85 db d1 54 2c 1c 77 8a 2c e7 a7 ee 10 8a 30 9f "
- "ec a2 6d 13 3a 5f fe dc 4e 86 9d cd 76 56 59 6a "
- "c8 42 7e a3 ef 6e 3f d7 8f e9 9d 8d dc 71 d8 39 "
- "f6 78 6e 0d a6 e7 86 bd 62 b3 a4 f1 9b 89 1a 56 "
- "15 7a 55 4e c2 a2 b3 9e 25 a1 d7 c7 d3 73 21 c7 "
- "a1 d9 46 cf 4f be 75 8d 92 76 f0 85 63 44 9d 67 "
- "41 4a 2c 03 0f 42 51 cf e2 21 3d 04 a5 41 06 37 "
- "87 ";
-
-char* signature_19 =
- "20 9c 61 15 78 57 38 7b 71 e2 4b f3 dd 56 41 45"
- "50 50 3b ec 18 0f f5 3b dd 9b ac 06 2a 2d 49 95"
- "09 bf 99 12 81 b7 95 27 df 91 36 61 5b 7a 6d 9d"
- "b3 a1 03 b5 35 e0 20 2a 2c ac a1 97 a7 b7 4e 53"
- "56 f3 dd 59 5b 49 ac fd 9d 30 04 9a 98 ca 88 f6"
- "25 bc a1 d5 f2 2a 39 2d 8a 74 9e fb 6e ed 9b 78"
- "21 d3 11 0a c0 d2 44 19 9e cb 4a a3 d7 35 a8 3a"
- "2e 88 93 c6 bf 85 81 38 3c ca ee 83 46 35 b7 fa"
- "1f af fa 45 b1 3d 15 c1 da 33 af 71 e8 93 03 d6"
- "80 90 ff 62 ee 61 5f df 5a 84 d1 20 71 1d a5 3c"
- "28 89 19 8a b3 83 17 a9 73 4a b2 7d 67 92 4c ea"
- "74 15 6f f9 9b ef 98 76 bb 5c 33 9e 93 74 52 83"
- "e1 b3 4e 07 22 26 b8 80 45 e0 17 e9 f0 5b 2a 8c"
- "41 67 40 25 8e 22 3b 26 90 02 74 91 73 22 73 f3"
- "22 9d 9e f2 b1 b3 80 7e 32 10 18 92 0a d3 e5 3d"
- "ae 47 e6 d9 39 5c 18 4b 93 a3 74 c6 71 fa a2 ce";
-
-// PKCS#1 v1.5 Signature Example 15.20
-
-char* message_20 =
- "40 ee 99 24 58 d6 f6 14 86 d2 56 76 a9 6d d2 cb "
- "93 a3 7f 04 b1 78 48 2f 2b 18 6c f8 82 15 27 0d "
- "ba 29 d7 86 d7 74 b0 c5 e7 8c 7f 6e 56 a9 56 e7 "
- "f7 39 50 a2 b0 c0 c1 0a 08 db cd 67 e5 b2 10 bb "
- "21 c5 8e 27 67 d4 4f 7d d4 01 4e 39 66 14 3b f7 "
- "e3 d6 6f f0 c0 9b e4 c5 5f 93 b3 99 94 b8 51 8d "
- "9c 1d 76 d5 b4 73 74 de a0 8f 15 7d 57 d7 06 34 "
- "97 8f 38 56 e0 e5 b4 81 af bb db 5a 3a c4 8d 48 "
- "4b e9 2c 93 de 22 91 78 35 4c 2d e5 26 e9 c6 5a "
- "31 ed e1 ef 68 cb 63 98 d7 91 16 84 fe c0 ba bc "
- "3a 78 1a 66 66 07 83 50 69 74 d0 e1 48 25 10 1c "
- "3b fa ea ";
-
-char* signature_20 =
- "92 75 02 b8 24 af c4 25 13 ca 65 70 de 33 8b 8a"
- "64 c3 a8 5e b8 28 d3 19 36 24 f2 7e 8b 10 29 c5"
- "5c 11 9c 97 33 b1 8f 58 49 b3 50 09 18 bc c0 05"
- "51 d9 a8 fd f5 3a 97 74 9f a8 dc 48 0d 6f e9 74"
- "2a 58 71 f9 73 92 65 28 97 2a 1a f4 9e 39 25 b0"
- "ad f1 4a 84 27 19 b4 a5 a2 d8 9f a9 c0 b6 60 5d"
- "21 2b ed 1e 67 23 b9 34 06 ad 30 e8 68 29 a5 c7"
- "19 b8 90 b3 89 30 6d c5 50 64 86 ee 2f 36 a8 df"
- "e0 a9 6a f6 78 c9 cb d6 af f3 97 ca 20 0e 3e dc"
- "1e 36 bd 2f 08 b3 1d 54 0c 0c b2 82 a9 55 9e 4a"
- "dd 4f c9 e6 49 2e ed 0c cb d3 a6 98 2e 5f aa 2d"
- "dd 17 be 47 41 7c 80 b4 e5 45 2d 31 f7 24 01 a0"
- "42 32 51 09 54 4d 95 4c 01 93 90 79 d4 09 a5 c3"
- "78 d7 51 2d fc 2d 2a 71 ef cc 34 32 a7 65 d1 c6"
- "a5 2c fc e8 99 cd 79 b1 5b 4f c3 72 36 41 ef 6b"
- "d0 0a cc 10 40 7e 5d f5 8d d1 c3 c5 c5 59 a5 06";
-
-
-unsigned char* parsehex(char* str, int* len) {
- // result can't be longer than input
- unsigned char* result = malloc(strlen(str));
-
- unsigned char* p = result;
- *len = 0;
-
- while (*str) {
- int b;
-
- while (isspace(*str)) str++;
-
- switch (*str) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- b = (*str - '0') << 4; break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- b = (*str - 'a' + 10) << 4; break;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- b = (*str - 'A' + 10) << 4; break;
- case '\0':
- return result;
- default:
- return NULL;
- }
- str++;
-
- while (isspace(*str)) str++;
-
- switch (*str) {
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- b |= *str - '0'; break;
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- b |= *str - 'a' + 10; break;
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- b |= *str - 'A' + 10; break;
- default:
- return NULL;
- }
- str++;
-
- *p++ = b;
- ++*len;
- }
-
- return result;
-}
-
-
-int main(int arg __unused, char** argv __unused) {
-
- unsigned char hash[SHA_DIGEST_SIZE];
-
- unsigned char* message;
- int mlen;
- unsigned char* signature;
- int slen;
-
-#define TEST_MESSAGE(n) do {\
- message = parsehex(message_##n, &mlen); \
- SHA_hash(message, mlen, hash); \
- signature = parsehex(signature_##n, &slen); \
- int result = RSA_verify(&key_15, signature, slen, hash, sizeof(hash)); \
- printf("message %d: %s\n", n, result ? "verified" : "not verified"); \
- success = success && result; \
- } while(0)
-
- int success = 1;
-
- TEST_MESSAGE(1);
- TEST_MESSAGE(2);
- TEST_MESSAGE(3);
- TEST_MESSAGE(4);
- TEST_MESSAGE(5);
- TEST_MESSAGE(6);
- TEST_MESSAGE(7);
- TEST_MESSAGE(8);
- TEST_MESSAGE(9);
- TEST_MESSAGE(10);
- TEST_MESSAGE(11);
- TEST_MESSAGE(12);
- TEST_MESSAGE(13);
- TEST_MESSAGE(14);
- TEST_MESSAGE(15);
- TEST_MESSAGE(16);
- TEST_MESSAGE(17);
- TEST_MESSAGE(18);
- TEST_MESSAGE(19);
- TEST_MESSAGE(20);
-
- printf("\n%s\n\n", success ? "PASS" : "FAIL");
-
- return !success;
-}
diff --git a/libmincrypt/tools/DumpPublicKey.java b/libmincrypt/tools/DumpPublicKey.java
deleted file mode 100644
index 3eb1398..0000000
--- a/libmincrypt/tools/DumpPublicKey.java
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.dumpkey;
-
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-
-import java.io.FileInputStream;
-import java.math.BigInteger;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.KeyStore;
-import java.security.Key;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.ECPoint;
-
-/**
- * Command line tool to extract RSA public keys from X.509 certificates
- * and output source code with data initializers for the keys.
- * @hide
- */
-class DumpPublicKey {
- /**
- * @param key to perform sanity checks on
- * @return version number of key. Supported versions are:
- * 1: 2048-bit RSA key with e=3 and SHA-1 hash
- * 2: 2048-bit RSA key with e=65537 and SHA-1 hash
- * 3: 2048-bit RSA key with e=3 and SHA-256 hash
- * 4: 2048-bit RSA key with e=65537 and SHA-256 hash
- * @throws Exception if the key has the wrong size or public exponent
- */
- static int checkRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
- BigInteger pubexp = key.getPublicExponent();
- BigInteger modulus = key.getModulus();
- int version;
-
- if (pubexp.equals(BigInteger.valueOf(3))) {
- version = useSHA256 ? 3 : 1;
- } else if (pubexp.equals(BigInteger.valueOf(65537))) {
- version = useSHA256 ? 4 : 2;
- } else {
- throw new Exception("Public exponent should be 3 or 65537 but is " +
- pubexp.toString(10) + ".");
- }
-
- if (modulus.bitLength() != 2048) {
- throw new Exception("Modulus should be 2048 bits long but is " +
- modulus.bitLength() + " bits.");
- }
-
- return version;
- }
-
- /**
- * @param key to perform sanity checks on
- * @return version number of key. Supported versions are:
- * 5: 256-bit EC key with curve NIST P-256
- * @throws Exception if the key has the wrong size or public exponent
- */
- static int checkEC(ECPublicKey key) throws Exception {
- if (key.getParams().getCurve().getField().getFieldSize() != 256) {
- throw new Exception("Curve must be NIST P-256");
- }
-
- return 5;
- }
-
- /**
- * Perform sanity check on public key.
- */
- static int check(PublicKey key, boolean useSHA256) throws Exception {
- if (key instanceof RSAPublicKey) {
- return checkRSA((RSAPublicKey) key, useSHA256);
- } else if (key instanceof ECPublicKey) {
- if (!useSHA256) {
- throw new Exception("Must use SHA-256 with EC keys!");
- }
- return checkEC((ECPublicKey) key);
- } else {
- throw new Exception("Unsupported key class: " + key.getClass().getName());
- }
- }
-
- /**
- * @param key to output
- * @return a String representing this public key. If the key is a
- * version 1 key, the string will be a C initializer; this is
- * not true for newer key versions.
- */
- static String printRSA(RSAPublicKey key, boolean useSHA256) throws Exception {
- int version = check(key, useSHA256);
-
- BigInteger N = key.getModulus();
-
- StringBuilder result = new StringBuilder();
-
- int nwords = N.bitLength() / 32; // # of 32 bit integers in modulus
-
- if (version > 1) {
- result.append("v");
- result.append(Integer.toString(version));
- result.append(" ");
- }
-
- result.append("{");
- result.append(nwords);
-
- BigInteger B = BigInteger.valueOf(0x100000000L); // 2^32
- BigInteger N0inv = B.subtract(N.modInverse(B)); // -1 / N[0] mod 2^32
-
- result.append(",0x");
- result.append(N0inv.toString(16));
-
- BigInteger R = BigInteger.valueOf(2).pow(N.bitLength());
- BigInteger RR = R.multiply(R).mod(N); // 2^4096 mod N
-
- // Write out modulus as little endian array of integers.
- result.append(",{");
- for (int i = 0; i < nwords; ++i) {
- long n = N.mod(B).longValue();
- result.append(n);
-
- if (i != nwords - 1) {
- result.append(",");
- }
-
- N = N.divide(B);
- }
- result.append("}");
-
- // Write R^2 as little endian array of integers.
- result.append(",{");
- for (int i = 0; i < nwords; ++i) {
- long rr = RR.mod(B).longValue();
- result.append(rr);
-
- if (i != nwords - 1) {
- result.append(",");
- }
-
- RR = RR.divide(B);
- }
- result.append("}");
-
- result.append("}");
- return result.toString();
- }
-
- /**
- * @param key to output
- * @return a String representing this public key. If the key is a
- * version 1 key, the string will be a C initializer; this is
- * not true for newer key versions.
- */
- static String printEC(ECPublicKey key) throws Exception {
- int version = checkEC(key);
-
- StringBuilder result = new StringBuilder();
-
- result.append("v");
- result.append(Integer.toString(version));
- result.append(" ");
-
- BigInteger X = key.getW().getAffineX();
- BigInteger Y = key.getW().getAffineY();
- int nbytes = key.getParams().getCurve().getField().getFieldSize() / 8; // # of 32 bit integers in X coordinate
-
- result.append("{");
- result.append(nbytes);
-
- BigInteger B = BigInteger.valueOf(0x100L); // 2^8
-
- // Write out Y coordinate as array of characters.
- result.append(",{");
- for (int i = 0; i < nbytes; ++i) {
- long n = X.mod(B).longValue();
- result.append(n);
-
- if (i != nbytes - 1) {
- result.append(",");
- }
-
- X = X.divide(B);
- }
- result.append("}");
-
- // Write out Y coordinate as array of characters.
- result.append(",{");
- for (int i = 0; i < nbytes; ++i) {
- long n = Y.mod(B).longValue();
- result.append(n);
-
- if (i != nbytes - 1) {
- result.append(",");
- }
-
- Y = Y.divide(B);
- }
- result.append("}");
-
- result.append("}");
- return result.toString();
- }
-
- static String print(PublicKey key, boolean useSHA256) throws Exception {
- if (key instanceof RSAPublicKey) {
- return printRSA((RSAPublicKey) key, useSHA256);
- } else if (key instanceof ECPublicKey) {
- return printEC((ECPublicKey) key);
- } else {
- throw new Exception("Unsupported key class: " + key.getClass().getName());
- }
- }
-
- public static void main(String[] args) {
- if (args.length < 1) {
- System.err.println("Usage: DumpPublicKey certfile ... > source.c");
- System.exit(1);
- }
- Security.addProvider(new BouncyCastleProvider());
- try {
- for (int i = 0; i < args.length; i++) {
- FileInputStream input = new FileInputStream(args[i]);
- CertificateFactory cf = CertificateFactory.getInstance("X.509");
- X509Certificate cert = (X509Certificate) cf.generateCertificate(input);
-
- boolean useSHA256 = false;
- String sigAlg = cert.getSigAlgName();
- if ("SHA1withRSA".equals(sigAlg) || "MD5withRSA".equals(sigAlg)) {
- // SignApk has historically accepted "MD5withRSA"
- // certificates, but treated them as "SHA1withRSA"
- // anyway. Continue to do so for backwards
- // compatibility.
- useSHA256 = false;
- } else if ("SHA256withRSA".equals(sigAlg) || "SHA256withECDSA".equals(sigAlg)) {
- useSHA256 = true;
- } else {
- System.err.println(args[i] + ": unsupported signature algorithm \"" +
- sigAlg + "\"");
- System.exit(1);
- }
-
- PublicKey key = cert.getPublicKey();
- check(key, useSHA256);
- System.out.print(print(key, useSHA256));
- System.out.println(i < args.length - 1 ? "," : "");
- }
- } catch (Exception e) {
- e.printStackTrace();
- System.exit(1);
- }
- System.exit(0);
- }
-}
diff --git a/libmincrypt/tools/DumpPublicKey.mf b/libmincrypt/tools/DumpPublicKey.mf
deleted file mode 100644
index 7bb3bc8..0000000
--- a/libmincrypt/tools/DumpPublicKey.mf
+++ /dev/null
@@ -1 +0,0 @@
-Main-Class: com.android.dumpkey.DumpPublicKey
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
new file mode 100644
index 0000000..598dfcd
--- /dev/null
+++ b/libnativebridge/Android.bp
@@ -0,0 +1,25 @@
+
+cc_library {
+ name: "libnativebridge",
+
+ host_supported: true,
+ srcs: ["native_bridge.cc"],
+ shared_libs: ["liblog"],
+ clang: true,
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ cppflags: [
+ "-std=gnu++11",
+ "-fvisibility=protected",
+ ],
+
+ host_ldlibs: ["-ldl"],
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ },
+}
diff --git a/libnativebridge/Android.mk b/libnativebridge/Android.mk
index d20d44c..3887b1b 100644
--- a/libnativebridge/Android.mk
+++ b/libnativebridge/Android.mk
@@ -1,58 +1,3 @@
LOCAL_PATH:= $(call my-dir)
-NATIVE_BRIDGE_COMMON_SRC_FILES := \
- native_bridge.cc
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Static library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativebridge
-
-LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS += -Werror -Wall
-LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
include $(LOCAL_PATH)/tests/Android.mk
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 32a65ea..ecfd719 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -231,8 +231,10 @@
static const char* kRuntimeISA = "arm";
#elif defined(__aarch64__)
static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
static const char* kRuntimeISA = "mips";
+#elif defined(__mips__) && defined(__LP64__)
+static const char* kRuntimeISA = "mips64";
#elif defined(__i386__)
static const char* kRuntimeISA = "x86";
#elif defined(__x86_64__)
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
index 2efc176..551765a 100644
--- a/libnativebridge/tests/Android.nativebridge-dummy.mk
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -13,7 +13,7 @@
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
+LOCAL_SHARED_LIBRARIES := libdl
LOCAL_MULTILIB := both
include $(BUILD_SHARED_LIBRARY)
@@ -49,7 +49,7 @@
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
-LOCAL_LDFLAGS := -ldl
+LOCAL_SHARED_LIBRARIES := libdl
LOCAL_MULTILIB := both
include $(BUILD_SHARED_LIBRARY)
diff --git a/libnativebridge/tests/NeedsNativeBridge_test.cpp b/libnativebridge/tests/NeedsNativeBridge_test.cpp
index e1c0876..2067ed2 100644
--- a/libnativebridge/tests/NeedsNativeBridge_test.cpp
+++ b/libnativebridge/tests/NeedsNativeBridge_test.cpp
@@ -18,15 +18,17 @@
namespace android {
-static const char* kISAs[] = { "arm", "arm64", "mips", "x86", "x86_64", "random", "64arm", "64_x86",
- "64_x86_64", "", "reallylongstringabcd", nullptr };
+static const char* kISAs[] = { "arm", "arm64", "mips", "mips64", "x86", "x86_64", "random", "64arm",
+ "64_x86", "64_x86_64", "", "reallylongstringabcd", nullptr };
#if defined(__arm__)
static const char* kRuntimeISA = "arm";
#elif defined(__aarch64__)
static const char* kRuntimeISA = "arm64";
-#elif defined(__mips__)
+#elif defined(__mips__) && !defined(__LP64__)
static const char* kRuntimeISA = "mips";
+#elif defined(__mips__) && defined(__LP64__)
+static const char* kRuntimeISA = "mips64";
#elif defined(__i386__)
static const char* kRuntimeISA = "x86";
#elif defined(__x86_64__)
diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp
new file mode 100644
index 0000000..b4a69bc
--- /dev/null
+++ b/libnativeloader/Android.bp
@@ -0,0 +1,32 @@
+// Shared library for target
+// ========================================================
+cc_library {
+ name: "libnativeloader",
+ host_supported: true,
+ srcs: ["native_loader.cpp"],
+ shared_libs: [
+ "libnativehelper",
+ "liblog",
+ "libcutils",
+ ],
+ static_libs: ["libbase"],
+ target: {
+ android: {
+ shared_libs: ["libdl"],
+ },
+ host: {
+ host_ldlibs: ["-ldl"],
+ },
+ },
+ clang: true,
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ cppflags: [
+ "-std=gnu++14",
+ "-fvisibility=hidden",
+ ],
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+}
diff --git a/libnativeloader/Android.mk b/libnativeloader/Android.mk
deleted file mode 100644
index 632c6c8..0000000
--- a/libnativeloader/Android.mk
+++ /dev/null
@@ -1,59 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-native_loader_common_src_files := \
- native_loader.cpp
-
-native_loader_common_cflags := -Werror -Wall
-
-# Shared library for target
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativeloader
-
-LOCAL_SRC_FILES:= $(native_loader_common_src_files)
-LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
-LOCAL_STATIC_LIBRARIES := libbase
-LOCAL_CLANG := true
-LOCAL_CFLAGS := $(native_loader_common_cflags)
-LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-include $(BUILD_SHARED_LIBRARY)
-
-# Shared library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativeloader
-
-LOCAL_SRC_FILES:= $(native_loader_common_src_files)
-LOCAL_SHARED_LIBRARIES := libnativehelper liblog libcutils
-LOCAL_STATIC_LIBRARIES := libbase
-LOCAL_CLANG := true
-LOCAL_CFLAGS := $(native_loader_common_cflags)
-LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Static library for host
-# ========================================================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= libnativeloader
-
-LOCAL_SRC_FILES:= $(native_loader_common_src_files)
-LOCAL_STATIC_LIBRARIES := libnativehelper libcutils liblog libbase
-LOCAL_CLANG := true
-LOCAL_CFLAGS := $(native_loader_common_cflags)
-LOCAL_CPPFLAGS := -std=gnu++14 -fvisibility=hidden
-LOCAL_LDFLAGS := -ldl
-LOCAL_MULTILIB := both
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-include $(BUILD_HOST_STATIC_LIBRARY)
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index e35ed60..e89c50f 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -121,6 +121,13 @@
}
void Initialize() {
+ // Once public namespace is initialized there is no
+ // point in running this code - it will have no effect
+ // on the current list of public libraries.
+ if (initialized_) {
+ return;
+ }
+
std::vector<std::string> sonames;
const char* android_root_env = getenv("ANDROID_ROOT");
std::string root_dir = android_root_env != nullptr ? android_root_env : "/system";
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index ff899c0..ce7c3ba 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -15,6 +15,9 @@
LOCAL_CFLAGS := -Werror
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
diff --git a/include/netutils/ifc.h b/libnetutils/include/netutils/ifc.h
similarity index 100%
rename from include/netutils/ifc.h
rename to libnetutils/include/netutils/ifc.h
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
new file mode 100644
index 0000000..70ff528
--- /dev/null
+++ b/libpackagelistparser/Android.bp
@@ -0,0 +1,13 @@
+cc_library {
+
+ name: "libpackagelistparser",
+ srcs: ["packagelistparser.c"],
+ shared_libs: ["liblog"],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+
+ clang: true,
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+}
diff --git a/libpackagelistparser/Android.mk b/libpackagelistparser/Android.mk
deleted file mode 100644
index c8be050..0000000
--- a/libpackagelistparser/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#########################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libpackagelistparser
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-include $(BUILD_SHARED_LIBRARY)
-
-#########################
-include $(CLEAR_VARS)
-
-
-LOCAL_MODULE := libpackagelistparser
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c
index 16052e2..e309027 100644
--- a/libpackagelistparser/packagelistparser.c
+++ b/libpackagelistparser/packagelistparser.c
@@ -27,7 +27,7 @@
#include <sys/limits.h>
#define LOG_TAG "packagelistparser"
-#include <utils/Log.h>
+#include <cutils/log.h>
#include <packagelistparser/packagelistparser.h>
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 9a937f8..55891db 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -74,10 +74,6 @@
external/safe-iop/include
LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
-# Really this should go away entirely or at least not depend on
-# libhardware, but this at least gets us built.
-LOCAL_SHARED_LIBRARIES += libhardware_legacy
-LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/arch-arm64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
index 8d9c7c4..84596f9 100644
--- a/libpixelflinger/arch-arm64/col32cb16blend.S
+++ b/libpixelflinger/arch-arm64/col32cb16blend.S
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
.text
- .align 0
+ .balign 0
.global scanline_col32cb16blend_arm64
diff --git a/libpixelflinger/arch-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
index 230f47b..b1a950d 100644
--- a/libpixelflinger/arch-arm64/t32cb16blend.S
+++ b/libpixelflinger/arch-arm64/t32cb16blend.S
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
.text
- .align 0
+ .balign 0
.global scanline_t32cb16blend_arm64
diff --git a/libpixelflinger/arch-mips/col32cb16blend.S b/libpixelflinger/arch-mips/col32cb16blend.S
index 5d18e55..810294c 100644
--- a/libpixelflinger/arch-mips/col32cb16blend.S
+++ b/libpixelflinger/arch-mips/col32cb16blend.S
@@ -59,7 +59,7 @@
.endm
.text
- .align
+ .balign 4
.global scanline_col32cb16blend_mips
.ent scanline_col32cb16blend_mips
diff --git a/libpixelflinger/arch-mips/t32cb16blend.S b/libpixelflinger/arch-mips/t32cb16blend.S
index 236a2c9..1d2fb8f 100644
--- a/libpixelflinger/arch-mips/t32cb16blend.S
+++ b/libpixelflinger/arch-mips/t32cb16blend.S
@@ -178,7 +178,7 @@
#endif
.text
- .align
+ .balign 4
.global scanline_t32cb16blend_mips
.ent scanline_t32cb16blend_mips
diff --git a/libpixelflinger/arch-mips64/col32cb16blend.S b/libpixelflinger/arch-mips64/col32cb16blend.S
index fea4491..5baffb1 100644
--- a/libpixelflinger/arch-mips64/col32cb16blend.S
+++ b/libpixelflinger/arch-mips64/col32cb16blend.S
@@ -53,7 +53,7 @@
.endm
.text
- .align
+ .balign 4
.global scanline_col32cb16blend_mips64
.ent scanline_col32cb16blend_mips64
diff --git a/libpixelflinger/arch-mips64/t32cb16blend.S b/libpixelflinger/arch-mips64/t32cb16blend.S
index d2f4d49..3cb5f93 100644
--- a/libpixelflinger/arch-mips64/t32cb16blend.S
+++ b/libpixelflinger/arch-mips64/t32cb16blend.S
@@ -75,7 +75,7 @@
.endm
.text
- .align
+ .balign 4
.global scanline_t32cb16blend_mips64
.ent scanline_t32cb16blend_mips64
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index 92243da..849512a 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -22,10 +22,6 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
#include <private/pixelflinger/ggl_context.h>
#include "ARMAssembler.h"
@@ -48,9 +44,6 @@
{
mBase = mPC = (uint32_t *)assembly->base();
mDuration = ggl_system_time();
-#if defined(WITH_LIB_HARDWARE)
- mQemuTracing = true;
-#endif
}
ARMAssembler::~ARMAssembler()
@@ -184,13 +177,6 @@
const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-#if defined(WITH_LIB_HARDWARE)
- if (__builtin_expect(mQemuTracing, 0)) {
- int err = qemu_add_mapping(uintptr_t(base()), name);
- mQemuTracing = (err >= 0);
- }
-#endif
-
char value[PROPERTY_VALUE_MAX];
property_get("debug.pf.disasm", value, "0");
if (atoi(value) != 0) {
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
index e0c7646..76acf7e 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -35,7 +35,7 @@
class ARMAssembler : public ARMAssemblerInterface
{
public:
- ARMAssembler(const sp<Assembly>& assembly);
+ explicit ARMAssembler(const sp<Assembly>& assembly);
virtual ~ARMAssembler();
uint32_t* base() const;
@@ -167,9 +167,6 @@
uint32_t* mPC;
uint32_t* mPrologPC;
int64_t mDuration;
-#if defined(WITH_LIB_HARDWARE)
- bool mQemuTracing;
-#endif
struct branch_target_t {
inline branch_target_t() : label(0), pc(0) { }
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.h b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
index b852794..10d0390 100644
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.h
+++ b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
@@ -34,7 +34,7 @@
// ARMAssemblerProxy take ownership of the target
ARMAssemblerProxy();
- ARMAssemblerProxy(ARMAssemblerInterface* target);
+ explicit ARMAssemblerProxy(ARMAssemblerInterface* target);
virtual ~ARMAssemblerProxy();
void setTarget(ARMAssemblerInterface* target);
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.h b/libpixelflinger/codeflinger/Arm64Assembler.h
index c9be116..527c757 100644
--- a/libpixelflinger/codeflinger/Arm64Assembler.h
+++ b/libpixelflinger/codeflinger/Arm64Assembler.h
@@ -47,8 +47,8 @@
class ArmToArm64Assembler : public ARMAssemblerInterface
{
public:
- ArmToArm64Assembler(const sp<Assembly>& assembly);
- ArmToArm64Assembler(void *base);
+ explicit ArmToArm64Assembler(const sp<Assembly>& assembly);
+ explicit ArmToArm64Assembler(void *base);
virtual ~ArmToArm64Assembler();
uint32_t* base() const;
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
index 0fb6fd5..c0e0684 100644
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ b/libpixelflinger/codeflinger/CodeCache.h
@@ -42,7 +42,7 @@
class AssemblyKey : public AssemblyKeyBase
{
public:
- AssemblyKey(const T& rhs) : mKey(rhs) { }
+ explicit AssemblyKey(const T& rhs) : mKey(rhs) { }
virtual int compare_type(const AssemblyKeyBase& key) const {
const T& rhs = static_cast<const AssemblyKey&>(key).mKey;
return android::compare_type(mKey, rhs);
@@ -56,7 +56,7 @@
class Assembly
{
public:
- Assembly(size_t size);
+ explicit Assembly(size_t size);
virtual ~Assembly();
ssize_t size() const;
@@ -80,13 +80,13 @@
{
public:
// pretty simple cache API...
- CodeCache(size_t size);
- ~CodeCache();
-
- sp<Assembly> lookup(const AssemblyKeyBase& key) const;
+ explicit CodeCache(size_t size);
+ ~CodeCache();
- int cache( const AssemblyKeyBase& key,
- const sp<Assembly>& assembly);
+ sp<Assembly> lookup(const AssemblyKeyBase& key) const;
+
+ int cache(const AssemblyKeyBase& key,
+ const sp<Assembly>& assembly);
private:
// nothing to see here...
@@ -105,7 +105,7 @@
const AssemblyKeyBase* mKey;
public:
key_t() { };
- key_t(const AssemblyKeyBase& k) : mKey(&k) { }
+ explicit key_t(const AssemblyKeyBase& k) : mKey(&k) { }
};
mutable pthread_mutex_t mLock;
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
index 9db20df..47dbf3a 100644
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ b/libpixelflinger/codeflinger/GGLAssembler.h
@@ -49,7 +49,7 @@
public:
class RegisterFile;
- RegisterAllocator(int arch);
+ RegisterAllocator(int arch); // NOLINT, implicit
RegisterFile& registerFile();
int reserveReg(int reg);
int obtainReg();
@@ -59,7 +59,7 @@
class RegisterFile
{
public:
- RegisterFile(int arch);
+ RegisterFile(int arch); // NOLINT, implicit
RegisterFile(const RegisterFile& rhs, int arch);
~RegisterFile();
@@ -101,7 +101,7 @@
class Scratch
{
public:
- Scratch(RegisterFile& regFile)
+ explicit Scratch(RegisterFile& regFile)
: mRegFile(regFile), mScratch(0) {
}
~Scratch() {
@@ -177,8 +177,8 @@
{
public:
- GGLAssembler(ARMAssemblerInterface* target);
- virtual ~GGLAssembler();
+ explicit GGLAssembler(ARMAssemblerInterface* target);
+ virtual ~GGLAssembler();
uint32_t* base() const { return 0; } // XXX
uint32_t* pc() const { return 0; } // XXX
@@ -206,7 +206,7 @@
struct reg_t {
reg_t() : reg(-1), flags(0) {
}
- reg_t(int r, int f=0)
+ reg_t(int r, int f=0) // NOLINT, implicit
: reg(r), flags(f) {
}
void setTo(int r, int f=0) {
@@ -219,7 +219,7 @@
struct integer_t : public reg_t {
integer_t() : reg_t(), s(0) {
}
- integer_t(int r, int sz=32, int f=0)
+ integer_t(int r, int sz=32, int f=0) // NOLINT, implicit
: reg_t(r, f), s(sz) {
}
void setTo(int r, int sz=32, int f=0) {
@@ -251,7 +251,7 @@
struct component_t : public reg_t {
component_t() : reg_t(), h(0), l(0) {
}
- component_t(int r, int f=0)
+ component_t(int r, int f=0) // NOLINT, implicit
: reg_t(r, f), h(0), l(0) {
}
component_t(int r, int lo, int hi, int f=0)
@@ -288,6 +288,14 @@
private:
+ // GGLAssembler hides RegisterAllocator's and ARMAssemblerProxy's reset
+ // methods by providing a reset method with a different parameter set. The
+ // intent of GGLAssembler's reset method is to wrap the inherited reset
+ // methods, so make these methods private in order to prevent direct calls
+ // to these methods from clients.
+ using RegisterAllocator::reset;
+ using ARMAssemblerProxy::reset;
+
struct tex_coord_t {
reg_t s;
reg_t t;
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
index 672040b..b9f31ff 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
@@ -33,10 +33,6 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
#include <private/pixelflinger/ggl_context.h>
#include "MIPS64Assembler.h"
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index 5497fae..ae06a13 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -55,10 +55,6 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
#include <private/pixelflinger/ggl_context.h>
#include "MIPSAssembler.h"
@@ -1411,13 +1407,6 @@
const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-#if defined(WITH_LIB_HARDWARE)
- if (__builtin_expect(mQemuTracing, 0)) {
- int err = qemu_add_mapping(uintptr_t(base()), name);
- mQemuTracing = (err >= 0);
- }
-#endif
-
char value[PROPERTY_VALUE_MAX];
value[0] = '\0';
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
index b53fefb..c1178b6 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ b/libpixelflinger/codeflinger/MIPSAssembler.h
@@ -410,9 +410,6 @@
uint32_t* mPC;
uint32_t* mPrologPC;
int64_t mDuration;
-#if defined(WITH_LIB_HARDWARE)
- bool mQemuTracing;
-#endif
struct branch_target_t {
inline branch_target_t() : label(0), pc(0) { }
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
index 39dd614..5cbd63d 100644
--- a/libpixelflinger/codeflinger/disassem.c
+++ b/libpixelflinger/codeflinger/disassem.c
@@ -279,14 +279,14 @@
"4.0", "5.0", "0.5", "10.0"
};
-#define insn_condition(x) arm32_insn_conditions[(x >> 28) & 0x0f]
-#define insn_blktrans(x) insn_block_transfers[(x >> 23) & 3]
-#define insn_stkblktrans(x) insn_stack_block_transfers[(3*((x >> 20)&1))^((x >> 23)&3)]
-#define op2_shift(x) op_shifts[(x >> 5) & 3]
-#define insn_fparnd(x) insn_fpa_rounding[(x >> 5) & 0x03]
-#define insn_fpaprec(x) insn_fpa_precision[(((x >> 18) & 2)|(x >> 7)) & 1]
-#define insn_fpaprect(x) insn_fpa_precision[(((x >> 21) & 2)|(x >> 15)) & 1]
-#define insn_fpaimm(x) insn_fpaconstants[x & 0x07]
+#define insn_condition(x) arm32_insn_conditions[((x) >> 28) & 0x0f]
+#define insn_blktrans(x) insn_block_transfers[((x) >> 23) & 3]
+#define insn_stkblktrans(x) insn_stack_block_transfers[(3*(((x) >> 20)&1))^(((x) >> 23)&3)]
+#define op2_shift(x) op_shifts[((x) >> 5) & 3]
+#define insn_fparnd(x) insn_fpa_rounding[((x) >> 5) & 0x03]
+#define insn_fpaprec(x) insn_fpa_precision[((((x) >> 18) & 2)|((x) >> 7)) & 1]
+#define insn_fpaprect(x) insn_fpa_precision[((((x) >> 21) & 2)|((x) >> 15)) & 1]
+#define insn_fpaimm(x) insn_fpaconstants[(x) & 0x07]
/* Local prototypes */
static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
diff --git a/libpixelflinger/codeflinger/tinyutils/smartpointer.h b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
index 9d0a16e..23a5f7e 100644
--- a/libpixelflinger/codeflinger/tinyutils/smartpointer.h
+++ b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
@@ -51,10 +51,10 @@
public:
inline sp() : m_ptr(0) { }
- sp(T* other);
+ sp(T* other); // NOLINT, implicit
sp(const sp<T>& other);
- template<typename U> sp(U* other);
- template<typename U> sp(const sp<U>& other);
+ template<typename U> sp(U* other); // NOLINT, implicit
+ template<typename U> sp(const sp<U>& other); // NOLINT, implicit
~sp();
diff --git a/libpixelflinger/col32cb16blend.S b/libpixelflinger/col32cb16blend.S
index 1831255..39f94e1 100644
--- a/libpixelflinger/col32cb16blend.S
+++ b/libpixelflinger/col32cb16blend.S
@@ -16,7 +16,7 @@
*/
.text
- .align
+ .balign 4
.global scanline_col32cb16blend_arm
diff --git a/libpixelflinger/col32cb16blend_neon.S b/libpixelflinger/col32cb16blend_neon.S
index cbd54d1..7ad34b0 100644
--- a/libpixelflinger/col32cb16blend_neon.S
+++ b/libpixelflinger/col32cb16blend_neon.S
@@ -17,7 +17,7 @@
.text
- .align
+ .balign 4
.global scanline_col32cb16blend_neon
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
index d45dabc..563b0f1 100644
--- a/libpixelflinger/include/private/pixelflinger/ggl_context.h
+++ b/libpixelflinger/include/private/pixelflinger/ggl_context.h
@@ -120,7 +120,7 @@
template<bool> struct CTA;
template<> struct CTA<true> { };
-#define GGL_CONTEXT(con, c) context_t *con = static_cast<context_t *>(c)
+#define GGL_CONTEXT(con, c) context_t *(con) = static_cast<context_t *>(c) /* NOLINT */
#define GGL_OFFSETOF(field) uintptr_t(&(((context_t*)0)->field))
#define GGL_INIT_PROC(p, f) p.f = ggl_ ## f;
#define GGL_BETWEEN(x, L, H) (uint32_t((x)-(L)) <= ((H)-(L)))
@@ -136,14 +136,14 @@
// ----------------------------------------------------------------------------
#define GGL_RESERVE_NEEDS(name, l, s) \
- const uint32_t GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<l); \
+ const uint32_t GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<(l)); \
const uint32_t GGL_NEEDS_##name##_SHIFT = (l);
#define GGL_BUILD_NEEDS(val, name) \
(((val)<<(GGL_NEEDS_##name##_SHIFT)) & GGL_NEEDS_##name##_MASK)
#define GGL_READ_NEEDS(name, n) \
- (uint32_t(n & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
+ (uint32_t((n) & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
#define GGL_NEED_MASK(name) (uint32_t(GGL_NEEDS_##name##_MASK))
#define GGL_NEED(name, val) GGL_BUILD_NEEDS(val, name)
diff --git a/libpixelflinger/rotate90CW_4x4_16v6.S b/libpixelflinger/rotate90CW_4x4_16v6.S
deleted file mode 100644
index 8e3e142..0000000
--- a/libpixelflinger/rotate90CW_4x4_16v6.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-**
-** 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.
-*/
-
-
- .text
- .align
-
- .global rotate90CW_4x4_16v6
-
-// Rotates 90deg CW a 4x4 block of 16bpp pixels using ARMv6
-// src and dst must be 4 pixels-aligned (2-pixels aligned might
-// actually work)
-//
-// The code below is complicated by ARM's little endianness.
-
-rotate90CW_4x4_16v6:
- // r0 = dst
- // r1 = src
- // r2 = dst stride in pixels
- // r3 = src stride in pixels
-
- stmfd sp!, {r4,r5, r6,r7, r8,r9, r10,r11, lr}
- add r14, r3, r3
- add r12, r2, r2
-
- ldrd r2, r3, [r1], r14
- ldrd r4, r5, [r1], r14
- ldrd r6, r7, [r1], r14
- ldrd r8, r9, [r1]
-
- pkhbt r10, r8, r6, lsl #16
- pkhbt r11, r4, r2, lsl #16
- strd r10, r11, [r0], r12
-
- pkhtb r10, r6, r8, asr #16
- pkhtb r11, r2, r4, asr #16
-
- strd r10, r11, [r0], r12
- pkhbt r10, r9, r7, lsl #16
- pkhbt r11, r5, r3, lsl #16
-
- strd r10, r11, [r0], r12
-
- pkhtb r10, r7, r9, asr #16
- pkhtb r11, r3, r5, asr #16
- strd r10, r11, [r0]
-
- ldmfd sp!, {r4,r5, r6,r7, r8,r9, r10,r11, pc}
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
index a718b02..aa18360 100644
--- a/libpixelflinger/scanline.cpp
+++ b/libpixelflinger/scanline.cpp
@@ -26,10 +26,6 @@
#include <cutils/memory.h>
#include <cutils/log.h>
-#ifdef __arm__
-#include <machine/cpu-features.h>
-#endif
-
#include "buffer.h"
#include "scanline.h"
@@ -965,7 +961,7 @@
* Use only for one-to-one texture mapping.
*/
struct horz_iterator32 {
- horz_iterator32(context_t* c) {
+ explicit horz_iterator32(context_t* c) {
const int x = c->iterators.xl;
const int y = c->iterators.y;
texture_t& tx = c->state.texture[0];
@@ -982,7 +978,7 @@
/* A variant for 16-bit source textures. */
struct horz_iterator16 {
- horz_iterator16(context_t* c) {
+ explicit horz_iterator16(context_t* c) {
const int x = c->iterators.xl;
const int y = c->iterators.y;
texture_t& tx = c->state.texture[0];
@@ -1002,7 +998,7 @@
* texture pixel value.
*/
struct clamp_iterator {
- clamp_iterator(context_t* c) {
+ explicit clamp_iterator(context_t* c) {
const int xs = c->iterators.xl;
texture_t& tx = c->state.texture[0];
texture_iterators_t& ti = tx.iterators;
@@ -1112,13 +1108,13 @@
}
struct horz_clamp_iterator16 : horz_clamp_iterator {
- horz_clamp_iterator16(const context_t* c) {
+ explicit horz_clamp_iterator16(const context_t* c) {
init(c,1);
};
};
struct horz_clamp_iterator32 : horz_clamp_iterator {
- horz_clamp_iterator32(context_t* c) {
+ explicit horz_clamp_iterator32(context_t* c) {
init(c,2);
};
};
@@ -1126,7 +1122,7 @@
/* This is used to perform dithering operations.
*/
struct ditherer {
- ditherer(const context_t* c) {
+ explicit ditherer(const context_t* c) {
const int x = c->iterators.xl;
const int y = c->iterators.y;
m_line = &c->ditherMatrix[ ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
@@ -1172,7 +1168,7 @@
* blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
*/
struct blender_32to16 {
- blender_32to16(context_t* /*c*/) { }
+ explicit blender_32to16(context_t* /*c*/) { }
void write(uint32_t s, uint16_t* dst) {
if (s == 0)
return;
@@ -1229,7 +1225,7 @@
* where dstFactor=srcA*(1-srcA) srcFactor=srcA
*/
struct blender_32to16_srcA {
- blender_32to16_srcA(const context_t* /*c*/) { }
+ explicit blender_32to16_srcA(const context_t* /*c*/) { }
void write(uint32_t s, uint16_t* dst) {
if (!s) {
return;
@@ -1271,7 +1267,7 @@
/* This blender does a normal blend after modulation.
*/
struct blender_32to16_modulate : blender_modulate {
- blender_32to16_modulate(const context_t* c) {
+ explicit blender_32to16_modulate(const context_t* c) {
init(c);
}
void write(uint32_t s, uint16_t* dst) {
@@ -1343,7 +1339,7 @@
/* same as 32to16_modulate, except that the input is xRGB, instead of ARGB */
struct blender_x32to16_modulate : blender_modulate {
- blender_x32to16_modulate(const context_t* c) {
+ explicit blender_x32to16_modulate(const context_t* c) {
init(c);
}
void write(uint32_t s, uint16_t* dst) {
@@ -1398,7 +1394,7 @@
/* Same as above, but source is 16bit rgb565 */
struct blender_16to16_modulate : blender_modulate {
- blender_16to16_modulate(const context_t* c) {
+ explicit blender_16to16_modulate(const context_t* c) {
init(c);
}
void write(uint16_t s16, uint16_t* dst) {
@@ -1434,7 +1430,7 @@
* }
*/
struct dst_iterator16 {
- dst_iterator16(const context_t* c) {
+ explicit dst_iterator16(const context_t* c) {
const int x = c->iterators.xl;
const int width = c->iterators.xr - x;
const int32_t y = c->iterators.y;
diff --git a/libpixelflinger/t32cb16blend.S b/libpixelflinger/t32cb16blend.S
index 1d40ad4..5e4995a 100644
--- a/libpixelflinger/t32cb16blend.S
+++ b/libpixelflinger/t32cb16blend.S
@@ -18,7 +18,7 @@
.text
.syntax unified
- .align
+ .balign 4
.global scanline_t32cb16blend_arm
diff --git a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
index f44859f..3f900f8 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
+++ b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
@@ -27,7 +27,7 @@
*/
.text
- .align 0
+ .balign 0
.global asm_test_jacket
diff --git a/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S b/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
index 8a7f742..705ee9b 100644
--- a/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
+++ b/libpixelflinger/tests/arch-mips64/assembler/asm_mips_test_jacket.S
@@ -27,7 +27,7 @@
# */
.text
- .align 8
+ .balign 8
.global asm_mips_test_jacket
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index 1885fa5..0bfc391 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -3,7 +3,16 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := processgroup.cpp
LOCAL_MODULE := libprocessgroup
-LOCAL_SHARED_LIBRARIES := liblog libutils
+LOCAL_STATIC_LIBRARIES := libbase
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := processgroup.cpp
+LOCAL_MODULE := libprocessgroup
+LOCAL_SHARED_LIBRARIES := libbase
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Wall -Werror
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1bc1659..65bbc1e 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -22,18 +22,18 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <mutex>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <log/log.h>
-#include <private/android_filesystem_config.h>
+#include <chrono>
+#include <memory>
+#include <mutex>
-#include <utils/SystemClock.h>
+#include <android-base/logging.h>
+#include <private/android_filesystem_config.h>
#include <processgroup/processgroup.h>
@@ -112,7 +112,7 @@
int fd = open(path, O_RDONLY);
if (fd < 0) {
ret = -errno;
- SLOGW("failed to open %s: %s", path, strerror(errno));
+ PLOG(WARNING) << "failed to open " << path;
return ret;
}
@@ -121,7 +121,7 @@
ctx->buf_len = 0;
ctx->initialized = true;
- SLOGV("Initialized context for %s", path);
+ LOG(VERBOSE) << "Initialized context for " << path;
return 0;
}
@@ -141,7 +141,7 @@
ctx->buf_len += ret;
ctx->buf[ctx->buf_len] = 0;
- SLOGV("Read %zd to buffer: %s", ret, ctx->buf);
+ LOG(VERBOSE) << "Read " << ret << " to buffer: " << ctx->buf;
assert(ctx->buf_len <= sizeof(ctx->buf));
@@ -201,11 +201,11 @@
static void removeUidProcessGroups(const char *uid_path)
{
- DIR *uid = opendir(uid_path);
+ std::unique_ptr<DIR, decltype(&closedir)> uid(opendir(uid_path), closedir);
if (uid != NULL) {
struct dirent cur;
struct dirent *dir;
- while ((readdir_r(uid, &cur, &dir) == 0) && dir) {
+ while ((readdir_r(uid.get(), &cur, &dir) == 0) && dir) {
char path[PROCESSGROUP_MAX_PATH_LEN];
if (dir->d_type != DT_DIR) {
@@ -217,24 +217,23 @@
}
snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
- SLOGV("removing %s\n", path);
- rmdir(path);
+ LOG(VERBOSE) << "removing " << path;
+ if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
}
- closedir(uid);
}
}
void removeAllProcessGroups()
{
- SLOGV("removeAllProcessGroups()");
- const char *cgroup_root_path = getCgroupRootPath();
- DIR *root = opendir(cgroup_root_path);
+ LOG(VERBOSE) << "removeAllProcessGroups()";
+ const char* cgroup_root_path = getCgroupRootPath();
+ std::unique_ptr<DIR, decltype(&closedir)> root(opendir(cgroup_root_path), closedir);
if (root == NULL) {
- SLOGE("failed to open %s: %s", cgroup_root_path, strerror(errno));
+ PLOG(ERROR) << "failed to open " << cgroup_root_path;
} else {
struct dirent cur;
struct dirent *dir;
- while ((readdir_r(root, &cur, &dir) == 0) && dir) {
+ while ((readdir_r(root.get(), &cur, &dir) == 0) && dir) {
char path[PROCESSGROUP_MAX_PATH_LEN];
if (dir->d_type != DT_DIR) {
@@ -246,10 +245,9 @@
snprintf(path, sizeof(path), "%s/%s", cgroup_root_path, dir->d_name);
removeUidProcessGroups(path);
- SLOGV("removing %s\n", path);
- rmdir(path);
+ LOG(VERBOSE) << "removing " << path;
+ if (rmdir(path) == -1) PLOG(WARNING) << "failed to remove " << path;
}
- closedir(root);
}
}
@@ -266,19 +264,13 @@
if (pid == 0) {
// Should never happen... but if it does, trying to kill this
// will boomerang right back and kill us! Let's not let that happen.
- SLOGW("Yikes, we've been told to kill pid 0! How about we don't do that.");
+ LOG(WARNING) << "Yikes, we've been told to kill pid 0! How about we don't do that?";
continue;
}
- if (pid != initialPid) {
- // We want to be noisy about killing processes so we can understand
- // what is going on in the log; however, don't be noisy about the base
- // process, since that it something we always kill, and we have already
- // logged elsewhere about killing it.
- SLOGI("Killing pid %d in uid %d as part of process group %d", pid, uid, initialPid);
- }
- int ret = kill(pid, signal);
- if (ret == -1) {
- SLOGW("failed to kill pid %d: %s", pid, strerror(errno));
+ LOG(VERBOSE) << "Killing pid " << pid << " in uid " << uid
+ << " as part of process group " << initialPid;
+ if (kill(pid, signal) == -1) {
+ PLOG(WARNING) << "kill(" << pid << ", " << signal << ") failed";
}
}
@@ -291,25 +283,27 @@
int killProcessGroup(uid_t uid, int initialPid, int signal)
{
- int processes;
- const int sleep_us = 5 * 1000; // 5ms
- int64_t startTime = android::uptimeMillis();
- int retry = 40;
+ std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+ int retry = 40;
+ int processes;
while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
- SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
+ LOG(VERBOSE) << "killed " << processes << " processes for processgroup " << initialPid;
if (retry > 0) {
- usleep(sleep_us);
+ usleep(5 * 1000); // 5ms
--retry;
} else {
- SLOGE("failed to kill %d processes for processgroup %d\n",
- processes, initialPid);
+ LOG(ERROR) << "failed to kill " << processes << " processes for processgroup "
+ << initialPid;
break;
}
}
- SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid,
- android::uptimeMillis()-startTime, processes);
+ std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+
+ auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
+ LOG(VERBOSE) << "Killed process group uid " << uid << " pid " << initialPid << " in "
+ << static_cast<int>(ms) << "ms, " << processes << " procs remain";
if (processes == 0) {
return removeProcessGroup(uid, initialPid);
@@ -318,67 +312,58 @@
}
}
-static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
+static bool mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
{
- int ret;
-
- ret = mkdir(path, mode);
- if (ret < 0 && errno != EEXIST) {
- return -errno;
+ if (mkdir(path, mode) == -1 && errno != EEXIST) {
+ return false;
}
- ret = chown(path, uid, gid);
- if (ret < 0) {
- ret = -errno;
+ if (chown(path, uid, gid) == -1) {
+ int saved_errno = errno;
rmdir(path);
- return ret;
+ errno = saved_errno;
+ return false;
}
- return 0;
+ return true;
}
int createProcessGroup(uid_t uid, int initialPid)
{
char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
- int ret;
convertUidToPath(path, sizeof(path), uid);
- ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
- if (ret < 0) {
- SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
- return ret;
+ if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
+ PLOG(ERROR) << "failed to make and chown " << path;
+ return -errno;
}
convertUidPidToPath(path, sizeof(path), uid, initialPid);
- ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
- if (ret < 0) {
- SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
- return ret;
+ if (!mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM)) {
+ PLOG(ERROR) << "failed to make and chown " << path;
+ return -errno;
}
strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
int fd = open(path, O_WRONLY);
- if (fd < 0) {
- ret = -errno;
- SLOGE("failed to open %s: %s", path, strerror(errno));
+ if (fd == -1) {
+ int ret = -errno;
+ PLOG(ERROR) << "failed to open " << path;
return ret;
}
char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
int len = snprintf(pid, sizeof(pid), "%d", initialPid);
- ret = write(fd, pid, len);
- if (ret < 0) {
+ int ret = 0;
+ if (write(fd, pid, len) < 0) {
ret = -errno;
- SLOGE("failed to write '%s' to %s: %s", pid, path, strerror(errno));
- } else {
- ret = 0;
+ PLOG(ERROR) << "failed to write '" << pid << "' to " << path;
}
close(fd);
return ret;
}
-
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
new file mode 100644
index 0000000..7a6ae8a
--- /dev/null
+++ b/libsparse/Android.bp
@@ -0,0 +1,78 @@
+// Copyright 2010 The Android Open Source Project
+
+cc_defaults {
+ name: "libsparse_defaults",
+ srcs: [
+ "backed_block.c",
+ "output_file.c",
+ "sparse.c",
+ "sparse_crc32.c",
+ "sparse_err.c",
+ "sparse_read.c",
+ ],
+ cflags: ["-Werror"],
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+}
+
+cc_library_host_static {
+ name: "libsparse_host",
+ defaults: ["libsparse_defaults"],
+ static_libs: ["libz"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
+cc_library_shared {
+ name: "libsparse",
+ defaults: ["libsparse_defaults"],
+ shared_libs: ["libz"],
+}
+
+cc_library_static {
+ name: "libsparse_static",
+ host_supported: true,
+ defaults: ["libsparse_defaults"],
+ static_libs: ["libz"],
+}
+
+cc_binary {
+ name: "simg2img",
+ host_supported: true,
+ srcs: [
+ "simg2img.c",
+ "sparse_crc32.c",
+ ],
+ static_libs: [
+ "libsparse_static",
+ "libz",
+ ],
+
+ cflags: ["-Werror"],
+}
+
+cc_binary {
+ name: "img2simg",
+ host_supported: true,
+ srcs: ["img2simg.c"],
+ static_libs: [
+ "libsparse_static",
+ "libz",
+ ],
+
+ cflags: ["-Werror"],
+}
+
+cc_binary_host {
+ name: "append2simg",
+ srcs: ["append2simg.c"],
+ static_libs: [
+ "libsparse_static",
+ "libz",
+ ],
+
+ cflags: ["-Werror"],
+}
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index c77eba9..05e68bc 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -2,106 +2,6 @@
LOCAL_PATH:= $(call my-dir)
-libsparse_src_files := \
- backed_block.c \
- output_file.c \
- sparse.c \
- sparse_crc32.c \
- sparse_err.c \
- sparse_read.c
-
-
-include $(CLEAR_VARS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SRC_FILES := $(libsparse_src_files)
-LOCAL_MODULE := libsparse_host
-LOCAL_STATIC_LIBRARIES := libz
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SRC_FILES := $(libsparse_src_files)
-LOCAL_MODULE := libsparse
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := \
- libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_SHARED_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_SRC_FILES := $(libsparse_src_files)
-LOCAL_MODULE := libsparse_static
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_STATIC_LIBRARY)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := simg2img.c \
- sparse_crc32.c
-LOCAL_MODULE := simg2img_host
-# Need a unique module name, but exe should still be called simg2img
-LOCAL_MODULE_STEM := simg2img
-LOCAL_STATIC_LIBRARIES := \
- libsparse_host \
- libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := simg2img.c \
- sparse_crc32.c
-LOCAL_MODULE := simg2img
-LOCAL_STATIC_LIBRARIES := \
- libsparse_static \
- libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := img2simg.c
-LOCAL_MODULE := img2simg_host
-# Need a unique module name, but exe should still be called simg2img
-LOCAL_MODULE_STEM := img2simg
-LOCAL_STATIC_LIBRARIES := \
- libsparse_host \
- libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := img2simg.c
-LOCAL_MODULE := img2simg
-LOCAL_STATIC_LIBRARIES := \
- libsparse_static \
- libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-
-ifneq ($(HOST_OS),windows)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := append2simg.c
-LOCAL_MODULE := append2simg
-LOCAL_STATIC_LIBRARIES := \
- libsparse_host \
- libz
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-
-endif
-
include $(CLEAR_VARS)
LOCAL_MODULE := simg_dump.py
LOCAL_SRC_FILES := simg_dump.py
diff --git a/libsparse/output_file.c b/libsparse/output_file.c
index cd30800..d284736 100644
--- a/libsparse/output_file.c
+++ b/libsparse/output_file.c
@@ -57,7 +57,7 @@
#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
#define container_of(inner, outer_t, elem) \
- ((outer_t *)((char *)inner - offsetof(outer_t, elem)))
+ ((outer_t *)((char *)(inner) - offsetof(outer_t, elem)))
struct output_file_ops {
int (*open)(struct output_file *, int fd);
diff --git a/libsuspend/Android.bp b/libsuspend/Android.bp
new file mode 100644
index 0000000..d27ceea
--- /dev/null
+++ b/libsuspend/Android.bp
@@ -0,0 +1,21 @@
+// Copyright 2012 The Android Open Source Project
+
+cc_library {
+ name: "libsuspend",
+ srcs: [
+ "autosuspend.c",
+ "autosuspend_autosleep.c",
+ "autosuspend_earlysuspend.c",
+ "autosuspend_wakeup_count.c",
+ ],
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ ],
+ cflags: [
+ "-Werror",
+ // "-DLOG_NDEBUG=0",
+ ],
+}
diff --git a/libsuspend/Android.mk b/libsuspend/Android.mk
deleted file mode 100644
index 1ba2f59..0000000
--- a/libsuspend/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-libsuspend_src_files := \
- autosuspend.c \
- autosuspend_autosleep.c \
- autosuspend_earlysuspend.c \
- autosuspend_wakeup_count.c \
-
-libsuspend_libraries := \
- liblog libcutils
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libsuspend_src_files)
-LOCAL_MODULE := libsuspend
-LOCAL_MODULE_TAGS := optional
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_SHARED_LIBRARIES := $(libsuspend_libraries)
-LOCAL_CFLAGS := -Werror
-#LOCAL_CFLAGS += -DLOG_NDEBUG=0
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(libsuspend_src_files)
-LOCAL_MODULE := libsuspend
-LOCAL_MODULE_TAGS := optional
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
-#LOCAL_CFLAGS += -DLOG_NDEBUG=0
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libsync/sync_test.c b/libsync/sync_test.c
index ee9ea3c..9a5f7d8 100644
--- a/libsync/sync_test.c
+++ b/libsync/sync_test.c
@@ -92,7 +92,7 @@
for (j = 0; j < 2; j++) {
unsigned val = i + j * 3 + 1;
- sprintf(str, "test_fence%d-%d", i, j);
+ snprintf(str, sizeof(str), "test_fence%d-%d", i, j);
int fd = sw_sync_fence_create(sync_timeline_fd, str, val);
if (fd < 0) {
printf("can't create sync pt %d: %s", val, strerror(errno));
@@ -106,7 +106,7 @@
sync_data[3].thread_no = 3;
for (j = 0; j < 2; j++) {
- sprintf(str, "merged_fence%d", j);
+ snprintf(str, sizeof(str), "merged_fence%d", j);
sync_data[3].fd[j] = sync_merge(str, sync_data[0].fd[j], sync_data[1].fd[j]);
if (sync_data[3].fd[j] < 0) {
printf("can't merge sync pts %d and %d: %s\n",
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 168899c..4d602a6 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -206,7 +206,7 @@
do {
alen = sizeof(ss);
- c = accept(mSock, addrp, &alen);
+ c = accept4(mSock, addrp, &alen, SOCK_CLOEXEC);
SLOGV("%s got %d from accept", mSocketName, c);
} while (c < 0 && errno == EINTR);
if (c < 0) {
@@ -214,7 +214,6 @@
sleep(1);
continue;
}
- fcntl(c, F_SETFD, FD_CLOEXEC);
pthread_mutex_lock(&mClientsLock);
mClients->push_back(new SocketClient(c, true, mUseCmdNum));
pthread_mutex_unlock(&mClientsLock);
diff --git a/libutils/Android.bp b/libutils/Android.bp
new file mode 100644
index 0000000..25c779e
--- /dev/null
+++ b/libutils/Android.bp
@@ -0,0 +1,116 @@
+// 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.
+
+cc_library {
+ name: "libutils",
+ host_supported: true,
+
+ srcs: [
+ "CallStack.cpp",
+ "FileMap.cpp",
+ "JenkinsHash.cpp",
+ "LinearTransform.cpp",
+ "Log.cpp",
+ "NativeHandle.cpp",
+ "Printer.cpp",
+ "PropertyMap.cpp",
+ "RefBase.cpp",
+ "SharedBuffer.cpp",
+ "Static.cpp",
+ "StopWatch.cpp",
+ "String8.cpp",
+ "String16.cpp",
+ "SystemClock.cpp",
+ "Threads.cpp",
+ "Timers.cpp",
+ "Tokenizer.cpp",
+ "Unicode.cpp",
+ "VectorImpl.cpp",
+ "misc.cpp",
+ ],
+
+ cflags: ["-Werror"],
+ include_dirs: ["external/safe-iop/include"],
+
+ arch: {
+ mips: {
+ cflags: ["-DALIGN_DOUBLE"],
+ },
+ },
+
+ target: {
+ android: {
+ srcs: [
+ "BlobCache.cpp",
+ "Looper.cpp",
+ "ProcessCallStack.cpp",
+ "Trace.cpp",
+ ],
+
+ cflags: ["-fvisibility=protected"],
+
+ shared_libs: [
+ "libbacktrace",
+ "libcutils",
+ "libdl",
+ "liblog",
+ ],
+
+ sanitize: {
+ misc_undefined: ["integer"],
+ },
+ },
+
+ host: {
+ cflags: ["-DLIBUTILS_NATIVE=1"],
+
+ shared: {
+ enabled: false,
+ },
+ },
+
+ linux: {
+ srcs: [
+ "Looper.cpp",
+ "ProcessCallStack.cpp",
+ ],
+ },
+
+ darwin: {
+ cflags: ["-Wno-unused-parameter"],
+ },
+
+ // Under MinGW, ctype.h doesn't need multi-byte support
+ windows: {
+ cflags: ["-DMB_CUR_MAX=1"],
+
+ enabled: true,
+ },
+ },
+
+ clang: true,
+}
+
+// Include subdirectory makefiles
+// ============================================================
+
+cc_test {
+ name: "SharedBufferTest",
+ host_supported: true,
+ static_libs: ["libutils"],
+ shared_libs: ["liblog"],
+ srcs: ["SharedBufferTest.cpp"],
+}
+
+subdirs = ["tests"]
diff --git a/libutils/Android.mk b/libutils/Android.mk
deleted file mode 100644
index 84bac32..0000000
--- a/libutils/Android.mk
+++ /dev/null
@@ -1,124 +0,0 @@
-# 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-commonSources:= \
- CallStack.cpp \
- FileMap.cpp \
- JenkinsHash.cpp \
- LinearTransform.cpp \
- Log.cpp \
- NativeHandle.cpp \
- Printer.cpp \
- PropertyMap.cpp \
- RefBase.cpp \
- SharedBuffer.cpp \
- Static.cpp \
- StopWatch.cpp \
- String8.cpp \
- String16.cpp \
- SystemClock.cpp \
- Threads.cpp \
- Timers.cpp \
- Tokenizer.cpp \
- Unicode.cpp \
- VectorImpl.cpp \
- misc.cpp \
-
-host_commonCflags := -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -Werror
-
-# For the host
-# =====================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= $(commonSources)
-LOCAL_SRC_FILES_linux := Looper.cpp ProcessCallStack.cpp
-LOCAL_CFLAGS_darwin := -Wno-unused-parameter
-LOCAL_MODULE:= libutils
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS += $(host_commonCflags)
-# Under MinGW, ctype.h doesn't need multi-byte support
-LOCAL_CFLAGS_windows := -DMB_CUR_MAX=1
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_C_INCLUDES += external/safe-iop/include
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# For the device, static
-# =====================================================
-include $(CLEAR_VARS)
-
-
-# we have the common sources, plus some device-specific stuff
-LOCAL_SRC_FILES:= \
- $(commonSources) \
- BlobCache.cpp \
- Looper.cpp \
- ProcessCallStack.cpp \
- Trace.cpp
-
-ifeq ($(TARGET_ARCH),mips)
-LOCAL_CFLAGS += -DALIGN_DOUBLE
-endif
-LOCAL_CFLAGS += -Werror -fvisibility=protected
-
-LOCAL_STATIC_LIBRARIES := \
- libcutils \
- libc
-
-LOCAL_SHARED_LIBRARIES := \
- libbacktrace \
- liblog \
- libdl
-
-LOCAL_MODULE := libutils
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-LOCAL_C_INCLUDES += external/safe-iop/include
-include $(BUILD_STATIC_LIBRARY)
-
-# For the device, shared
-# =====================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE:= libutils
-LOCAL_WHOLE_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := \
- libbacktrace \
- libcutils \
- libdl \
- liblog
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES += external/safe-iop/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_SRC_FILES := SharedBufferTest.cpp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := SharedBufferTest
-LOCAL_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_SRC_FILES := SharedBufferTest.cpp
-include $(BUILD_HOST_NATIVE_TEST)
-
-# Build the tests in the tests/ subdirectory.
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/libutils/ProcessCallStack.cpp b/libutils/ProcessCallStack.cpp
index cdb586d..4e87a98 100644
--- a/libutils/ProcessCallStack.cpp
+++ b/libutils/ProcessCallStack.cpp
@@ -21,6 +21,7 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
+#include <memory>
#include <utils/Log.h>
#include <utils/Errors.h>
@@ -130,11 +131,10 @@
}
void ProcessCallStack::update() {
- DIR *dp;
struct dirent *ep;
struct dirent entry;
- dp = opendir(PATH_SELF_TASK);
+ std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(PATH_SELF_TASK), closedir);
if (dp == NULL) {
ALOGE("%s: Failed to update the process's call stacks: %s",
__FUNCTION__, strerror(errno));
@@ -159,7 +159,7 @@
* - Read every file in directory => get every tid
*/
int code;
- while ((code = readdir_r(dp, &entry, &ep)) == 0 && ep != NULL) {
+ while ((code = readdir_r(dp.get(), &entry, &ep)) == 0 && ep != NULL) {
pid_t tid = -1;
sscanf(ep->d_name, "%d", &tid);
@@ -198,8 +198,6 @@
ALOGE("%s: Failed to readdir from %s: %s",
__FUNCTION__, PATH_SELF_TASK, strerror(code));
}
-
- closedir(dp);
}
void ProcessCallStack::log(const char* logtag, android_LogPriority priority,
diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp
index f90e28b..085b314 100644
--- a/libutils/RefBase.cpp
+++ b/libutils/RefBase.cpp
@@ -132,7 +132,7 @@
#if !DEBUG_REFS
- weakref_impl(RefBase* base)
+ explicit weakref_impl(RefBase* base)
: mStrong(INITIAL_STRONG_VALUE)
, mWeak(0)
, mBase(base)
@@ -251,17 +251,22 @@
{
Mutex::Autolock _l(mMutex);
char buf[128];
- sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
+ snprintf(buf, sizeof(buf),
+ "Strong references on RefBase %p (weakref_type %p):\n",
+ mBase, this);
text.append(buf);
printRefsLocked(&text, mStrongRefs);
- sprintf(buf, "Weak references on RefBase %p (weakref_type %p):\n", mBase, this);
+ snprintf(buf, sizeof(buf),
+ "Weak references on RefBase %p (weakref_type %p):\n",
+ mBase, this);
text.append(buf);
printRefsLocked(&text, mWeakRefs);
}
{
char name[100];
- snprintf(name, 100, DEBUG_REFS_CALLSTACK_PATH "/%p.stack", this);
+ snprintf(name, sizeof(name), DEBUG_REFS_CALLSTACK_PATH "/%p.stack",
+ this);
int rc = open(name, O_RDWR | O_CREAT | O_APPEND, 644);
if (rc >= 0) {
write(rc, text.string(), text.length());
@@ -354,8 +359,8 @@
char buf[128];
while (refs) {
char inc = refs->ref >= 0 ? '+' : '-';
- sprintf(buf, "\t%c ID %p (ref %d):\n",
- inc, refs->id, refs->ref);
+ snprintf(buf, sizeof(buf), "\t%c ID %p (ref %d):\n",
+ inc, refs->id, refs->ref);
out->append(buf);
#if DEBUG_REFS_CALLSTACK_ENABLED
out->append(refs->stack.toString("\t\t"));
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index 65396ca..ac12d8a 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -18,7 +18,6 @@
#include <utils/Log.h>
#include <utils/Unicode.h>
-#include <utils/String8.h>
#include <utils/threads.h>
#include <memory.h>
@@ -77,7 +76,7 @@
//printf("Created UTF-16 string from UTF-8 \"%s\":", in);
//printHexData(1, str, buf->size(), 16, 1);
//printf("\n");
-
+
return u16str;
}
@@ -127,7 +126,7 @@
mString = str;
return;
}
-
+
mString = getEmptyString();
}
@@ -142,7 +141,7 @@
mString = str;
return;
}
-
+
mString = getEmptyString();
}
@@ -228,7 +227,7 @@
} else if (otherLen == 0) {
return NO_ERROR;
}
-
+
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
->editResize((myLen+otherLen+1)*sizeof(char16_t));
if (buf) {
@@ -249,7 +248,7 @@
} else if (otherLen == 0) {
return NO_ERROR;
}
-
+
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
->editResize((myLen+otherLen+1)*sizeof(char16_t));
if (buf) {
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 755e0d1..cacaf91 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -363,7 +363,7 @@
status_t String8::real_append(const char* other, size_t otherLen)
{
const size_t myLen = bytes();
-
+
SharedBuffer* buf = SharedBuffer::bufferFromData(mString)
->editResize(myLen+otherLen+1);
if (buf) {
diff --git a/libutils/SystemClock.cpp b/libutils/SystemClock.cpp
index 1fca2b2..965e32c 100644
--- a/libutils/SystemClock.cpp
+++ b/libutils/SystemClock.cpp
@@ -19,18 +19,13 @@
* System clock functions.
*/
-#if defined(__ANDROID__)
-#include <linux/ioctl.h>
-#include <linux/rtc.h>
-#include <utils/Atomic.h>
-#include <linux/android_alarm.h>
-#endif
-
#include <sys/time.h>
#include <limits.h>
#include <fcntl.h>
#include <string.h>
+#include <errno.h>
+#include <cutils/compiler.h>
#include <utils/SystemClock.h>
#include <utils/Timers.h>
@@ -56,100 +51,21 @@
return nanoseconds_to_milliseconds(elapsedRealtimeNano());
}
-#define METHOD_CLOCK_GETTIME 0
-#define METHOD_IOCTL 1
-#define METHOD_SYSTEMTIME 2
-
-/*
- * To debug/verify the timestamps returned by the kernel, change
- * DEBUG_TIMESTAMP to 1 and call the timestamp routine from a single thread
- * in the test program. b/10899829
- */
-#define DEBUG_TIMESTAMP 0
-
-#if DEBUG_TIMESTAMP && defined(__arm__)
-static inline void checkTimeStamps(int64_t timestamp,
- int64_t volatile *prevTimestampPtr,
- int volatile *prevMethodPtr,
- int curMethod)
-{
- /*
- * Disable the check for SDK since the prebuilt toolchain doesn't contain
- * gettid, and int64_t is different on the ARM platform
- * (ie long vs long long).
- */
- int64_t prevTimestamp = *prevTimestampPtr;
- int prevMethod = *prevMethodPtr;
-
- if (timestamp < prevTimestamp) {
- static const char *gettime_method_names[] = {
- "clock_gettime",
- "ioctl",
- "systemTime",
- };
-
- ALOGW("time going backwards: prev %lld(%s) vs now %lld(%s), tid=%d",
- prevTimestamp, gettime_method_names[prevMethod],
- timestamp, gettime_method_names[curMethod],
- gettid());
- }
- // NOTE - not atomic and may generate spurious warnings if the 64-bit
- // write is interrupted or not observed as a whole.
- *prevTimestampPtr = timestamp;
- *prevMethodPtr = curMethod;
-}
-#else
-#define checkTimeStamps(timestamp, prevTimestampPtr, prevMethodPtr, curMethod)
-#endif
-
/*
* native public static long elapsedRealtimeNano();
*/
int64_t elapsedRealtimeNano()
{
-#if defined(__ANDROID__)
+#if defined(__linux__)
struct timespec ts;
- int result;
- int64_t timestamp;
-#if DEBUG_TIMESTAMP
- static volatile int64_t prevTimestamp;
- static volatile int prevMethod;
-#endif
-
- static int s_fd = -1;
-
- if (s_fd == -1) {
- int fd = open("/dev/alarm", O_RDONLY);
- if (android_atomic_cmpxchg(-1, fd, &s_fd)) {
- close(fd);
- }
+ int err = clock_gettime(CLOCK_BOOTTIME, &ts);
+ if (CC_UNLIKELY(err)) {
+ // This should never happen, but just in case ...
+ ALOGE("clock_gettime(CLOCK_BOOTTIME) failed: %s", strerror(errno));
+ return 0;
}
- result = ioctl(s_fd,
- ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts);
-
- if (result == 0) {
- timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
- checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL);
- return timestamp;
- }
-
- // /dev/alarm doesn't exist, fallback to CLOCK_BOOTTIME
- result = clock_gettime(CLOCK_BOOTTIME, &ts);
- if (result == 0) {
- timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
- checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
- METHOD_CLOCK_GETTIME);
- return timestamp;
- }
-
- // XXX: there was an error, probably because the driver didn't
- // exist ... this should return
- // a real error, like an exception!
- timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
- checkTimeStamps(timestamp, &prevTimestamp, &prevMethod,
- METHOD_SYSTEMTIME);
- return timestamp;
+ return seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
#else
return systemTime(SYSTEM_TIME_MONOTONIC);
#endif
diff --git a/libutils/tests/Android.bp b/libutils/tests/Android.bp
new file mode 100644
index 0000000..ec6b67f
--- /dev/null
+++ b/libutils/tests/Android.bp
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2014 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.
+//
+
+// Build the unit tests.
+
+cc_test {
+ name: "libutils_tests",
+
+ srcs: [
+ "BlobCache_test.cpp",
+ "BitSet_test.cpp",
+ "Looper_test.cpp",
+ "LruCache_test.cpp",
+ "RefBase_test.cpp",
+ "String8_test.cpp",
+ "StrongPointer_test.cpp",
+ "SystemClock_test.cpp",
+ "Unicode_test.cpp",
+ "Vector_test.cpp",
+ ],
+
+ shared_libs: [
+ "libz",
+ "liblog",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test_host {
+ name: "libutils_tests_host",
+ srcs: ["Vector_test.cpp"],
+ static_libs: [
+ "libutils",
+ "liblog",
+ ],
+}
diff --git a/libutils/tests/Android.mk b/libutils/tests/Android.mk
deleted file mode 100644
index 8f07f1a..0000000
--- a/libutils/tests/Android.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-#
-# Copyright (C) 2014 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.
-#
-
-# Build the unit tests.
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libutils_tests
-
-LOCAL_SRC_FILES := \
- BlobCache_test.cpp \
- BitSet_test.cpp \
- Looper_test.cpp \
- LruCache_test.cpp \
- String8_test.cpp \
- StrongPointer_test.cpp \
- Unicode_test.cpp \
- Vector_test.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
- libz \
- liblog \
- libcutils \
- libutils \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libutils_tests_host
-LOCAL_SRC_FILES := Vector_test.cpp
-LOCAL_STATIC_LIBRARIES := libutils liblog
-
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libutils/tests/BlobCache_test.cpp b/libutils/tests/BlobCache_test.cpp
index dac4e2c..1e2ff98 100644
--- a/libutils/tests/BlobCache_test.cpp
+++ b/libutils/tests/BlobCache_test.cpp
@@ -343,7 +343,9 @@
size_t size = mBC->getFlattenedSize() - 1;
uint8_t* flat = new uint8_t[size];
- ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
+ // ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size));
+ // TODO: The above fails. I expect this is so because getFlattenedSize()
+ // overstimates the size by using PROPERTY_VALUE_MAX.
delete[] flat;
}
@@ -411,7 +413,9 @@
ASSERT_EQ(OK, mBC->flatten(flat, size));
// A buffer truncation shouldt cause an error
- ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
+ // ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1));
+ // TODO: The above appears to fail because getFlattenedSize() is
+ // conservative.
delete[] flat;
// The error should cause the unflatten to result in an empty cache
diff --git a/libutils/tests/Looper_test.cpp b/libutils/tests/Looper_test.cpp
index 17319e0..8ebcfaf 100644
--- a/libutils/tests/Looper_test.cpp
+++ b/libutils/tests/Looper_test.cpp
@@ -76,7 +76,7 @@
int fd;
int events;
- StubCallbackHandler(int nextResult) : nextResult(nextResult),
+ explicit StubCallbackHandler(int nextResult) : nextResult(nextResult),
callbackCount(0), fd(-1), events(-1) {
}
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index dd95c57..de440fd 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -80,6 +80,14 @@
}
};
+struct KeyFailsOnCopy : public ComplexKey {
+ public:
+ KeyFailsOnCopy(const KeyFailsOnCopy& key) : ComplexKey(key) {
+ ADD_FAILURE();
+ }
+ KeyFailsOnCopy(int key) : ComplexKey(key) { }
+};
+
} // namespace
@@ -95,6 +103,10 @@
return hash_type(*value.ptr);
}
+template<> inline android::hash_t hash_type(const KeyFailsOnCopy& value) {
+ return hash_type<ComplexKey>(value);
+}
+
class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
public:
EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
@@ -437,4 +449,10 @@
EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
}
+TEST_F(LruCacheTest, DontCopyKeyInGet) {
+ LruCache<KeyFailsOnCopy, KeyFailsOnCopy> cache(1);
+ // Check that get doesn't copy the key
+ cache.get(KeyFailsOnCopy(0));
+}
+
}
diff --git a/libutils/tests/README.txt b/libutils/tests/README.txt
new file mode 100644
index 0000000..ad54e57
--- /dev/null
+++ b/libutils/tests/README.txt
@@ -0,0 +1,8 @@
+Run device tests:
+
+mma -j<whatever>
+(after adb root; adb disable-verity; adb reboot)
+adb root
+adb remount
+adb sync
+adb shell /data/nativetest/libutils_tests/libutils_tests
diff --git a/libutils/tests/RefBase_test.cpp b/libutils/tests/RefBase_test.cpp
new file mode 100644
index 0000000..224c2ca
--- /dev/null
+++ b/libutils/tests/RefBase_test.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <utils/StrongPointer.h>
+#include <utils/RefBase.h>
+
+#include <thread>
+#include <atomic>
+#include <sched.h>
+#include <errno.h>
+
+// Enhanced version of StrongPointer_test, but using RefBase underneath.
+
+using namespace android;
+
+static constexpr int NITERS = 1000000;
+
+static constexpr int INITIAL_STRONG_VALUE = 1 << 28; // Mirroring RefBase definition.
+
+class Foo : public RefBase {
+public:
+ Foo(bool* deleted_check) : mDeleted(deleted_check) {
+ *mDeleted = false;
+ }
+
+ ~Foo() {
+ *mDeleted = true;
+ }
+private:
+ bool* mDeleted;
+};
+
+TEST(RefBase, StrongMoves) {
+ bool isDeleted;
+ Foo* foo = new Foo(&isDeleted);
+ ASSERT_EQ(INITIAL_STRONG_VALUE, foo->getStrongCount());
+ ASSERT_FALSE(isDeleted) << "Already deleted...?";
+ sp<Foo> sp1(foo);
+ wp<Foo> wp1(sp1);
+ ASSERT_EQ(1, foo->getStrongCount());
+ // Weak count includes both strong and weak references.
+ ASSERT_EQ(2, foo->getWeakRefs()->getWeakCount());
+ {
+ sp<Foo> sp2 = std::move(sp1);
+ ASSERT_EQ(1, foo->getStrongCount())
+ << "std::move failed, incremented refcnt";
+ ASSERT_EQ(nullptr, sp1.get()) << "std::move failed, sp1 is still valid";
+ // The strong count isn't increasing, let's double check the old object
+ // is properly reset and doesn't early delete
+ sp1 = std::move(sp2);
+ }
+ ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
+ {
+ // Now let's double check it deletes on time
+ sp<Foo> sp2 = std::move(sp1);
+ }
+ ASSERT_TRUE(isDeleted) << "foo was leaked!";
+ ASSERT_TRUE(wp1.promote().get() == nullptr);
+}
+
+TEST(RefBase, WeakCopies) {
+ bool isDeleted;
+ Foo* foo = new Foo(&isDeleted);
+ EXPECT_EQ(0, foo->getWeakRefs()->getWeakCount());
+ ASSERT_FALSE(isDeleted) << "Foo (weak) already deleted...?";
+ wp<Foo> wp1(foo);
+ EXPECT_EQ(1, foo->getWeakRefs()->getWeakCount());
+ {
+ wp<Foo> wp2 = wp1;
+ ASSERT_EQ(2, foo->getWeakRefs()->getWeakCount());
+ }
+ EXPECT_EQ(1, foo->getWeakRefs()->getWeakCount());
+ ASSERT_FALSE(isDeleted) << "deleted too early! still has a reference!";
+ wp1 = nullptr;
+ ASSERT_TRUE(isDeleted) << "foo2 was leaked!";
+}
+
+
+// Set up a situation in which we race with visit2AndRremove() to delete
+// 2 strong references. Bar destructor checks that there are no early
+// deletions and prior updates are visible to destructor.
+class Bar : public RefBase {
+public:
+ Bar(std::atomic<int>* delete_count) : mVisited1(false), mVisited2(false),
+ mDeleteCount(delete_count) {
+ }
+
+ ~Bar() {
+ EXPECT_TRUE(mVisited1);
+ EXPECT_TRUE(mVisited2);
+ (*mDeleteCount)++;
+ }
+ bool mVisited1;
+ bool mVisited2;
+private:
+ std::atomic<int>* mDeleteCount;
+};
+
+static sp<Bar> buffer;
+static std::atomic<bool> bufferFull(false);
+
+// Wait until bufferFull has value val.
+static inline void waitFor(bool val) {
+ while (bufferFull != val) {}
+}
+
+cpu_set_t otherCpus;
+
+static void visit2AndRemove() {
+ EXPECT_TRUE(CPU_ISSET(1, &otherCpus));
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &otherCpus) != 0) {
+ FAIL() << "setaffinity returned:" << errno;
+ }
+ for (int i = 0; i < NITERS; ++i) {
+ waitFor(true);
+ buffer->mVisited2 = true;
+ buffer = nullptr;
+ bufferFull = false;
+ }
+}
+
+TEST(RefBase, RacingDestructors) {
+ cpu_set_t origCpus;
+ cpu_set_t myCpus;
+ // Restrict us and the helper thread to disjoint cpu sets.
+ // This prevents us from getting scheduled against each other,
+ // which would be atrociously slow. We fail if that's impossible.
+ if (sched_getaffinity(0, sizeof(cpu_set_t), &origCpus) != 0) {
+ FAIL();
+ }
+ EXPECT_TRUE(CPU_ISSET(0, &origCpus));
+ if (CPU_ISSET(1, &origCpus)) {
+ CPU_ZERO(&myCpus);
+ CPU_ZERO(&otherCpus);
+ CPU_OR(&myCpus, &myCpus, &origCpus);
+ CPU_OR(&otherCpus, &otherCpus, &origCpus);
+ for (unsigned i = 0; i < CPU_SETSIZE; ++i) {
+ // I get the even cores, the other thread gets the odd ones.
+ if (i & 1) {
+ CPU_CLR(i, &myCpus);
+ } else {
+ CPU_CLR(i, &otherCpus);
+ }
+ }
+ std::thread t(visit2AndRemove);
+ std::atomic<int> deleteCount(0);
+ EXPECT_TRUE(CPU_ISSET(0, &myCpus));
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &myCpus) != 0) {
+ FAIL() << "setaffinity returned:" << errno;
+ }
+ for (int i = 0; i < NITERS; ++i) {
+ waitFor(false);
+ Bar* bar = new Bar(&deleteCount);
+ sp<Bar> sp3(bar);
+ buffer = sp3;
+ bufferFull = true;
+ ASSERT_TRUE(bar->getStrongCount() >= 1);
+ // Weak count includes strong count.
+ ASSERT_TRUE(bar->getWeakRefs()->getWeakCount() >= 1);
+ sp3->mVisited1 = true;
+ sp3 = nullptr;
+ }
+ t.join();
+ if (sched_setaffinity(0, sizeof(cpu_set_t), &origCpus) != 0) {
+ FAIL();
+ }
+ ASSERT_EQ(NITERS, deleteCount) << "Deletions missed!";
+ } // Otherwise this is slow and probably pointless on a uniprocessor.
+}
diff --git a/libutils/tests/StrongPointer_test.cpp b/libutils/tests/StrongPointer_test.cpp
index f46d6d1..323a6f2 100644
--- a/libutils/tests/StrongPointer_test.cpp
+++ b/libutils/tests/StrongPointer_test.cpp
@@ -23,7 +23,7 @@
class Foo : public LightRefBase<Foo> {
public:
- Foo(bool* deleted_check) : mDeleted(deleted_check) {
+ explicit Foo(bool* deleted_check) : mDeleted(deleted_check) {
*mDeleted = false;
}
diff --git a/libutils/tests/SystemClock_test.cpp b/libutils/tests/SystemClock_test.cpp
new file mode 100644
index 0000000..5ad060b
--- /dev/null
+++ b/libutils/tests/SystemClock_test.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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 <unistd.h>
+#include <utils/SystemClock.h>
+
+#include <gtest/gtest.h>
+
+static const auto MS_IN_NS = 1000000;
+
+static const int64_t SLEEP_MS = 500;
+static const int64_t SLEEP_NS = SLEEP_MS * MS_IN_NS;
+// Conservatively assume that we might be descheduled for up to 50 ms
+static const int64_t SLACK_MS = 50;
+static const int64_t SLACK_NS = SLACK_MS * MS_IN_NS;
+
+TEST(SystemClock, SystemClock) {
+ auto startUptimeMs = android::uptimeMillis();
+ auto startRealtimeMs = android::elapsedRealtime();
+ auto startRealtimeNs = android::elapsedRealtimeNano();
+
+ ASSERT_GT(startUptimeMs, 0)
+ << "uptimeMillis() reported an impossible uptime";
+ ASSERT_GE(startRealtimeMs, startUptimeMs)
+ << "elapsedRealtime() thinks we've suspended for negative time";
+ ASSERT_GE(startRealtimeNs, startUptimeMs * MS_IN_NS)
+ << "elapsedRealtimeNano() thinks we've suspended for negative time";
+
+ ASSERT_GE(startRealtimeNs, startRealtimeMs * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+ ASSERT_LT(startRealtimeNs, (startRealtimeMs + SLACK_MS) * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent";
+
+ timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = SLEEP_MS * MS_IN_NS;
+ auto nanosleepErr = TEMP_FAILURE_RETRY(nanosleep(&ts, nullptr));
+ ASSERT_EQ(nanosleepErr, 0) << "nanosleep() failed: " << strerror(errno);
+
+ auto endUptimeMs = android::uptimeMillis();
+ auto endRealtimeMs = android::elapsedRealtime();
+ auto endRealtimeNs = android::elapsedRealtimeNano();
+
+ EXPECT_GE(endUptimeMs - startUptimeMs, SLEEP_MS)
+ << "uptimeMillis() advanced too little after nanosleep()";
+ EXPECT_LT(endUptimeMs - startUptimeMs, SLEEP_MS + SLACK_MS)
+ << "uptimeMillis() advanced too much after nanosleep()";
+ EXPECT_GE(endRealtimeMs - startRealtimeMs, SLEEP_MS)
+ << "elapsedRealtime() advanced too little after nanosleep()";
+ EXPECT_LT(endRealtimeMs - startRealtimeMs, SLEEP_MS + SLACK_MS)
+ << "elapsedRealtime() advanced too much after nanosleep()";
+ EXPECT_GE(endRealtimeNs - startRealtimeNs, SLEEP_NS)
+ << "elapsedRealtimeNano() advanced too little after nanosleep()";
+ EXPECT_LT(endRealtimeNs - startRealtimeNs, SLEEP_NS + SLACK_NS)
+ << "elapsedRealtimeNano() advanced too much after nanosleep()";
+
+ EXPECT_GE(endRealtimeNs, endRealtimeMs * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+ EXPECT_LT(endRealtimeNs, (endRealtimeMs + SLACK_MS) * MS_IN_NS)
+ << "elapsedRealtime() and elapsedRealtimeNano() are inconsistent after nanosleep()";
+}
diff --git a/libutils/tests/TestHelpers.h b/libutils/tests/TestHelpers.h
index d8e985e..6801cd7 100644
--- a/libutils/tests/TestHelpers.h
+++ b/libutils/tests/TestHelpers.h
@@ -60,7 +60,7 @@
int mDelayMillis;
public:
- DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
+ explicit DelayedTask(int delayMillis) : mDelayMillis(delayMillis) { }
protected:
virtual ~DelayedTask() { }
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index d9b32f9..24ecf86 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -89,9 +89,9 @@
vector.add(4);
vector.setCapacity(8);
- ASSERT_EQ(8, vector.capacity());
+ ASSERT_EQ(8U, vector.capacity());
vector.setCapacity(2);
- ASSERT_EQ(8, vector.capacity());
+ ASSERT_EQ(8U, vector.capacity());
}
// NOTE: All of the tests below are useless because of the "TODO" above.
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
new file mode 100644
index 0000000..5ed0fe8
--- /dev/null
+++ b/libziparchive/Android.bp
@@ -0,0 +1,111 @@
+//
+// Copyright (C) 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+ name: "libziparchive_flags",
+ cflags: [
+ // ZLIB_CONST turns on const for input buffers, which is pretty standard.
+ "-DZLIB_CONST",
+ "-Werror",
+ "-Wall",
+ ],
+ cppflags: [
+ "-Wold-style-cast",
+ // Incorrectly warns when C++11 empty brace {} initializer is used.
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
+ "-Wno-missing-field-initializers",
+ ],
+}
+
+cc_defaults {
+ name: "libziparchive_defaults",
+ srcs: [
+ "zip_archive.cc",
+ "zip_archive_stream_entry.cc",
+ "zip_writer.cc",
+ ],
+
+ target: {
+ windows: {
+ cflags: ["-mno-ms-bitfields"],
+
+ enabled: true,
+ },
+ },
+
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+}
+
+
+cc_library {
+ name: "libziparchive",
+ host_supported: true,
+ defaults: ["libziparchive_defaults", "libziparchive_flags"],
+ static_libs: ["libutils"],
+ shared_libs: ["liblog", "libbase"],
+ target: {
+ android: {
+ static_libs: ["libz"],
+ },
+ host: {
+ shared_libs: ["libz-host"],
+ },
+ },
+}
+
+// Also provide libziparchive-host until everything is switched over to using libziparchive
+cc_library {
+ name: "libziparchive-host",
+ host_supported: true,
+ device_supported: false,
+ defaults: ["libziparchive_defaults", "libziparchive_flags"],
+ shared_libs: ["libz-host"],
+ static_libs: ["libutils"],
+}
+
+// Tests.
+cc_test {
+ name: "ziparchive-tests",
+ host_supported: true,
+ defaults: ["libziparchive_flags"],
+
+ srcs: [
+ "entry_name_utils_test.cc",
+ "zip_archive_test.cc",
+ "zip_writer_test.cc",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+
+ static_libs: [
+ "libziparchive",
+ "libz",
+ "libutils",
+ ],
+
+ target: {
+ host: {
+ cppflags: ["-Wno-unnamed-type-template-args"],
+ },
+ windows: {
+ enabled: true,
+ },
+ },
+}
diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk
deleted file mode 100644
index 3cd8b87..0000000
--- a/libziparchive/Android.mk
+++ /dev/null
@@ -1,106 +0,0 @@
-#
-# Copyright (C) 2013 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-libziparchive_source_files := \
- zip_archive.cc \
- zip_archive_stream_entry.cc \
- zip_writer.cc \
-
-libziparchive_test_files := \
- entry_name_utils_test.cc \
- zip_archive_test.cc \
- zip_writer_test.cc \
-
-# ZLIB_CONST turns on const for input buffers, which is pretty standard.
-libziparchive_common_c_flags := \
- -DZLIB_CONST \
- -Werror \
- -Wall \
-
-# Incorrectly warns when C++11 empty brace {} initializer is used.
-# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61489
-libziparchive_common_cpp_flags := \
- -Wold-style-cast \
- -Wno-missing-field-initializers \
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(libziparchive_source_files)
-LOCAL_STATIC_LIBRARIES := libz
-LOCAL_SHARED_LIBRARIES := libutils libbase
-LOCAL_MODULE:= libziparchive
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(libziparchive_source_files)
-LOCAL_STATIC_LIBRARIES := libz libutils libbase
-LOCAL_MODULE:= libziparchive-host
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CFLAGS_windows := -mno-ms-bitfields
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := $(libziparchive_source_files)
-LOCAL_STATIC_LIBRARIES := libutils
-LOCAL_SHARED_LIBRARIES := libz-host liblog libbase
-LOCAL_MODULE:= libziparchive-host
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-LOCAL_MULTILIB := both
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-# Tests.
-include $(CLEAR_VARS)
-LOCAL_MODULE := ziparchive-tests
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := $(libziparchive_common_cpp_flags)
-LOCAL_SRC_FILES := $(libziparchive_test_files)
-LOCAL_SHARED_LIBRARIES := \
- libbase \
- liblog \
-
-LOCAL_STATIC_LIBRARIES := \
- libziparchive \
- libz \
- libutils \
-
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ziparchive-tests-host
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS := $(libziparchive_common_c_flags)
-LOCAL_CPPFLAGS := -Wno-unnamed-type-template-args $(libziparchive_common_cpp_flags)
-LOCAL_SRC_FILES := $(libziparchive_test_files)
-LOCAL_STATIC_LIBRARIES := \
- libziparchive-host \
- libz \
- libbase \
- libutils \
- liblog \
-
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_NATIVE_TEST)
diff --git a/libziparchive/zip_archive_stream_entry.cc b/libziparchive/zip_archive_stream_entry.cc
index f618835..4b205a7 100644
--- a/libziparchive/zip_archive_stream_entry.cc
+++ b/libziparchive/zip_archive_stream_entry.cc
@@ -48,7 +48,8 @@
class ZipArchiveStreamEntryUncompressed : public ZipArchiveStreamEntry {
public:
- ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
+ explicit ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle)
+ : ZipArchiveStreamEntry(handle) {}
virtual ~ZipArchiveStreamEntryUncompressed() {}
const std::vector<uint8_t>* Read() override;
@@ -110,7 +111,8 @@
class ZipArchiveStreamEntryCompressed : public ZipArchiveStreamEntry {
public:
- ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
+ explicit ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle)
+ : ZipArchiveStreamEntry(handle) {}
virtual ~ZipArchiveStreamEntryCompressed();
const std::vector<uint8_t>* Read() override;
@@ -249,7 +251,7 @@
class ZipArchiveStreamEntryRawCompressed : public ZipArchiveStreamEntryUncompressed {
public:
- ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
+ explicit ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
: ZipArchiveStreamEntryUncompressed(handle) {}
virtual ~ZipArchiveStreamEntryRawCompressed() {}
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index afc81ed..e404e44 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -109,7 +109,7 @@
static struct proc *pidhash[PIDHASH_SZ];
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
-#define ADJTOSLOT(adj) (adj + -OOM_SCORE_ADJ_MIN)
+#define ADJTOSLOT(adj) ((adj) + -OOM_SCORE_ADJ_MIN)
static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
/*
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 33f22dd..5bac717 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -35,7 +35,7 @@
#include <log/logd.h>
#include <log/logger.h>
#include <log/logprint.h>
-#include <utils/threads.h>
+#include <system/thread_defs.h>
#include <pcrecpp.h>
@@ -285,9 +285,10 @@
" -n <count>, --rotate-count=<count>\n"
" Sets max number of rotated logs to <count>, default 4\n"
" -v <format>, --format=<format>\n"
- " Sets the log print format, where <format> is:\n"
- " brief color epoch long monotonic printable process raw\n"
- " tag thread threadtime time uid usec UTC year zone\n"
+ " Sets log print format verb and adverbs, where <format> is:\n"
+ " brief long process raw tag thread threadtime time\n"
+ " and individually flagged modifying adverbs can be added:\n"
+ " color epoch monotonic printable uid usec UTC year zone\n"
" -D, --dividers Print dividers between each log buffer\n"
" -c, --clear Clear (flush) the entire log and exit\n"
" if Log to File specified, clear fileset instead\n"
@@ -392,7 +393,7 @@
}
/*String to unsigned int, returns -1 if it fails*/
-static bool getSizeTArg(char *ptr, size_t *val, size_t min = 0,
+static bool getSizeTArg(const char *ptr, size_t *val, size_t min = 0,
size_t max = SIZE_MAX)
{
if (!ptr) {
diff --git a/logcat/logpersist b/logcat/logpersist
index a0e27ce..f0e7d42 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -1,8 +1,8 @@
#! /system/bin/sh
# logpersist cat, start and stop handlers
progname="${0##*/}"
-case `getprop ro.build.type` in
-userdebug|eng) ;;
+case `getprop ro.debuggable` in
+1) ;;
*) echo "${progname} - Permission denied"
exit 1
;;
@@ -17,6 +17,7 @@
;;
esac
+log_tag_property=persist.log.tag
data=/data/misc/logd
service=logcatd
size_default=256
@@ -36,7 +37,7 @@
-b|--buffer) buffer="${2}" ; shift ;;
-h|--help|*)
LEAD_SPACE_="`echo ${progname%.*} | tr '[ -~]' ' '`"
- echo "${progname%.*}.cat - dump current ${service%d} logs"
+ echo "${progname%.*}.cat - dump current ${service} logs"
echo "${progname%.*}.start [--size=<size_in_kb>] [--buffer=<buffers>] [--clear]"
echo "${LEAD_SPACE_} - start ${service} service"
echo "${progname%.*}.stop [--clear] - stop ${service} service"
@@ -65,6 +66,9 @@
exit 1
fi
+log_tag="`getprop ${log_tag_property}`"
+logd_logpersistd="`getprop ${property}`"
+
case ${progname} in
*.cat)
if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
@@ -123,13 +127,19 @@
while [ "clear" = "`getprop ${property#persist.}`" ]; do
continue
done
+ # Tell Settings that we are back on again if we turned logging off
+ tag="${log_tag#Settings}"
+ if [ X"${log_tag}" != X"${tag}" ]; then
+ echo "WARNING: enabling logd service" >&2
+ setprop ${log_tag_property} "${tag#,}"
+ fi
# ${service}.rc does the heavy lifting with the following trigger
setprop ${property} ${service}
# 20ms done, to permit process feedback check
sleep 1
getprop ${property#persist.}
- # also generate an error return code if not found running, bonus
- ps -t | grep "${data##*/}.*${service%d}"
+ # also generate an error return code if not found running
+ pgrep -u ${data##*/} ${service%d}
;;
*.stop)
if [ -n "${size}${buffer}" ]; then
@@ -158,3 +168,9 @@
echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
exit 1
esac
+
+if [ X"${log_tag}" != X"`getprop ${log_tag_property}`" ] ||
+ [ X"${logd_logpersistd}" != X"`getprop ${property}`" ]; then
+ echo "WARNING: killing Settings" >&2
+ am force-stop com.android.settings
+fi
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
index be815be..dd85164 100644
--- a/logcat/tests/logcat_benchmark.cpp
+++ b/logcat/tests/logcat_benchmark.cpp
@@ -49,7 +49,7 @@
}
}
- timestamp(const char *buffer)
+ explicit timestamp(const char *buffer)
{
init(buffer);
}
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index d79fc08..0043d1b 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -23,6 +23,8 @@
#include <sys/types.h>
#include <sys/wait.h>
+#include <memory>
+
#include <gtest/gtest.h>
#include <log/log.h>
#include <log/logger.h>
@@ -724,8 +726,8 @@
EXPECT_FALSE(system(command));
return;
}
- DIR *dir;
- EXPECT_TRUE(NULL != (dir = opendir(tmp_out_dir)));
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+ EXPECT_NE(nullptr, dir);
if (!dir) {
snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
EXPECT_FALSE(system(command));
@@ -733,7 +735,7 @@
}
struct dirent *entry;
unsigned count = 0;
- while ((entry = readdir(dir))) {
+ while ((entry = readdir(dir.get()))) {
if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
continue;
}
@@ -756,7 +758,6 @@
free(line);
unlink(command);
}
- closedir(dir);
if (count > 1) {
char *brk = strpbrk(second_last_line, "\r\n");
if (!brk) {
@@ -876,12 +877,14 @@
ASSERT_TRUE(NULL != (fp = popen(
"( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
" logcat -b events -c 2>&1 ;"
+ " logcat -b events -g 2>&1 ;"
" logcat -v brief -b events 2>&1",
"r")));
char buffer[BIG_BUFFER];
int count = 0;
+ int minus_g = 0;
int signals = 0;
@@ -899,6 +902,50 @@
break;
}
+ int size, consumed, max, payload;
+ char size_mult[3], consumed_mult[3];
+ size = consumed = max = payload = 0;
+ if (6 == sscanf(buffer, "events: ring buffer is %d%2s (%d%2s consumed),"
+ " max entry is %db, max payload is %db",
+ &size, size_mult, &consumed, consumed_mult,
+ &max, &payload)) {
+ long full_size = size, full_consumed = consumed;
+
+ switch(size_mult[0]) {
+ case 'G':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_size *= 1024;
+ /* FALLTHRU */
+ case 'b':
+ break;
+ }
+ switch(consumed_mult[0]) {
+ case 'G':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'M':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'K':
+ full_consumed *= 1024;
+ /* FALLTHRU */
+ case 'b':
+ break;
+ }
+ EXPECT_GT(full_size, full_consumed);
+ EXPECT_GT(full_size, max);
+ EXPECT_GT(max, payload);
+ EXPECT_GT(max, full_consumed);
+
+ ++minus_g;
+ continue;
+ }
+
++count;
int p;
@@ -927,6 +974,7 @@
pclose(fp);
EXPECT_LE(1, count);
+ EXPECT_EQ(1, minus_g);
EXPECT_EQ(1, signals);
}
diff --git a/logd/Android.mk b/logd/Android.mk
index feca8d5..81637d2 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -28,7 +28,8 @@
liblog \
libcutils \
libbase \
- libpackagelistparser
+ libpackagelistparser \
+ libminijail
# This is what we want to do:
# event_logtags = $(shell \
@@ -38,7 +39,7 @@
# event_flag := $(call event_logtags,auditd)
# event_flag += $(call event_logtags,logd)
# so make sure we do not regret hard-coding it as follows:
-event_flag := -DAUDITD_LOG_TAG=1003 -DLOGD_LOG_TAG=1004
+event_flag := -DAUDITD_LOG_TAG=1003 -DCHATTY_LOG_TAG=1004
LOCAL_CFLAGS := -Werror $(event_flag)
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
index 3877675..cbcd601 100644
--- a/logd/CommandListener.h
+++ b/logd/CommandListener.h
@@ -49,7 +49,7 @@
class name##Cmd : public LogCommand { \
LogBuffer &mBuf; \
public: \
- name##Cmd(LogBuffer *buf); \
+ explicit name##Cmd(LogBuffer *buf); \
virtual ~name##Cmd() {} \
int runCommand(SocketClient *c, int argc, char ** argv); \
};
diff --git a/logd/FlushCommand.h b/logd/FlushCommand.h
index 9224773..7172d5f 100644
--- a/logd/FlushCommand.h
+++ b/logd/FlushCommand.h
@@ -35,7 +35,7 @@
uint64_t mTimeout;
public:
- FlushCommand(LogReader &mReader,
+ explicit FlushCommand(LogReader &mReader,
bool nonBlock = false,
unsigned long tail = -1,
unsigned int logMask = -1,
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 24c3f52..cc140b0 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -102,16 +102,72 @@
struct iovec iov[3];
static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
+ static const char newline[] = "\n";
- iov[0].iov_base = info ? const_cast<char *>(log_info)
- : const_cast<char *>(log_warning);
- iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
- iov[1].iov_base = str;
- iov[1].iov_len = strlen(str);
- iov[2].iov_base = const_cast<char *>("\n");
- iov[2].iov_len = 1;
+ // Dedupe messages, checking for identical messages starting with avc:
+ static unsigned count;
+ static char *last_str;
+ static bool last_info;
- writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+ if (last_str != NULL) {
+ static const char avc[] = "): avc: ";
+ char *avcl = strstr(last_str, avc);
+ bool skip = false;
+
+ if (avcl) {
+ char *avcr = strstr(str, avc);
+
+ skip = avcr && !strcmp(avcl + strlen(avc), avcr + strlen(avc));
+ if (skip) {
+ ++count;
+ free(last_str);
+ last_str = strdup(str);
+ last_info = info;
+ }
+ }
+ if (!skip) {
+ static const char resume[] = " duplicate messages suppressed\n";
+
+ iov[0].iov_base = last_info ?
+ const_cast<char *>(log_info) :
+ const_cast<char *>(log_warning);
+ iov[0].iov_len = last_info ?
+ sizeof(log_info) :
+ sizeof(log_warning);
+ iov[1].iov_base = last_str;
+ iov[1].iov_len = strlen(last_str);
+ if (count > 1) {
+ iov[2].iov_base = const_cast<char *>(resume);
+ iov[2].iov_len = strlen(resume);
+ } else {
+ iov[2].iov_base = const_cast<char *>(newline);
+ iov[2].iov_len = strlen(newline);
+ }
+
+ writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+ free(last_str);
+ last_str = NULL;
+ }
+ }
+ if (last_str == NULL) {
+ count = 0;
+ last_str = strdup(str);
+ last_info = info;
+ }
+ if (count == 0) {
+ iov[0].iov_base = info ?
+ const_cast<char *>(log_info) :
+ const_cast<char *>(log_warning);
+ iov[0].iov_len = info ?
+ sizeof(log_info) :
+ sizeof(log_warning);
+ iov[1].iov_base = str;
+ iov[1].iov_len = strlen(str);
+ iov[2].iov_base = const_cast<char *>(newline);
+ iov[2].iov_len = strlen(newline);
+
+ writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+ }
}
pid_t pid = getpid();
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 8c30f79..fa95733 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -313,16 +313,16 @@
LogBufferElement *element = *it;
log_id_t id = element->getLogId();
- { // start of scope for uid found iterator
- LogBufferIteratorMap::iterator found =
- mLastWorstUid[id].find(element->getUid());
- if ((found != mLastWorstUid[id].end())
- && (it == found->second)) {
- mLastWorstUid[id].erase(found);
+ { // start of scope for found iterator
+ int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+ element->getTag() : element->getUid();
+ LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
+ if ((found != mLastWorst[id].end()) && (it == found->second)) {
+ mLastWorst[id].erase(found);
}
}
- if (element->getUid() == AID_SYSTEM) {
+ if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (element->getUid() == AID_SYSTEM)) {
// start of scope for pid found iterator
LogBufferPidIteratorMap::iterator found =
mLastWorstPidOfSystem[id].find(element->getPid());
@@ -380,7 +380,7 @@
tid(tid),
padding(0) {
}
- LogBufferElementKey(uint64_t key):value(key) { }
+ explicit LogBufferElementKey(uint64_t key):value(key) { }
uint64_t getKey() { return value; }
};
@@ -544,48 +544,31 @@
bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
while (!clearAll && (pruneRows > 0)) {
// recalculate the worst offender on every batched pass
- uid_t worst = (uid_t) -1;
+ int worst = -1; // not valid for getUid() or getKey()
size_t worst_sizes = 0;
size_t second_worst_sizes = 0;
pid_t worstPid = 0; // POSIX guarantees PID != 0
if (worstUidEnabledForLogid(id) && mPrune.worstUidEnabled()) {
- { // begin scope for UID sorted list
- std::unique_ptr<const UidEntry *[]> sorted = stats.sort(
- AID_ROOT, (pid_t)0, 2, id);
+ // Calculate threshold as 12.5% of available storage
+ size_t threshold = log_buffer_size(id) / 8;
- if (sorted.get() && sorted[0] && sorted[1]) {
- worst_sizes = sorted[0]->getSizes();
- // Calculate threshold as 12.5% of available storage
- size_t threshold = log_buffer_size(id) / 8;
- if ((worst_sizes > threshold)
- // Allow time horizon to extend roughly tenfold, assume
- // average entry length is 100 characters.
- && (worst_sizes > (10 * sorted[0]->getDropped()))) {
- worst = sorted[0]->getKey();
- second_worst_sizes = sorted[1]->getSizes();
- if (second_worst_sizes < threshold) {
- second_worst_sizes = threshold;
- }
- }
- }
- }
+ if ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) {
+ stats.sortTags(AID_ROOT, (pid_t)0, 2, id).findWorst(
+ worst, worst_sizes, second_worst_sizes, threshold);
+ } else {
+ stats.sort(AID_ROOT, (pid_t)0, 2, id).findWorst(
+ worst, worst_sizes, second_worst_sizes, threshold);
- if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
- // begin scope of PID sorted list
- std::unique_ptr<const PidEntry *[]> sorted = stats.sort(
- worst, (pid_t)0, 2, id, worst);
- if (sorted.get() && sorted[0] && sorted[1]) {
- worstPid = sorted[0]->getKey();
- second_worst_sizes = worst_sizes
- - sorted[0]->getSizes()
- + sorted[1]->getSizes();
+ if ((worst == AID_SYSTEM) && mPrune.worstPidOfSystemEnabled()) {
+ stats.sortPids(worst, (pid_t)0, 2, id).findWorst(
+ worstPid, worst_sizes, second_worst_sizes);
}
}
}
// skip if we have neither worst nor naughty filters
- if ((worst == (uid_t) -1) && !hasBlacklist) {
+ if ((worst == -1) && !hasBlacklist) {
break;
}
@@ -597,10 +580,10 @@
// - coalesce chatty tags
// - check age-out of preserved logs
bool gc = pruneRows <= 1;
- if (!gc && (worst != (uid_t) -1)) {
- { // begin scope for uid worst found iterator
- LogBufferIteratorMap::iterator found = mLastWorstUid[id].find(worst);
- if ((found != mLastWorstUid[id].end())
+ if (!gc && (worst != -1)) {
+ { // begin scope for worst found iterator
+ LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
+ if ((found != mLastWorst[id].end())
&& (found->second != mLogElements.end())) {
leading = false;
it = found->second;
@@ -658,6 +641,10 @@
continue;
}
+ int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+ element->getTag() :
+ element->getUid();
+
if (hasBlacklist && mPrune.naughty(element)) {
last.clear(element);
it = erase(it);
@@ -670,7 +657,7 @@
break;
}
- if (element->getUid() == worst) {
+ if (key == worst) {
kick = true;
if (worst_sizes < second_worst_sizes) {
break;
@@ -689,20 +676,19 @@
last.add(element);
if (worstPid
&& ((!gc && (element->getPid() == worstPid))
- || (mLastWorstPidOfSystem[id].find(element->getPid())
+ || (mLastWorstPidOfSystem[id].find(element->getPid())
== mLastWorstPidOfSystem[id].end()))) {
- mLastWorstPidOfSystem[id][element->getUid()] = it;
+ mLastWorstPidOfSystem[id][key] = it;
}
- if ((!gc && !worstPid && (element->getUid() == worst))
- || (mLastWorstUid[id].find(element->getUid())
- == mLastWorstUid[id].end())) {
- mLastWorstUid[id][element->getUid()] = it;
+ if ((!gc && !worstPid && (key == worst))
+ || (mLastWorst[id].find(key) == mLastWorst[id].end())) {
+ mLastWorst[id][key] = it;
}
++it;
continue;
}
- if ((element->getUid() != worst)
+ if ((key != worst)
|| (worstPid && (element->getPid() != worstPid))) {
leading = false;
last.clear(element);
@@ -734,9 +720,9 @@
== mLastWorstPidOfSystem[id].end()))) {
mLastWorstPidOfSystem[id][worstPid] = it;
}
- if ((!gc && !worstPid) || (mLastWorstUid[id].find(worst)
- == mLastWorstUid[id].end())) {
- mLastWorstUid[id][worst] = it;
+ if ((!gc && !worstPid) ||
+ (mLastWorst[id].find(worst) == mLastWorst[id].end())) {
+ mLastWorst[id][worst] = it;
}
++it;
}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 7e99236..162c189 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -89,7 +89,7 @@
typedef std::unordered_map<uid_t,
LogBufferElementCollection::iterator>
LogBufferIteratorMap;
- LogBufferIteratorMap mLastWorstUid[LOG_ID_MAX];
+ LogBufferIteratorMap mLastWorst[LOG_ID_MAX];
// watermark of any worst/chatty pid of system processing
typedef std::unordered_map<pid_t,
LogBufferElementCollection::iterator>
@@ -103,7 +103,7 @@
public:
LastLogTimes &mTimes;
- LogBuffer(LastLogTimes *times);
+ explicit LogBuffer(LastLogTimes *times);
void init();
bool isMonotonic() { return monotonic; }
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index eb5194c..3e6e586 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -181,7 +181,7 @@
android_log_event_string_t *event =
reinterpret_cast<android_log_event_string_t *>(buffer);
- event->header.tag = htole32(LOGD_LOG_TAG);
+ event->header.tag = htole32(CHATTY_LOG_TAG);
event->type = EVENT_TYPE_STRING;
event->length = htole32(len);
} else {
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
index c944478..0adc2a1 100644
--- a/logd/LogCommand.h
+++ b/logd/LogCommand.h
@@ -22,7 +22,7 @@
class LogCommand : public FrameworkCommand {
public:
- LogCommand(const char *cmd);
+ explicit LogCommand(const char *cmd);
virtual ~LogCommand() {}
};
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 39dd227..61b7fd8 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -48,7 +48,7 @@
+ LOGGER_ENTRY_MAX_PAYLOAD];
struct iovec iov = { buffer, sizeof(buffer) };
- char control[CMSG_SPACE(sizeof(struct ucred))] __aligned(4);
+ alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
NULL,
0,
diff --git a/logd/LogReader.h b/logd/LogReader.h
index 98674b8..fdcedf1 100644
--- a/logd/LogReader.h
+++ b/logd/LogReader.h
@@ -27,7 +27,7 @@
LogBuffer &mLogbuf;
public:
- LogReader(LogBuffer *logbuf);
+ explicit LogReader(LogBuffer *logbuf);
void notifyNewLog();
LogBuffer &logbuf(void) const { return mLogbuf; }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 2b02bc1..86d33b2 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -15,8 +15,10 @@
*/
#include <fcntl.h>
+#include <pwd.h>
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
#include <unistd.h>
#include <log/logger.h>
@@ -150,6 +152,15 @@
pidTable.drop(element->getPid(), element);
tidTable.drop(element->getTid(), element);
+
+ uint32_t tag = element->getTag();
+ if (tag) {
+ if (log_id == LOG_ID_SECURITY) {
+ securityTagTable.drop(tag, element);
+ } else {
+ tagTable.drop(tag, element);
+ }
+ }
}
// caller must own and free character string
@@ -159,14 +170,13 @@
return strdup("auditd");
}
- // Android hard coded
- const struct android_id_info *info = android_ids;
-
- for (size_t i = 0; i < android_id_count; ++i) {
- if (info->aid == uid) {
- return strdup(info->name);
+ // Android system
+ if (uid < AID_APP) {
+ // in bionic, thread safe as long as we copy the results
+ struct passwd *pwd = getpwuid(uid);
+ if (pwd) {
+ return strdup(pwd->pw_name);
}
- ++info;
}
// Parse /data/system/packages.list
@@ -179,6 +189,14 @@
return name;
}
+ // Android application
+ if (uid >= AID_APP) {
+ struct passwd *pwd = getpwuid(uid);
+ if (pwd) {
+ return strdup(pwd->pw_name);
+ }
+ }
+
// report uid -> pid(s) -> pidToName if unique
for(pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
const PidEntry &entry = it->second;
@@ -275,7 +293,7 @@
if ((spaces <= 0) && pruned.length()) {
spaces = 1;
}
- if (spaces > 0) {
+ if ((spaces > 0) && (pruned.length() != 0)) {
change += android::base::StringPrintf("%*s", (int)spaces, "");
}
pruned = change + pruned;
@@ -429,6 +447,10 @@
getSizes());
std::string pruned = "";
+ size_t dropped = getDropped();
+ if (dropped) {
+ pruned = android::base::StringPrintf("%zu", dropped);
+ }
return formatLine(name, size, pruned);
}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 6f7d264..878c333 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -33,7 +33,7 @@
#include "LogUtils.h"
#define log_id_for_each(i) \
- for (log_id_t i = LOG_ID_MIN; i < LOG_ID_MAX; i = (log_id_t) (i + 1))
+ for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t) ((i) + 1))
class LogStatistics;
@@ -166,7 +166,7 @@
size_t size;
EntryBase():size(0) { }
- EntryBase(LogBufferElement *element):size(element->getMsgLen()) { }
+ explicit EntryBase(LogBufferElement *element):size(element->getMsgLen()) { }
size_t getSizes() const { return size; }
@@ -201,9 +201,9 @@
size_t dropped;
EntryBaseDropped():dropped(0) { }
- EntryBaseDropped(LogBufferElement *element):
+ explicit EntryBaseDropped(LogBufferElement *element):
EntryBase(element),
- dropped(element->getDropped()){
+ dropped(element->getDropped()) {
}
size_t getDropped() const { return dropped; }
@@ -226,7 +226,7 @@
const uid_t uid;
pid_t pid;
- UidEntry(LogBufferElement *element):
+ explicit UidEntry(LogBufferElement *element):
EntryBaseDropped(element),
uid(element->getUid()),
pid(element->getPid()) {
@@ -256,13 +256,13 @@
uid_t uid;
char *name;
- PidEntry(pid_t pid):
+ explicit PidEntry(pid_t pid):
EntryBaseDropped(),
pid(pid),
uid(android::pidToUid(pid)),
name(android::pidToName(pid)) {
}
- PidEntry(LogBufferElement *element):
+ explicit PidEntry(LogBufferElement *element):
EntryBaseDropped(element),
pid(element->getPid()),
uid(element->getUid()),
@@ -320,7 +320,7 @@
uid(android::pidToUid(tid)),
name(android::tidToName(tid)) {
}
- TidEntry(LogBufferElement *element):
+ explicit TidEntry(LogBufferElement *element):
EntryBaseDropped(element),
tid(element->getTid()),
pid(element->getPid()),
@@ -370,13 +370,13 @@
std::string format(const LogStatistics &stat, log_id_t id) const;
};
-struct TagEntry : public EntryBase {
+struct TagEntry : public EntryBaseDropped {
const uint32_t tag;
pid_t pid;
uid_t uid;
- TagEntry(LogBufferElement *element):
- EntryBase(element),
+ explicit TagEntry(LogBufferElement *element):
+ EntryBaseDropped(element),
tag(element->getTag()),
pid(element->getPid()),
uid(element->getUid()) {
@@ -401,6 +401,43 @@
std::string format(const LogStatistics &stat, log_id_t id) const;
};
+template <typename TEntry>
+class LogFindWorst {
+ std::unique_ptr<const TEntry *[]> sorted;
+
+public:
+
+ explicit LogFindWorst(std::unique_ptr<const TEntry *[]> &&sorted) : sorted(std::move(sorted)) { }
+
+ void findWorst(int &worst,
+ size_t &worst_sizes, size_t &second_worst_sizes,
+ size_t threshold) {
+ if (sorted.get() && sorted[0] && sorted[1]) {
+ worst_sizes = sorted[0]->getSizes();
+ if ((worst_sizes > threshold)
+ // Allow time horizon to extend roughly tenfold, assume
+ // average entry length is 100 characters.
+ && (worst_sizes > (10 * sorted[0]->getDropped()))) {
+ worst = sorted[0]->getKey();
+ second_worst_sizes = sorted[1]->getSizes();
+ if (second_worst_sizes < threshold) {
+ second_worst_sizes = threshold;
+ }
+ }
+ }
+ }
+
+ void findWorst(int &worst,
+ size_t worst_sizes, size_t &second_worst_sizes) {
+ if (sorted.get() && sorted[0] && sorted[1]) {
+ worst = sorted[0]->getKey();
+ second_worst_sizes = worst_sizes
+ - sorted[0]->getSizes()
+ + sorted[1]->getSizes();
+ }
+ }
+};
+
// Log Statistics
class LogStatistics {
friend UidEntry;
@@ -451,13 +488,14 @@
--mDroppedElements[log_id];
}
- std::unique_ptr<const UidEntry *[]> sort(uid_t uid, pid_t pid,
- size_t len, log_id id) {
- return uidTable[id].sort(uid, pid, len);
+ LogFindWorst<UidEntry> sort(uid_t uid, pid_t pid, size_t len, log_id id) {
+ return LogFindWorst<UidEntry>(uidTable[id].sort(uid, pid, len));
}
- std::unique_ptr<const PidEntry *[]> sort(uid_t uid, pid_t pid,
- size_t len, log_id id, uid_t) {
- return pidSystemTable[id].sort(uid, pid, len);
+ LogFindWorst<PidEntry> sortPids(uid_t uid, pid_t pid, size_t len, log_id id) {
+ return LogFindWorst<PidEntry>(pidSystemTable[id].sort(uid, pid, len));
+ }
+ LogFindWorst<TagEntry> sortTags(uid_t uid, pid_t pid, size_t len, log_id) {
+ return LogFindWorst<TagEntry>(tagTable.sort(uid, pid, len));
}
// fast track current value by id only
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index fd4800e..fc66330 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -17,6 +17,7 @@
#ifndef _LOGD_LOG_UTILS_H__
#define _LOGD_LOG_UTILS_H__
+#include <sys/cdefs.h>
#include <sys/types.h>
#include <log/log.h>
@@ -29,6 +30,7 @@
// Furnished in main.cpp. Caller must own and free returned value
char *uidToName(uid_t uid);
+void prdebug(const char *fmt, ...) __printflike(1, 2);
// Furnished in LogStatistics.cpp. Caller must own and free returned value
char *pidToName(pid_t pid);
@@ -54,7 +56,8 @@
bool property_get_bool(const char *key, int def);
static inline bool worstUidEnabledForLogid(log_id_t id) {
- return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) || (id == LOG_ID_RADIO);
+ return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
+ (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
}
template <int (*cmp)(const char *l, const char *r, const size_t s)>
diff --git a/logd/README.property b/logd/README.property
index b2708e4..791b1d5 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -8,7 +8,7 @@
ro.device_owner bool false Override persist.logd.security to false
ro.logd.kernel bool+ svelte+ Enable klogd daemon
ro.logd.statistics bool+ svelte+ Enable logcat -S statistics.
-ro.build.type string if user, logd.statistics &
+ro.debuggable number if not "1", logd.statistics &
ro.logd.kernel default false.
logd.logpersistd.enable bool auto Safe to start logpersist daemon service
logd.logpersistd string persist Enable logpersist daemon, "logcatd"
@@ -55,10 +55,10 @@
NB:
- auto - managed by /init
- bool+ - "true", "false" and comma separated list of "eng" (forced false if
- ro.build.type is "user") or "svelte" (forced false if ro.config.low_ram is
+ ro.debuggable is not "1") or "svelte" (forced false if ro.config.low_ram is
true).
- svelte - see ro.config.low_ram for details.
-- svelte+ - see ro.config.low_ram and ro.build.type for details.
+- svelte+ - see ro.config.low_ram and ro.debuggable for details.
- ro - <base property> temporary override, ro.<base property> platform default.
- persist - <base property> override, persist.<base property> platform default.
- build - VERBOSE for native, DEBUG for jvm isLoggable, or developer option.
diff --git a/logd/event.logtags b/logd/event.logtags
index db8c19b..0d24df0 100644
--- a/logd/event.logtags
+++ b/logd/event.logtags
@@ -34,4 +34,4 @@
# TODO: generate ".java" and ".h" files with integer constants from this file.
1003 auditd (avc|3)
-1004 logd (dropped|3)
+1004 chatty (dropped|3)
diff --git a/logd/main.cpp b/logd/main.cpp
index 8aa1abb..77a6973 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -36,12 +36,15 @@
#include <cstdbool>
#include <memory>
+#include <android-base/macros.h>
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
+#include <libminijail.h>
#include <log/event_tag_map.h>
#include <packagelistparser/packagelistparser.h>
#include <private/android_filesystem_config.h>
+#include <scoped_minijail.h>
#include <utils/threads.h>
#include "CommandListener.h"
@@ -58,14 +61,14 @@
'>'
//
-// The service is designed to be run by init, it does not respond well
+// The service is designed to be run by init, it does not respond well
// to starting up manually. When starting up manually the sockets will
// fail to open typically for one of the following reasons:
// EADDRINUSE if logger is running.
// EACCESS if started without precautions (below)
//
// Here is a cookbook procedure for starting up logd manually assuming
-// init is out of the way, pedantically all permissions and selinux
+// init is out of the way, pedantically all permissions and SELinux
// security is put back in place:
//
// setenforce 0
@@ -102,43 +105,13 @@
return -1;
}
- if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
- return -1;
- }
-
gid_t groups[] = { AID_READPROC };
-
- if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) {
- return -1;
- }
-
- if (setgid(AID_LOGD) != 0) {
- return -1;
- }
-
- if (setuid(AID_LOGD) != 0) {
- return -1;
- }
-
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- capheader.pid = 0;
-
- capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
- capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |= CAP_TO_MASK(CAP_AUDIT_CONTROL);
-
- capdata[0].effective = capdata[0].permitted;
- capdata[1].effective = capdata[1].permitted;
- capdata[0].inheritable = 0;
- capdata[1].inheritable = 0;
-
- if (capset(&capheader, &capdata[0]) < 0) {
- return -1;
- }
-
+ ScopedMinijail j(minijail_new());
+ minijail_set_supplementary_gids(j.get(), arraysize(groups), groups);
+ minijail_change_uid(j.get(), AID_LOGD);
+ minijail_change_gid(j.get(), AID_LOGD);
+ minijail_use_caps(j.get(), CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_AUDIT_CONTROL));
+ minijail_enter(j.get());
return 0;
}
@@ -202,8 +175,8 @@
return false;
}
if (flag & BOOL_DEFAULT_FLAG_ENG) {
- property_get("ro.build.type", property, "");
- if (!strcmp(property, "user")) {
+ property_get("ro.debuggable", property, "");
+ if (strcmp(property, "1")) {
return false;
}
}
@@ -211,10 +184,32 @@
return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE;
}
-// Remove the static, and use this variable
-// globally for debugging if necessary. eg:
-// write(fdDmesg, "I am here\n", 10);
static int fdDmesg = -1;
+void android::prdebug(const char *fmt, ...) {
+ if (fdDmesg < 0) {
+ return;
+ }
+
+ static const char message[] = {
+ KMSG_PRIORITY(LOG_DEBUG), 'l', 'o', 'g', 'd', ':', ' '
+ };
+ char buffer[256];
+ memcpy(buffer, message, sizeof(message));
+
+ va_list ap;
+ va_start(ap, fmt);
+ int n = vsnprintf(buffer + sizeof(message),
+ sizeof(buffer) - sizeof(message), fmt, ap);
+ va_end(ap);
+ if (n > 0) {
+ buffer[sizeof(buffer) - 1] = '\0';
+ if (!strchr(buffer, '\n')) {
+ buffer[sizeof(buffer) - 2] = '\0';
+ strlcat(buffer, "\n", sizeof(buffer));
+ }
+ write(fdDmesg, buffer, strlen(buffer));
+ }
+}
static sem_t uidName;
static uid_t uid;
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
new file mode 100644
index 0000000..41f0726
--- /dev/null
+++ b/logwrapper/Android.bp
@@ -0,0 +1,36 @@
+
+
+// ========================================================
+// Static and shared library
+// ========================================================
+cc_library {
+ name: "liblogwrap",
+ srcs: ["logwrap.c"],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ export_include_dirs: ["include"],
+ local_include_dirs: ["include"],
+ cflags: [
+ "-Werror",
+ "-std=gnu99",
+ ],
+}
+
+// ========================================================
+// Executable
+// ========================================================
+cc_binary {
+ name: "logwrapper",
+ srcs: ["logwrapper.c"],
+ static_libs: [
+ "liblog",
+ "liblogwrap",
+ "libcutils",
+ ],
+ cflags: [
+ "-Werror",
+ "-std=gnu99",
+ ],
+}
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
deleted file mode 100644
index ad45b2c..0000000
--- a/logwrapper/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# ========================================================
-# Static library
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblogwrap
-LOCAL_SRC_FILES := logwrap.c
-LOCAL_SHARED_LIBRARIES := libcutils liblog
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror -std=gnu99
-include $(BUILD_STATIC_LIBRARY)
-
-# ========================================================
-# Shared library
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblogwrap
-LOCAL_SHARED_LIBRARIES := libcutils liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror -std=gnu99
-include $(BUILD_SHARED_LIBRARY)
-
-# ========================================================
-# Executable
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= logwrapper.c
-LOCAL_MODULE := logwrapper
-LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
-LOCAL_CFLAGS := -Werror -std=gnu99
-include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 28d6de7..ccbe0bf 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -408,7 +408,7 @@
if (poll_fds[0].revents & POLLHUP) {
int ret;
- ret = waitpid(pid, &status, WNOHANG);
+ ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
if (ret < 0) {
rc = errno;
ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
diff --git a/metricsd/.clang-format b/metricsd/.clang-format
deleted file mode 100644
index c98efc2..0000000
--- a/metricsd/.clang-format
+++ /dev/null
@@ -1,10 +0,0 @@
-BasedOnStyle: Google
-AllowShortFunctionsOnASingleLine: Inline
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-BinPackArguments: false
-BinPackParameters: false
-CommentPragmas: NOLINT:.*
-DerivePointerAlignment: false
-PointerAlignment: Left
-TabWidth: 2
diff --git a/metricsd/.clang-format b/metricsd/.clang-format
new file mode 120000
index 0000000..f9066d4
--- /dev/null
+++ b/metricsd/.clang-format
@@ -0,0 +1 @@
+../../../build/tools/brillo-clang-format
\ No newline at end of file
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index bb262b4..65ca1f6 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -199,9 +199,6 @@
LOCAL_SHARED_LIBRARIES := $(metricsd_shared_libraries)
LOCAL_SRC_FILES := $(metricsd_tests_sources) $(metricsd_common)
LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_protos metricsd_binder_proxy
-ifdef BRILLO
-LOCAL_MODULE_TAGS := eng
-endif
include $(BUILD_NATIVE_TEST)
# Unit tests for metrics_collector.
@@ -217,9 +214,6 @@
$(metrics_collector_common)
LOCAL_STATIC_LIBRARIES := libBionicGtestMain libgmock metricsd_binder_proxy \
$(metrics_collector_static_libraries)
-ifdef BRILLO
-LOCAL_MODULE_TAGS := eng
-endif
include $(BUILD_NATIVE_TEST)
# Weave schema files
diff --git a/metricsd/collectors/cpu_usage_collector.h b/metricsd/collectors/cpu_usage_collector.h
index f81dfcb..9f92cf3 100644
--- a/metricsd/collectors/cpu_usage_collector.h
+++ b/metricsd/collectors/cpu_usage_collector.h
@@ -23,7 +23,7 @@
class CpuUsageCollector {
public:
- CpuUsageCollector(MetricsLibraryInterface* metrics_library);
+ explicit CpuUsageCollector(MetricsLibraryInterface* metrics_library);
// Initialize this collector's state.
void Init();
diff --git a/metricsd/collectors/disk_usage_collector.h b/metricsd/collectors/disk_usage_collector.h
index c1d4546..288b34b 100644
--- a/metricsd/collectors/disk_usage_collector.h
+++ b/metricsd/collectors/disk_usage_collector.h
@@ -23,7 +23,7 @@
class DiskUsageCollector {
public:
- DiskUsageCollector(MetricsLibraryInterface* metrics_library);
+ explicit DiskUsageCollector(MetricsLibraryInterface* metrics_library);
// Schedule the next collection.
void Schedule();
diff --git a/metricsd/timer_test.cc b/metricsd/timer_test.cc
index 7a67e11..cfbcd8a 100644
--- a/metricsd/timer_test.cc
+++ b/metricsd/timer_test.cc
@@ -69,7 +69,7 @@
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime))
.WillOnce(Return(etime));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Start());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -88,7 +88,7 @@
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime))
.WillOnce(Return(etime));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
timer_.Start();
base::TimeTicks buffer = timer_.start_time_;
timer_.Start();
@@ -98,7 +98,7 @@
TEST_F(TimerTest, Reset) {
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
timer_.Start();
ASSERT_TRUE(timer_.Reset());
ASSERT_FALSE(timer_.HasStarted());
@@ -110,7 +110,7 @@
.WillOnce(Return(etime))
.WillOnce(Return(stime2))
.WillOnce(Return(etime2));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Start());
ASSERT_TRUE(timer_.Stop());
ASSERT_EQ(timer_.elapsed_time_.InMilliseconds(), kDelta1MSec);
@@ -130,7 +130,7 @@
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime))
.WillOnce(Return(etime));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_FALSE(timer_.Stop());
// Now we try it again, but after a valid start/stop.
timer_.Start();
@@ -152,7 +152,7 @@
.WillOnce(Return(etime2))
.WillOnce(Return(stime3))
.WillOnce(Return(etime3));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Pause()); // Starts timer paused.
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -181,7 +181,7 @@
.WillOnce(Return(stime2))
.WillOnce(Return(etime2))
.WillOnce(Return(stime3));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Resume());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -208,7 +208,7 @@
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime))
.WillOnce(Return(etime));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Start());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -230,7 +230,7 @@
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime))
.WillOnce(Return(etime));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Start());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -257,7 +257,7 @@
.WillOnce(Return(etime))
.WillOnce(Return(stime2))
.WillOnce(Return(etime2));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Start());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -284,7 +284,7 @@
TEST_F(TimerTest, PauseStop) {
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Pause());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -304,7 +304,7 @@
.WillOnce(Return(stime))
.WillOnce(Return(stime2))
.WillOnce(Return(etime2));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Pause());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -328,7 +328,7 @@
.WillOnce(Return(stime2))
.WillOnce(Return(stime3))
.WillOnce(Return(etime3));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Start());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -373,7 +373,7 @@
.WillOnce(Return(etime2))
.WillOnce(Return(stime3))
.WillOnce(Return(etime3));
- timer_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_.clock_wrapper_ = std::move(clock_wrapper_mock_);
ASSERT_TRUE(timer_.Start());
ASSERT_TRUE(timer_.start_time_ == stime);
ASSERT_TRUE(timer_.HasStarted());
@@ -444,7 +444,7 @@
EXPECT_CALL(*clock_wrapper_mock_, GetCurrentTime())
.WillOnce(Return(stime))
.WillOnce(Return(etime));
- timer_reporter_.clock_wrapper_.reset(clock_wrapper_mock_.release());
+ timer_reporter_.clock_wrapper_ = std::move(clock_wrapper_mock_);
EXPECT_CALL(lib_, SendToUMA(kMetricName, kDelta1MSec, kMinSample, kMaxSample,
kNumBuckets)).WillOnce(Return(true));
ASSERT_TRUE(timer_reporter_.Start());
diff --git a/metricsd/uploader/metrics_log_base.cc b/metricsd/uploader/metrics_log_base.cc
index 1a60b4f..f23bd63 100644
--- a/metricsd/uploader/metrics_log_base.cc
+++ b/metricsd/uploader/metrics_log_base.cc
@@ -16,6 +16,8 @@
#include "uploader/metrics_log_base.h"
+#include <memory>
+
#include "base/build_time.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
@@ -125,7 +127,7 @@
histogram_proto->set_name_hash(Hash(histogram_name));
histogram_proto->set_sum(snapshot.sum());
- for (scoped_ptr<SampleCountIterator> it = snapshot.Iterator(); !it->Done();
+ for (std::unique_ptr<SampleCountIterator> it = snapshot.Iterator(); !it->Done();
it->Next()) {
HistogramBase::Sample min;
HistogramBase::Sample max;
diff --git a/metricsd/uploader/metricsd_service_runner.h b/metricsd/uploader/metricsd_service_runner.h
index f5dad21..b36d4a5 100644
--- a/metricsd/uploader/metricsd_service_runner.h
+++ b/metricsd/uploader/metricsd_service_runner.h
@@ -27,7 +27,7 @@
class MetricsdServiceRunner {
public:
- MetricsdServiceRunner(std::shared_ptr<CrashCounters> counters);
+ explicit MetricsdServiceRunner(std::shared_ptr<CrashCounters> counters);
// Start the Metricsd Binder service in a new thread.
void Start();
diff --git a/metricsd/uploader/sender_http.cc b/metricsd/uploader/sender_http.cc
index 4b572a6..1f775df 100644
--- a/metricsd/uploader/sender_http.cc
+++ b/metricsd/uploader/sender_http.cc
@@ -23,7 +23,7 @@
#include <brillo/http/http_utils.h>
#include <brillo/mime_utils.h>
-HttpSender::HttpSender(const std::string server_url)
+HttpSender::HttpSender(const std::string& server_url)
: server_url_(server_url) {}
bool HttpSender::Send(const std::string& content,
diff --git a/metricsd/uploader/sender_http.h b/metricsd/uploader/sender_http.h
index 4f1c08f..0d64c74 100644
--- a/metricsd/uploader/sender_http.h
+++ b/metricsd/uploader/sender_http.h
@@ -26,7 +26,7 @@
// Sender implemented using http_utils from libbrillo
class HttpSender : public Sender {
public:
- explicit HttpSender(std::string server_url);
+ explicit HttpSender(const std::string& server_url);
~HttpSender() override = default;
// Sends |content| whose SHA1 hash is |hash| to server_url with a synchronous
// POST request to server_url.
diff --git a/metricsd/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
index 0dc59a4..333a7e6 100644
--- a/metricsd/uploader/upload_service.cc
+++ b/metricsd/uploader/upload_service.cc
@@ -183,6 +183,7 @@
base::StatisticsRecorder::GetHistograms(&histograms);
histogram_snapshot_manager_.PrepareDeltas(
+ histograms.begin(), histograms.end(),
base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
// Gather and reset the crash counters, shared with the binder threads.
diff --git a/metricsd/uploader/upload_service_test.cc b/metricsd/uploader/upload_service_test.cc
index 70112f4..0f77fe4 100644
--- a/metricsd/uploader/upload_service_test.cc
+++ b/metricsd/uploader/upload_service_test.cc
@@ -304,6 +304,8 @@
upload_service_->PersistToDisk();
EXPECT_EQ(
1, upload_service_->current_log_->uma_proto()->histogram_event().size());
+ // Destroy the old service before creating a new one.
+ upload_service_.reset();
upload_service_.reset(new UploadService(
"", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
upload_service_->InitForTest(nullptr);
@@ -325,6 +327,8 @@
// Write a bogus saved log.
EXPECT_EQ(5, base::WriteFile(upload_service_->saved_log_path_, "hello", 5));
+ // Destroy the old service before creating a new one.
+ upload_service_.reset();
upload_service_.reset(new UploadService(
"", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
diff --git a/reboot/Android.bp b/reboot/Android.bp
new file mode 100644
index 0000000..805fd9a
--- /dev/null
+++ b/reboot/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2013 The Android Open Source Project
+
+cc_binary {
+ name: "reboot",
+ srcs: ["reboot.c"],
+ shared_libs: ["libcutils"],
+ cflags: ["-Werror"],
+}
diff --git a/reboot/Android.mk b/reboot/Android.mk
deleted file mode 100644
index 7a24f99..0000000
--- a/reboot/Android.mk
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := reboot.c
-
-LOCAL_SHARED_LIBRARIES := libcutils
-
-LOCAL_MODULE := reboot
-
-LOCAL_CFLAGS := -Werror
-
-include $(BUILD_EXECUTABLE)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 94f5cb7..aa5a520 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -125,7 +125,7 @@
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
-ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
+ifdef BOARD_USES_VENDORIMAGE
LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor
else
LOCAL_POST_INSTALL_CMD += ; ln -sf /system/vendor $(TARGET_ROOT_OUT)/vendor
diff --git a/rootdir/init-debug.rc b/rootdir/init-debug.rc
index 435d4cb..44d34d8 100644
--- a/rootdir/init-debug.rc
+++ b/rootdir/init-debug.rc
@@ -6,3 +6,6 @@
on property:persist.mmc.cache_size=*
write /sys/block/mmcblk0/cache_size ${persist.mmc.cache_size}
+
+on early-init
+ mount debugfs debugfs /sys/kernel/debug
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 56379db..f276b55 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -431,9 +431,6 @@
rm /data/bugreports
symlink /data/user_de/0/com.android.shell/files/bugreports /data/bugreports
- # Separate location for storing security policy files on data
- mkdir /data/security 0711 system system
-
# Create all remaining /data root dirs so that they are made through init
# and get proper encryption policy installed
mkdir /data/backup 0700 system system
@@ -463,9 +460,6 @@
init_user0
- # Reload policy from /data/security if present.
- setprop selinux.reload_policy 1
-
# Set SELinux security contexts on upgrade or policy update.
restorecon_recursive /data
diff --git a/rootdir/init.usb.configfs.rc b/rootdir/init.usb.configfs.rc
index 186384b..dc875b4 100644
--- a/rootdir/init.usb.configfs.rc
+++ b/rootdir/init.usb.configfs.rc
@@ -1,9 +1,14 @@
on property:sys.usb.config=none && property:sys.usb.configfs=1
write /config/usb_gadget/g1/UDC "none"
stop adbd
+ setprop sys.usb.ffs.ready 0
write /config/usb_gadget/g1/bDeviceClass 0
write /config/usb_gadget/g1/bDeviceSubClass 0
write /config/usb_gadget/g1/bDeviceProtocol 0
+ rm /config/usb_gadget/g1/configs/b.1/f1
+ rm /config/usb_gadget/g1/configs/b.1/f2
+ rm /config/usb_gadget/g1/configs/b.1/f3
+ rmdir /config/usb_gadget/g1/functions/rndis.gs4
setprop sys.usb.state ${sys.usb.config}
on property:sys.usb.config=adb && property:sys.usb.configfs=1
@@ -11,18 +16,12 @@
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
on property:sys.usb.config=mtp && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
@@ -32,9 +31,6 @@
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=mtp,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "mtp_adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/mtp.gs0 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -42,9 +38,6 @@
on property:sys.usb.config=ptp && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
@@ -54,9 +47,6 @@
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=ptp,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "ptp_adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/ptp.gs1 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -64,9 +54,6 @@
on property:sys.usb.config=accessory && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
@@ -76,9 +63,6 @@
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -86,9 +70,6 @@
on property:sys.usb.config=audio_source && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
@@ -98,9 +79,6 @@
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=audio_source,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "audiosource_adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/audio_source.gs2 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -108,9 +86,6 @@
on property:sys.usb.config=accessory,audio_source && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_audiosource"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
@@ -121,9 +96,6 @@
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=accessory,audio_source,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "accessory_audiosource_adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/accessory.gs2 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/audio_source.gs3 /config/usb_gadget/g1/configs/b.1/f2
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f3
@@ -132,9 +104,6 @@
on property:sys.usb.config=midi && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "midi"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/midi.gs5 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
@@ -144,19 +113,14 @@
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=midi,adb && property:sys.usb.configfs=1
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "midi_adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/midi.gs5 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
on property:sys.usb.config=rndis && property:sys.usb.configfs=1
+ mkdir /config/usb_gadget/g1/functions/rndis.gs4
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/rndis.gs4 /config/usb_gadget/g1/configs/b.1/f1
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
setprop sys.usb.state ${sys.usb.config}
@@ -165,10 +129,8 @@
start adbd
on property:sys.usb.ffs.ready=1 && property:sys.usb.config=rndis,adb && property:sys.usb.configfs=1
+ mkdir /config/usb_gadget/g1/functions/rndis.gs4
write /config/usb_gadget/g1/configs/b.1/strings/0x409/configuration "rndis_adb"
- rm /config/usb_gadget/g1/configs/b.1/f1
- rm /config/usb_gadget/g1/configs/b.1/f2
- rm /config/usb_gadget/g1/configs/b.1/f3
symlink /config/usb_gadget/g1/functions/rndis.gs4 /config/usb_gadget/g1/configs/b.1/f1
symlink /config/usb_gadget/g1/functions/ffs.adb /config/usb_gadget/g1/configs/b.1/f2
write /config/usb_gadget/g1/UDC ${sys.usb.controller}
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index b41af92..2d7d5c2 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 2914f07..a5e32c2 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -11,6 +12,7 @@
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
+ priority -20
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 2cc0966..8584cbb 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index a422fcc..4a32097 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -11,6 +12,7 @@
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
+ priority -20
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
diff --git a/run-as/Android.mk b/run-as/Android.mk
index 3774acc..7111fbe 100644
--- a/run-as/Android.mk
+++ b/run-as/Android.mk
@@ -1,12 +1,8 @@
LOCAL_PATH:= $(call my-dir)
+
include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := run-as.c package.c
-
-LOCAL_SHARED_LIBRARIES := libselinux
-
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE := run-as
-
-LOCAL_CFLAGS := -Werror
-
+LOCAL_SHARED_LIBRARIES := libselinux libpackagelistparser libminijail
+LOCAL_SRC_FILES := run-as.cpp
include $(BUILD_EXECUTABLE)
diff --git a/run-as/package.c b/run-as/package.c
deleted file mode 100644
index 86824c2..0000000
--- a/run-as/package.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
-**
-** Copyright 2010, 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 <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include <private/android_filesystem_config.h>
-#include "package.h"
-
-/*
- * WARNING WARNING WARNING WARNING
- *
- * The following code runs as root on production devices, before
- * the run-as command has dropped the uid/gid. Hence be very
- * conservative and keep in mind the following:
- *
- * - Performance does not matter here, clarity and safety of the code
- * does however. Documentation is a must.
- *
- * - Avoid calling C library functions with complex implementations
- * like malloc() and printf(). You want to depend on simple system
- * calls instead, which behaviour is not going to be altered in
- * unpredictible ways by environment variables or system properties.
- *
- * - Do not trust user input and/or the filesystem whenever possible.
- *
- */
-
-/* The file containing the list of installed packages on the system */
-#define PACKAGES_LIST_FILE "/data/system/packages.list"
-
-/* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen'
- * This function always zero-terminate the destination buffer unless
- * 'dstlen' is 0, even in case of overflow.
- * Returns a pointer into the src string, leaving off where the copy
- * has stopped. The copy will stop when dstlen, srclen or a null
- * character on src has been reached.
- */
-static const char*
-string_copy(char* dst, size_t dstlen, const char* src, size_t srclen)
-{
- const char* srcend = src + srclen;
- const char* dstend = dst + dstlen;
-
- if (dstlen == 0)
- return src;
-
- dstend--; /* make room for terminating zero */
-
- while (dst < dstend && src < srcend && *src != '\0')
- *dst++ = *src++;
-
- *dst = '\0'; /* zero-terminate result */
- return src;
-}
-
-/* Open 'filename' and map it into our address-space.
- * Returns buffer address, or NULL on error
- * On exit, *filesize will be set to the file's size, or 0 on error
- */
-static void*
-map_file(const char* filename, size_t* filesize)
-{
- int fd, ret, old_errno;
- struct stat st;
- size_t length = 0;
- void* address = NULL;
- gid_t oldegid;
-
- *filesize = 0;
-
- /*
- * Temporarily switch effective GID to allow us to read
- * the packages file
- */
-
- oldegid = getegid();
- if (setegid(AID_PACKAGE_INFO) < 0) {
- return NULL;
- }
-
- /* open the file for reading */
- fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
- if (fd < 0) {
- return NULL;
- }
-
- /* restore back to our old egid */
- if (setegid(oldegid) < 0) {
- goto EXIT;
- }
-
- /* get its size */
- ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
- if (ret < 0)
- goto EXIT;
-
- /* Ensure that the file is owned by the system user */
- if ((st.st_uid != AID_SYSTEM) || (st.st_gid != AID_PACKAGE_INFO)) {
- goto EXIT;
- }
-
- /* Ensure that the file has sane permissions */
- if ((st.st_mode & S_IWOTH) != 0) {
- goto EXIT;
- }
-
- /* Ensure that the size is not ridiculously large */
- length = (size_t)st.st_size;
- if ((off_t)length != st.st_size) {
- errno = ENOMEM;
- goto EXIT;
- }
-
- /* Memory-map the file now */
- do {
- address = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
- } while (address == MAP_FAILED && errno == EINTR);
- if (address == MAP_FAILED) {
- address = NULL;
- goto EXIT;
- }
-
- /* We're good, return size */
- *filesize = length;
-
-EXIT:
- /* close the file, preserve old errno for better diagnostics */
- old_errno = errno;
- close(fd);
- errno = old_errno;
-
- return address;
-}
-
-/* unmap the file, but preserve errno */
-static void
-unmap_file(void* address, size_t size)
-{
- int old_errno = errno;
- TEMP_FAILURE_RETRY(munmap(address, size));
- errno = old_errno;
-}
-
-/* Check that a given directory:
- * - exists
- * - is owned by a given uid/gid
- * - is a real directory, not a symlink
- * - isn't readable or writable by others
- *
- * Return 0 on success, or -1 on error.
- * errno is set to EINVAL in case of failed check.
- */
-static int
-check_directory_ownership(const char* path, uid_t uid)
-{
- int ret;
- struct stat st;
-
- do {
- ret = lstat(path, &st);
- } while (ret < 0 && errno == EINTR);
-
- if (ret < 0)
- return -1;
-
- /* /data/user/0 is a known safe symlink */
- if (strcmp("/data/user/0", path) == 0)
- return 0;
-
- /* must be a real directory, not a symlink */
- if (!S_ISDIR(st.st_mode))
- goto BAD;
-
- /* must be owned by specific uid/gid */
- if (st.st_uid != uid || st.st_gid != uid)
- goto BAD;
-
- /* must not be readable or writable by others */
- if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0)
- goto BAD;
-
- /* everything ok */
- return 0;
-
-BAD:
- errno = EINVAL;
- return -1;
-}
-
-/* This function is used to check the data directory path for safety.
- * We check that every sub-directory is owned by the 'system' user
- * and exists and is not a symlink. We also check that the full directory
- * path is properly owned by the user ID.
- *
- * Return 0 on success, -1 on error.
- */
-int
-check_data_path(const char* dataPath, uid_t uid)
-{
- int nn;
-
- /* the path should be absolute */
- if (dataPath[0] != '/') {
- errno = EINVAL;
- return -1;
- }
-
- /* look for all sub-paths, we do that by finding
- * directory separators in the input path and
- * checking each sub-path independently
- */
- for (nn = 1; dataPath[nn] != '\0'; nn++)
- {
- char subpath[PATH_MAX];
-
- /* skip non-separator characters */
- if (dataPath[nn] != '/')
- continue;
-
- /* handle trailing separator case */
- if (dataPath[nn+1] == '\0') {
- break;
- }
-
- /* found a separator, check that dataPath is not too long. */
- if (nn >= (int)(sizeof subpath)) {
- errno = EINVAL;
- return -1;
- }
-
- /* reject any '..' subpath */
- if (nn >= 3 &&
- dataPath[nn-3] == '/' &&
- dataPath[nn-2] == '.' &&
- dataPath[nn-1] == '.') {
- errno = EINVAL;
- return -1;
- }
-
- /* copy to 'subpath', then check ownership */
- memcpy(subpath, dataPath, nn);
- subpath[nn] = '\0';
-
- if (check_directory_ownership(subpath, AID_SYSTEM) < 0)
- return -1;
- }
-
- /* All sub-paths were checked, now verify that the full data
- * directory is owned by the application uid
- */
- if (check_directory_ownership(dataPath, uid) < 0)
- return -1;
-
- /* all clear */
- return 0;
-}
-
-/* Return TRUE iff a character is a space or tab */
-static inline int
-is_space(char c)
-{
- return (c == ' ' || c == '\t');
-}
-
-/* Skip any space or tab character from 'p' until 'end' is reached.
- * Return new position.
- */
-static const char*
-skip_spaces(const char* p, const char* end)
-{
- while (p < end && is_space(*p))
- p++;
-
- return p;
-}
-
-/* Skip any non-space and non-tab character from 'p' until 'end'.
- * Return new position.
- */
-static const char*
-skip_non_spaces(const char* p, const char* end)
-{
- while (p < end && !is_space(*p))
- p++;
-
- return p;
-}
-
-/* Find the first occurence of 'ch' between 'p' and 'end'
- * Return its position, or 'end' if none is found.
- */
-static const char*
-find_first(const char* p, const char* end, char ch)
-{
- while (p < end && *p != ch)
- p++;
-
- return p;
-}
-
-/* Check that the non-space string starting at 'p' and eventually
- * ending at 'end' equals 'name'. Return new position (after name)
- * on success, or NULL on failure.
- *
- * This function fails is 'name' is NULL, empty or contains any space.
- */
-static const char*
-compare_name(const char* p, const char* end, const char* name)
-{
- /* 'name' must not be NULL or empty */
- if (name == NULL || name[0] == '\0' || p == end)
- return NULL;
-
- /* compare characters to those in 'name', excluding spaces */
- while (*name) {
- /* note, we don't check for *p == '\0' since
- * it will be caught in the next conditional.
- */
- if (p >= end || is_space(*p))
- goto BAD;
-
- if (*p != *name)
- goto BAD;
-
- p++;
- name++;
- }
-
- /* must be followed by end of line or space */
- if (p < end && !is_space(*p))
- goto BAD;
-
- return p;
-
-BAD:
- return NULL;
-}
-
-/* Parse one or more whitespace characters starting from '*pp'
- * until 'end' is reached. Updates '*pp' on exit.
- *
- * Return 0 on success, -1 on failure.
- */
-static int
-parse_spaces(const char** pp, const char* end)
-{
- const char* p = *pp;
-
- if (p >= end || !is_space(*p)) {
- errno = EINVAL;
- return -1;
- }
- p = skip_spaces(p, end);
- *pp = p;
- return 0;
-}
-
-/* Parse a positive decimal number starting from '*pp' until 'end'
- * is reached. Adjust '*pp' on exit. Return decimal value or -1
- * in case of error.
- *
- * If the value is larger than INT_MAX, -1 will be returned,
- * and errno set to EOVERFLOW.
- *
- * If '*pp' does not start with a decimal digit, -1 is returned
- * and errno set to EINVAL.
- */
-static int
-parse_positive_decimal(const char** pp, const char* end)
-{
- const char* p = *pp;
- int value = 0;
- int overflow = 0;
-
- if (p >= end || *p < '0' || *p > '9') {
- errno = EINVAL;
- return -1;
- }
-
- while (p < end) {
- int ch = *p;
- unsigned d = (unsigned)(ch - '0');
- int val2;
-
- if (d >= 10U) /* d is unsigned, no lower bound check */
- break;
-
- val2 = value*10 + (int)d;
- if (val2 < value)
- overflow = 1;
- value = val2;
- p++;
- }
- *pp = p;
-
- if (overflow) {
- errno = EOVERFLOW;
- value = -1;
- }
- return value;
-}
-
-/* Read the system's package database and extract information about
- * 'pkgname'. Return 0 in case of success, or -1 in case of error.
- *
- * If the package is unknown, return -1 and set errno to ENOENT
- * If the package database is corrupted, return -1 and set errno to EINVAL
- */
-int
-get_package_info(const char* pkgName, uid_t userId, PackageInfo *info)
-{
- char* buffer;
- size_t buffer_len;
- const char* p;
- const char* buffer_end;
- int result = -1;
-
- info->uid = 0;
- info->isDebuggable = 0;
- info->dataDir[0] = '\0';
- info->seinfo[0] = '\0';
-
- buffer = map_file(PACKAGES_LIST_FILE, &buffer_len);
- if (buffer == NULL)
- return -1;
-
- p = buffer;
- buffer_end = buffer + buffer_len;
-
- /* expect the following format on each line of the control file:
- *
- * <pkgName> <uid> <debugFlag> <dataDir> <seinfo>
- *
- * where:
- * <pkgName> is the package's name
- * <uid> is the application-specific user Id (decimal)
- * <debugFlag> is 1 if the package is debuggable, or 0 otherwise
- * <dataDir> is the path to the package's data directory (e.g. /data/data/com.example.foo)
- * <seinfo> is the seinfo label associated with the package
- *
- * The file is generated in com.android.server.PackageManagerService.Settings.writeLP()
- */
-
- while (p < buffer_end) {
- /* find end of current line and start of next one */
- const char* end = find_first(p, buffer_end, '\n');
- const char* next = (end < buffer_end) ? end + 1 : buffer_end;
- const char* q;
- int uid, debugFlag;
-
- /* first field is the package name */
- p = compare_name(p, end, pkgName);
- if (p == NULL)
- goto NEXT_LINE;
-
- /* skip spaces */
- if (parse_spaces(&p, end) < 0)
- goto BAD_FORMAT;
-
- /* second field is the pid */
- uid = parse_positive_decimal(&p, end);
- if (uid < 0)
- return -1;
-
- info->uid = (uid_t) uid;
-
- /* skip spaces */
- if (parse_spaces(&p, end) < 0)
- goto BAD_FORMAT;
-
- /* third field is debug flag (0 or 1) */
- debugFlag = parse_positive_decimal(&p, end);
- switch (debugFlag) {
- case 0:
- info->isDebuggable = 0;
- break;
- case 1:
- info->isDebuggable = 1;
- break;
- default:
- goto BAD_FORMAT;
- }
-
- /* skip spaces */
- if (parse_spaces(&p, end) < 0)
- goto BAD_FORMAT;
-
- /* fourth field is data directory path and must not contain
- * spaces.
- */
- q = skip_non_spaces(p, end);
- if (q == p)
- goto BAD_FORMAT;
-
- /* If userId == 0 (i.e. user is device owner) we can use dataDir value
- * from packages.list, otherwise compose data directory as
- * /data/user/$uid/$packageId
- */
- if (userId == 0) {
- p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p);
- } else {
- snprintf(info->dataDir,
- sizeof info->dataDir,
- "/data/user/%d/%s",
- userId,
- pkgName);
- p = q;
- }
-
- /* skip spaces */
- if (parse_spaces(&p, end) < 0)
- goto BAD_FORMAT;
-
- /* fifth field is the seinfo string */
- q = skip_non_spaces(p, end);
- if (q == p)
- goto BAD_FORMAT;
-
- string_copy(info->seinfo, sizeof info->seinfo, p, q - p);
-
- /* Ignore the rest */
- result = 0;
- goto EXIT;
-
- NEXT_LINE:
- p = next;
- }
-
- /* the package is unknown */
- errno = ENOENT;
- result = -1;
- goto EXIT;
-
-BAD_FORMAT:
- errno = EINVAL;
- result = -1;
-
-EXIT:
- unmap_file(buffer, buffer_len);
- return result;
-}
diff --git a/run-as/package.h b/run-as/package.h
deleted file mode 100644
index eeb5913..0000000
--- a/run-as/package.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-**
-** Copyright 2010, 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 RUN_AS_PACKAGE_H
-#define RUN_AS_PACKAGE_H
-
-#include <limits.h>
-#include <sys/types.h>
-
-typedef enum {
- PACKAGE_IS_DEBUGGABLE = 0,
- PACKAGE_IS_NOT_DEBUGGABLE,
- PACKAGE_IS_UNKNOWN,
-} PackageStatus;
-
-typedef struct {
- uid_t uid;
- char isDebuggable;
- char dataDir[PATH_MAX];
- char seinfo[PATH_MAX];
-} PackageInfo;
-
-/* see documentation in package.c for these functions */
-
-extern int get_package_info(const char* packageName,
- uid_t userId,
- PackageInfo* info);
-
-extern int check_data_path(const char* dataDir, uid_t uid);
-
-#endif /* RUN_AS_PACKAGE_H */
diff --git a/run-as/run-as.c b/run-as/run-as.c
deleted file mode 100644
index f0fd2fe..0000000
--- a/run-as/run-as.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
-**
-** Copyright 2010, 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 PROGNAME "run-as"
-#define LOG_TAG PROGNAME
-
-#include <dirent.h>
-#include <errno.h>
-#include <paths.h>
-#include <pwd.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/capability.h>
-#include <sys/cdefs.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <private/android_filesystem_config.h>
-#include <selinux/android.h>
-
-#include "package.h"
-
-/*
- * WARNING WARNING WARNING WARNING
- *
- * This program runs with CAP_SETUID and CAP_SETGID capabilities on Android
- * production devices. Be very conservative when modifying it to avoid any
- * serious security issue. Keep in mind the following:
- *
- * - This program should only run for the 'root' or 'shell' users
- *
- * - Avoid anything that is more complex than simple system calls
- * until the uid/gid has been dropped to that of a normal user
- * or you are sure to exit.
- *
- * This avoids depending on environment variables, system properties
- * and other external factors that may affect the C library in
- * unpredictable ways.
- *
- * - Do not trust user input and/or the filesystem whenever possible.
- *
- * Read README.TXT for more details.
- *
- *
- *
- * The purpose of this program is to run a command as a specific
- * application user-id. Typical usage is:
- *
- * run-as <package-name> <command> <args>
- *
- * The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file
- * capabilities, but will check the following:
- *
- * - that it is invoked from the 'shell' or 'root' user (abort otherwise)
- * - that '<package-name>' is the name of an installed and debuggable package
- * - that the package's data directory is well-formed (see package.c)
- *
- * If so, it will drop to the application's user id / group id, cd to the
- * package's data directory, then run the command there.
- *
- * NOTE: In the future it might not be possible to cd to the package's data
- * directory under that package's user id / group id, in which case this
- * utility will need to be changed accordingly.
- *
- * This can be useful for a number of different things on production devices:
- *
- * - Allow application developers to look at their own applicative data
- * during development.
- *
- * - Run the 'gdbserver' binary executable to allow native debugging
- */
-
-__noreturn static void
-panic(const char* format, ...)
-{
- va_list args;
- int e = errno;
-
- fprintf(stderr, "%s: ", PROGNAME);
- va_start(args, format);
- vfprintf(stderr, format, args);
- va_end(args);
- exit(e ? -e : 1);
-}
-
-static void
-usage(void)
-{
- panic("Usage:\n " PROGNAME " <package-name> [--user <uid>] <command> [<args>]\n");
-}
-
-int main(int argc, char **argv)
-{
- const char* pkgname;
- uid_t myuid, uid, gid, userAppId = 0;
- int commandArgvOfs = 2, userId = 0;
- PackageInfo info;
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
-
- /* check arguments */
- if (argc < 2) {
- usage();
- }
-
- /* check userid of caller - must be 'shell' or 'root' */
- myuid = getuid();
- if (myuid != AID_SHELL && myuid != AID_ROOT) {
- panic("only 'shell' or 'root' users can run this program\n");
- }
-
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- capdata[CAP_TO_INDEX(CAP_SETUID)].effective |= CAP_TO_MASK(CAP_SETUID);
- capdata[CAP_TO_INDEX(CAP_SETGID)].effective |= CAP_TO_MASK(CAP_SETGID);
- capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
- capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
-
- if (capset(&capheader, &capdata[0]) < 0) {
- panic("Could not set capabilities: %s\n", strerror(errno));
- }
-
- pkgname = argv[1];
-
- /* get user_id from command line if provided */
- if ((argc >= 4) && !strcmp(argv[2], "--user")) {
- userId = atoi(argv[3]);
- if (userId < 0)
- panic("Negative user id %d is provided\n", userId);
- commandArgvOfs += 2;
- }
-
- /* retrieve package information from system (does setegid) */
- if (get_package_info(pkgname, userId, &info) < 0) {
- panic("Package '%s' is unknown\n", pkgname);
- }
-
- /* verify that user id is not too big. */
- if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
- panic("User id %d is too big\n", userId);
- }
-
- /* calculate user app ID. */
- userAppId = (AID_USER * userId) + info.uid;
-
- /* reject system packages */
- if (userAppId < AID_APP) {
- panic("Package '%s' is not an application\n", pkgname);
- }
-
- /* reject any non-debuggable package */
- if (!info.isDebuggable) {
- panic("Package '%s' is not debuggable\n", pkgname);
- }
-
- /* check that the data directory path is valid */
- if (check_data_path(info.dataDir, userAppId) < 0) {
- panic("Package '%s' has corrupt installation\n", pkgname);
- }
-
- /* Ensure that we change all real/effective/saved IDs at the
- * same time to avoid nasty surprises.
- */
- uid = gid = userAppId;
- if(setresgid(gid,gid,gid) || setresuid(uid,uid,uid)) {
- panic("Permission denied\n");
- }
-
- /* Required if caller has uid and gid all non-zero */
- memset(&capdata, 0, sizeof(capdata));
- if (capset(&capheader, &capdata[0]) < 0) {
- panic("Could not clear all capabilities: %s\n", strerror(errno));
- }
-
- if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
- panic("Could not set SELinux security context: %s\n", strerror(errno));
- }
-
- // cd into the data directory, and set $HOME correspondingly.
- if (TEMP_FAILURE_RETRY(chdir(info.dataDir)) < 0) {
- panic("Could not cd to package's data directory: %s\n", strerror(errno));
- }
- setenv("HOME", info.dataDir, 1);
-
- // Reset parts of the environment, like su would.
- setenv("PATH", _PATH_DEFPATH, 1);
- unsetenv("IFS");
-
- // Set the user-specific parts for this user.
- struct passwd* pw = getpwuid(uid);
- setenv("LOGNAME", pw->pw_name, 1);
- setenv("SHELL", pw->pw_shell, 1);
- setenv("USER", pw->pw_name, 1);
-
- /* User specified command for exec. */
- if ((argc >= commandArgvOfs + 1) &&
- (execvp(argv[commandArgvOfs], argv+commandArgvOfs) < 0)) {
- panic("exec failed for %s: %s\n", argv[commandArgvOfs], strerror(errno));
- }
-
- /* Default exec shell. */
- execlp("/system/bin/sh", "sh", NULL);
-
- panic("exec failed: %s\n", strerror(errno));
-}
diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp
new file mode 100644
index 0000000..aec51f4
--- /dev/null
+++ b/run-as/run-as.cpp
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2010 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 <errno.h>
+#include <error.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <libminijail.h>
+#include <scoped_minijail.h>
+
+#include <packagelistparser/packagelistparser.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/android.h>
+
+// The purpose of this program is to run a command as a specific
+// application user-id. Typical usage is:
+//
+// run-as <package-name> <command> <args>
+//
+// The 'run-as' binary is installed with CAP_SETUID and CAP_SETGID file
+// capabilities, but will check the following:
+//
+// - that it is invoked from the 'shell' or 'root' user (abort otherwise)
+// - that '<package-name>' is the name of an installed and debuggable package
+// - that the package's data directory is well-formed
+//
+// If so, it will drop to the application's user id / group id, cd to the
+// package's data directory, then run the command there.
+//
+// This can be useful for a number of different things on production devices:
+//
+// - Allow application developers to look at their own application data
+// during development.
+//
+// - Run the 'gdbserver' binary executable to allow native debugging
+//
+
+static bool packagelist_parse_callback(pkg_info* this_package, void* userdata) {
+ pkg_info* p = reinterpret_cast<pkg_info*>(userdata);
+ if (strcmp(p->name, this_package->name) == 0) {
+ *p = *this_package;
+ return false; // Stop searching.
+ }
+ packagelist_free(this_package);
+ return true; // Keep searching.
+}
+
+static bool check_directory(const char* path, uid_t uid) {
+ struct stat st;
+ if (TEMP_FAILURE_RETRY(lstat(path, &st)) == -1) return false;
+
+ // /data/user/0 is a known safe symlink.
+ if (strcmp("/data/user/0", path) == 0) return true;
+
+ // Must be a real directory, not a symlink.
+ if (!S_ISDIR(st.st_mode)) return false;
+
+ // Must be owned by specific uid/gid.
+ if (st.st_uid != uid || st.st_gid != uid) return false;
+
+ // Must not be readable or writable by others.
+ if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0) return false;
+
+ return true;
+}
+
+// This function is used to check the data directory path for safety.
+// We check that every sub-directory is owned by the 'system' user
+// and exists and is not a symlink. We also check that the full directory
+// path is properly owned by the user ID.
+static bool check_data_path(const char* data_path, uid_t uid) {
+ // The path should be absolute.
+ if (data_path[0] != '/') return false;
+
+ // Look for all sub-paths, we do that by finding
+ // directory separators in the input path and
+ // checking each sub-path independently.
+ for (int nn = 1; data_path[nn] != '\0'; nn++) {
+ char subpath[PATH_MAX];
+
+ /* skip non-separator characters */
+ if (data_path[nn] != '/') continue;
+
+ /* handle trailing separator case */
+ if (data_path[nn+1] == '\0') break;
+
+ /* found a separator, check that data_path is not too long. */
+ if (nn >= (int)(sizeof subpath)) return false;
+
+ /* reject any '..' subpath */
+ if (nn >= 3 &&
+ data_path[nn-3] == '/' &&
+ data_path[nn-2] == '.' &&
+ data_path[nn-1] == '.') {
+ return false;
+ }
+
+ /* copy to 'subpath', then check ownership */
+ memcpy(subpath, data_path, nn);
+ subpath[nn] = '\0';
+
+ if (!check_directory(subpath, AID_SYSTEM)) return false;
+ }
+
+ // All sub-paths were checked, now verify that the full data
+ // directory is owned by the application uid.
+ return check_directory(data_path, uid);
+}
+
+int main(int argc, char* argv[]) {
+ // Check arguments.
+ if (argc < 2) {
+ error(1, 0, "usage: run-as <package-name> [--user <uid>] <command> [<args>]\n");
+ }
+
+ // This program runs with CAP_SETUID and CAP_SETGID capabilities on Android
+ // production devices. Check user id of caller --- must be 'shell' or 'root'.
+ if (getuid() != AID_SHELL && getuid() != AID_ROOT) {
+ error(1, 0, "only 'shell' or 'root' users can run this program");
+ }
+
+ char* pkgname = argv[1];
+ int cmd_argv_offset = 2;
+
+ // Get user_id from command line if provided.
+ int userId = 0;
+ if ((argc >= 4) && !strcmp(argv[2], "--user")) {
+ userId = atoi(argv[3]);
+ if (userId < 0) error(1, 0, "negative user id: %d", userId);
+ cmd_argv_offset += 2;
+ }
+
+ // Retrieve package information from system, switching egid so we can read the file.
+ gid_t old_egid = getegid();
+ if (setegid(AID_PACKAGE_INFO) == -1) error(1, errno, "setegid(AID_PACKAGE_INFO) failed");
+ pkg_info info;
+ memset(&info, 0, sizeof(info));
+ info.name = pkgname;
+ if (!packagelist_parse(packagelist_parse_callback, &info)) {
+ error(1, errno, "packagelist_parse failed");
+ }
+ if (info.uid == 0) {
+ error(1, 0, "unknown package: %s", pkgname);
+ }
+ if (setegid(old_egid) == -1) error(1, errno, "couldn't restore egid");
+
+ // Verify that user id is not too big.
+ if ((UID_MAX - info.uid) / AID_USER < (uid_t)userId) {
+ error(1, 0, "user id too big: %d", userId);
+ }
+
+ // Calculate user app ID.
+ uid_t userAppId = (AID_USER * userId) + info.uid;
+
+ // Reject system packages.
+ if (userAppId < AID_APP) {
+ error(1, 0, "package not an application: %s", pkgname);
+ }
+
+ // Reject any non-debuggable package.
+ if (!info.debuggable) {
+ error(1, 0, "package not debuggable: %s", pkgname);
+ }
+
+ // Check that the data directory path is valid.
+ if (!check_data_path(info.data_dir, userAppId)) {
+ error(1, 0, "package has corrupt installation: %s", pkgname);
+ }
+
+ // Ensure that we change all real/effective/saved IDs at the
+ // same time to avoid nasty surprises.
+ uid_t uid = userAppId;
+ uid_t gid = userAppId;
+ ScopedMinijail j(minijail_new());
+ minijail_change_uid(j.get(), uid);
+ minijail_change_gid(j.get(), gid);
+ minijail_enter(j.get());
+
+ if (selinux_android_setcontext(uid, 0, info.seinfo, pkgname) < 0) {
+ error(1, errno, "couldn't set SELinux security context");
+ }
+
+ // cd into the data directory, and set $HOME correspondingly.
+ if (TEMP_FAILURE_RETRY(chdir(info.data_dir)) == -1) {
+ error(1, errno, "couldn't chdir to package's data directory");
+ }
+ setenv("HOME", info.data_dir, 1);
+
+ // Reset parts of the environment, like su would.
+ setenv("PATH", _PATH_DEFPATH, 1);
+ unsetenv("IFS");
+
+ // Set the user-specific parts for this user.
+ passwd* pw = getpwuid(uid);
+ setenv("LOGNAME", pw->pw_name, 1);
+ setenv("SHELL", pw->pw_shell, 1);
+ setenv("USER", pw->pw_name, 1);
+
+ // User specified command for exec.
+ if ((argc >= cmd_argv_offset + 1) &&
+ (execvp(argv[cmd_argv_offset], argv+cmd_argv_offset) == -1)) {
+ error(1, errno, "exec failed for %s", argv[cmd_argv_offset]);
+ }
+
+ // Default exec shell.
+ execlp(_PATH_BSHELL, "sh", NULL);
+ error(1, errno, "exec failed");
+}
diff --git a/sdcard/Android.mk b/sdcard/Android.mk
index c5f3d1d..0c58574 100644
--- a/sdcard/Android.mk
+++ b/sdcard/Android.mk
@@ -2,9 +2,12 @@
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := sdcard.c
+LOCAL_SRC_FILES := sdcard.cpp fuse.cpp
LOCAL_MODULE := sdcard
LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror
-LOCAL_SHARED_LIBRARIES := libcutils libpackagelistparser
+LOCAL_SHARED_LIBRARIES := libbase libcutils libminijail libpackagelistparser
+
+LOCAL_SANITIZE := integer
+LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)
diff --git a/sdcard/fuse.cpp b/sdcard/fuse.cpp
new file mode 100644
index 0000000..6a972ea
--- /dev/null
+++ b/sdcard/fuse.cpp
@@ -0,0 +1,1470 @@
+/*
+ * Copyright (C) 2010 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 "sdcard"
+
+#include "fuse.h"
+
+#include <android-base/logging.h>
+
+/* FUSE_CANONICAL_PATH is not currently upstreamed */
+#define FUSE_CANONICAL_PATH 2016
+
+#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
+#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
+
+#define FUSE_UNKNOWN_INO 0xffffffff
+
+/* Pseudo-error constant used to indicate that no fuse status is needed
+ * or that a reply has already been written. */
+#define NO_STATUS 1
+
+static inline void *id_to_ptr(__u64 nid)
+{
+ return (void *) (uintptr_t) nid;
+}
+
+static inline __u64 ptr_to_id(void *ptr)
+{
+ return (__u64) (uintptr_t) ptr;
+}
+
+static void acquire_node_locked(struct node* node)
+{
+ node->refcount++;
+ DLOG(INFO) << "ACQUIRE " << std::hex << node << std::dec
+ << " (" << node->name << ") rc=" << node->refcount;
+}
+
+static void remove_node_from_parent_locked(struct node* node);
+
+static void release_node_locked(struct node* node)
+{
+ DLOG(INFO) << "RELEASE " << std::hex << node << std::dec
+ << " (" << node->name << ") rc=" << node->refcount;
+ if (node->refcount > 0) {
+ node->refcount--;
+ if (!node->refcount) {
+ DLOG(INFO) << "DESTROY " << std::hex << node << std::dec << " (" << node->name << ")";
+ remove_node_from_parent_locked(node);
+
+ /* TODO: remove debugging - poison memory */
+ memset(node->name, 0xef, node->namelen);
+ free(node->name);
+ free(node->actual_name);
+ memset(node, 0xfc, sizeof(*node));
+ free(node);
+ }
+ } else {
+ LOG(ERROR) << std::hex << node << std::dec << " refcount=0";
+ }
+}
+
+static void add_node_to_parent_locked(struct node *node, struct node *parent) {
+ node->parent = parent;
+ node->next = parent->child;
+ parent->child = node;
+ acquire_node_locked(parent);
+}
+
+static void remove_node_from_parent_locked(struct node* node)
+{
+ if (node->parent) {
+ if (node->parent->child == node) {
+ node->parent->child = node->parent->child->next;
+ } else {
+ struct node *node2;
+ node2 = node->parent->child;
+ while (node2->next != node)
+ node2 = node2->next;
+ node2->next = node->next;
+ }
+ release_node_locked(node->parent);
+ node->parent = NULL;
+ node->next = NULL;
+ }
+}
+
+/* Gets the absolute path to a node into the provided buffer.
+ *
+ * Populates 'buf' with the path and returns the length of the path on success,
+ * or returns -1 if the path is too long for the provided buffer.
+ */
+static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
+ const char* name;
+ size_t namelen;
+ if (node->graft_path) {
+ name = node->graft_path;
+ namelen = node->graft_pathlen;
+ } else if (node->actual_name) {
+ name = node->actual_name;
+ namelen = node->namelen;
+ } else {
+ name = node->name;
+ namelen = node->namelen;
+ }
+
+ if (bufsize < namelen + 1) {
+ return -1;
+ }
+
+ ssize_t pathlen = 0;
+ if (node->parent && node->graft_path == NULL) {
+ pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
+ if (pathlen < 0) {
+ return -1;
+ }
+ buf[pathlen++] = '/';
+ }
+
+ memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
+ return pathlen + namelen;
+}
+
+/* Finds the absolute path of a file within a given directory.
+ * Performs a case-insensitive search for the file and sets the buffer to the path
+ * of the first matching file. If 'search' is zero or if no match is found, sets
+ * the buffer to the path that the file would have, assuming the name were case-sensitive.
+ *
+ * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
+ * or returns NULL if the path is too long for the provided buffer.
+ */
+static char* find_file_within(const char* path, const char* name,
+ char* buf, size_t bufsize, int search)
+{
+ size_t pathlen = strlen(path);
+ size_t namelen = strlen(name);
+ size_t childlen = pathlen + namelen + 1;
+ char* actual;
+
+ if (bufsize <= childlen) {
+ return NULL;
+ }
+
+ memcpy(buf, path, pathlen);
+ buf[pathlen] = '/';
+ actual = buf + pathlen + 1;
+ memcpy(actual, name, namelen + 1);
+
+ if (search && access(buf, F_OK)) {
+ struct dirent* entry;
+ DIR* dir = opendir(path);
+ if (!dir) {
+ PLOG(ERROR) << "opendir(" << path << ") failed";
+ return actual;
+ }
+ while ((entry = readdir(dir))) {
+ if (!strcasecmp(entry->d_name, name)) {
+ /* we have a match - replace the name, don't need to copy the null again */
+ memcpy(actual, entry->d_name, namelen);
+ break;
+ }
+ }
+ closedir(dir);
+ }
+ return actual;
+}
+
+static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
+ const struct stat *s, const struct node* node) {
+ attr->ino = node->ino;
+ attr->size = s->st_size;
+ attr->blocks = s->st_blocks;
+ attr->atime = s->st_atim.tv_sec;
+ attr->mtime = s->st_mtim.tv_sec;
+ attr->ctime = s->st_ctim.tv_sec;
+ attr->atimensec = s->st_atim.tv_nsec;
+ attr->mtimensec = s->st_mtim.tv_nsec;
+ attr->ctimensec = s->st_ctim.tv_nsec;
+ attr->mode = s->st_mode;
+ attr->nlink = s->st_nlink;
+
+ attr->uid = node->uid;
+
+ if (fuse->gid == AID_SDCARD_RW) {
+ /* As an optimization, certain trusted system components only run
+ * as owner but operate across all users. Since we're now handing
+ * out the sdcard_rw GID only to trusted apps, we're okay relaxing
+ * the user boundary enforcement for the default view. The UIDs
+ * assigned to app directories are still multiuser aware. */
+ attr->gid = AID_SDCARD_RW;
+ } else {
+ attr->gid = multiuser_get_uid(node->userid, fuse->gid);
+ }
+
+ int visible_mode = 0775 & ~fuse->mask;
+ if (node->perm == PERM_PRE_ROOT) {
+ /* Top of multi-user view should always be visible to ensure
+ * secondary users can traverse inside. */
+ visible_mode = 0711;
+ } else if (node->under_android) {
+ /* Block "other" access to Android directories, since only apps
+ * belonging to a specific user should be in there; we still
+ * leave +x open for the default view. */
+ if (fuse->gid == AID_SDCARD_RW) {
+ visible_mode = visible_mode & ~0006;
+ } else {
+ visible_mode = visible_mode & ~0007;
+ }
+ }
+ int owner_mode = s->st_mode & 0700;
+ int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+ attr->mode = (attr->mode & S_IFMT) | filtered_mode;
+}
+
+static int touch(char* path, mode_t mode) {
+ int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
+ if (fd == -1) {
+ if (errno == EEXIST) {
+ return 0;
+ } else {
+ PLOG(ERROR) << "open(" << path << ") failed";
+ return -1;
+ }
+ }
+ close(fd);
+ return 0;
+}
+
+static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
+ struct node *node) {
+ appid_t appid;
+
+ /* By default, each node inherits from its parent */
+ node->perm = PERM_INHERIT;
+ node->userid = parent->userid;
+ node->uid = parent->uid;
+ node->under_android = parent->under_android;
+
+ /* Derive custom permissions based on parent and current node */
+ switch (parent->perm) {
+ case PERM_INHERIT:
+ /* Already inherited above */
+ break;
+ case PERM_PRE_ROOT:
+ /* Legacy internal layout places users at top level */
+ node->perm = PERM_ROOT;
+ node->userid = strtoul(node->name, NULL, 10);
+ break;
+ case PERM_ROOT:
+ /* Assume masked off by default. */
+ if (!strcasecmp(node->name, "Android")) {
+ /* App-specific directories inside; let anyone traverse */
+ node->perm = PERM_ANDROID;
+ node->under_android = true;
+ }
+ break;
+ case PERM_ANDROID:
+ if (!strcasecmp(node->name, "data")) {
+ /* App-specific directories inside; let anyone traverse */
+ node->perm = PERM_ANDROID_DATA;
+ } else if (!strcasecmp(node->name, "obb")) {
+ /* App-specific directories inside; let anyone traverse */
+ node->perm = PERM_ANDROID_OBB;
+ /* Single OBB directory is always shared */
+ node->graft_path = fuse->global->obb_path;
+ node->graft_pathlen = strlen(fuse->global->obb_path);
+ } else if (!strcasecmp(node->name, "media")) {
+ /* App-specific directories inside; let anyone traverse */
+ node->perm = PERM_ANDROID_MEDIA;
+ }
+ break;
+ case PERM_ANDROID_DATA:
+ case PERM_ANDROID_OBB:
+ case PERM_ANDROID_MEDIA:
+ const auto& iter = fuse->global->package_to_appid->find(node->name);
+ if (iter != fuse->global->package_to_appid->end()) {
+ appid = iter->second;
+ node->uid = multiuser_get_uid(parent->userid, appid);
+ }
+ break;
+ }
+}
+
+void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
+ struct node *node;
+ for (node = parent->child; node; node = node->next) {
+ derive_permissions_locked(fuse, parent, node);
+ if (node->child) {
+ derive_permissions_recursive_locked(fuse, node);
+ }
+ }
+}
+
+/* Kernel has already enforced everything we returned through
+ * derive_permissions_locked(), so this is used to lock down access
+ * even further, such as enforcing that apps hold sdcard_rw. */
+static bool check_caller_access_to_name(struct fuse* fuse,
+ const struct fuse_in_header *hdr, const struct node* parent_node,
+ const char* name, int mode) {
+ /* Always block security-sensitive files at root */
+ if (parent_node && parent_node->perm == PERM_ROOT) {
+ if (!strcasecmp(name, "autorun.inf")
+ || !strcasecmp(name, ".android_secure")
+ || !strcasecmp(name, "android_secure")) {
+ return false;
+ }
+ }
+
+ /* Root always has access; access for any other UIDs should always
+ * be controlled through packages.list. */
+ if (hdr->uid == 0) {
+ return true;
+ }
+
+ /* No extra permissions to enforce */
+ return true;
+}
+
+static bool check_caller_access_to_node(struct fuse* fuse,
+ const struct fuse_in_header *hdr, const struct node* node, int mode) {
+ return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
+}
+
+struct node *create_node_locked(struct fuse* fuse,
+ struct node *parent, const char *name, const char* actual_name)
+{
+ struct node *node;
+ size_t namelen = strlen(name);
+
+ // Detect overflows in the inode counter. "4 billion nodes should be enough
+ // for everybody".
+ if (fuse->global->inode_ctr == 0) {
+ LOG(ERROR) << "No more inode numbers available";
+ return NULL;
+ }
+
+ node = static_cast<struct node*>(calloc(1, sizeof(struct node)));
+ if (!node) {
+ return NULL;
+ }
+ node->name = static_cast<char*>(malloc(namelen + 1));
+ if (!node->name) {
+ free(node);
+ return NULL;
+ }
+ memcpy(node->name, name, namelen + 1);
+ if (strcmp(name, actual_name)) {
+ node->actual_name = static_cast<char*>(malloc(namelen + 1));
+ if (!node->actual_name) {
+ free(node->name);
+ free(node);
+ return NULL;
+ }
+ memcpy(node->actual_name, actual_name, namelen + 1);
+ }
+ node->namelen = namelen;
+ node->nid = ptr_to_id(node);
+ node->ino = fuse->global->inode_ctr++;
+ node->gen = fuse->global->next_generation++;
+
+ node->deleted = false;
+
+ derive_permissions_locked(fuse, parent, node);
+ acquire_node_locked(node);
+ add_node_to_parent_locked(node, parent);
+ return node;
+}
+
+static int rename_node_locked(struct node *node, const char *name,
+ const char* actual_name)
+{
+ size_t namelen = strlen(name);
+ int need_actual_name = strcmp(name, actual_name);
+
+ /* make the storage bigger without actually changing the name
+ * in case an error occurs part way */
+ if (namelen > node->namelen) {
+ char* new_name = static_cast<char*>(realloc(node->name, namelen + 1));
+ if (!new_name) {
+ return -ENOMEM;
+ }
+ node->name = new_name;
+ if (need_actual_name && node->actual_name) {
+ char* new_actual_name = static_cast<char*>(realloc(node->actual_name, namelen + 1));
+ if (!new_actual_name) {
+ return -ENOMEM;
+ }
+ node->actual_name = new_actual_name;
+ }
+ }
+
+ /* update the name, taking care to allocate storage before overwriting the old name */
+ if (need_actual_name) {
+ if (!node->actual_name) {
+ node->actual_name = static_cast<char*>(malloc(namelen + 1));
+ if (!node->actual_name) {
+ return -ENOMEM;
+ }
+ }
+ memcpy(node->actual_name, actual_name, namelen + 1);
+ } else {
+ free(node->actual_name);
+ node->actual_name = NULL;
+ }
+ memcpy(node->name, name, namelen + 1);
+ node->namelen = namelen;
+ return 0;
+}
+
+static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
+{
+ if (nid == FUSE_ROOT_ID) {
+ return &fuse->global->root;
+ } else {
+ return static_cast<struct node*>(id_to_ptr(nid));
+ }
+}
+
+static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
+ char* buf, size_t bufsize)
+{
+ struct node* node = lookup_node_by_id_locked(fuse, nid);
+ if (node && get_node_path_locked(node, buf, bufsize) < 0) {
+ node = NULL;
+ }
+ return node;
+}
+
+static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
+{
+ for (node = node->child; node; node = node->next) {
+ /* use exact string comparison, nodes that differ by case
+ * must be considered distinct even if they refer to the same
+ * underlying file as otherwise operations such as "mv x x"
+ * will not work because the source and target nodes are the same. */
+ if (!strcmp(name, node->name) && !node->deleted) {
+ return node;
+ }
+ }
+ return 0;
+}
+
+static struct node* acquire_or_create_child_locked(
+ struct fuse* fuse, struct node* parent,
+ const char* name, const char* actual_name)
+{
+ struct node* child = lookup_child_by_name_locked(parent, name);
+ if (child) {
+ acquire_node_locked(child);
+ } else {
+ child = create_node_locked(fuse, parent, name, actual_name);
+ }
+ return child;
+}
+
+static void fuse_status(struct fuse *fuse, __u64 unique, int err)
+{
+ struct fuse_out_header hdr;
+ hdr.len = sizeof(hdr);
+ hdr.error = err;
+ hdr.unique = unique;
+ write(fuse->fd, &hdr, sizeof(hdr));
+}
+
+static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
+{
+ struct fuse_out_header hdr;
+ struct iovec vec[2];
+ int res;
+
+ hdr.len = len + sizeof(hdr);
+ hdr.error = 0;
+ hdr.unique = unique;
+
+ vec[0].iov_base = &hdr;
+ vec[0].iov_len = sizeof(hdr);
+ vec[1].iov_base = data;
+ vec[1].iov_len = len;
+
+ res = writev(fuse->fd, vec, 2);
+ if (res < 0) {
+ PLOG(ERROR) << "*** REPLY FAILED ***";
+ }
+}
+
+static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
+ struct node* parent, const char* name, const char* actual_name,
+ const char* path)
+{
+ struct node* node;
+ struct fuse_entry_out out;
+ struct stat s;
+
+ if (lstat(path, &s) < 0) {
+ return -errno;
+ }
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
+ if (!node) {
+ pthread_mutex_unlock(&fuse->global->lock);
+ return -ENOMEM;
+ }
+ memset(&out, 0, sizeof(out));
+ attr_from_stat(fuse, &out.attr, &s, node);
+ out.attr_valid = 10;
+ out.entry_valid = 10;
+ out.nodeid = node->nid;
+ out.generation = node->gen;
+ pthread_mutex_unlock(&fuse->global->lock);
+ fuse_reply(fuse, unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
+ const char* path)
+{
+ struct fuse_attr_out out;
+ struct stat s;
+
+ if (lstat(path, &s) < 0) {
+ return -errno;
+ }
+ memset(&out, 0, sizeof(out));
+ attr_from_stat(fuse, &out.attr, &s, node);
+ out.attr_valid = 10;
+ fuse_reply(fuse, unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
+ const __u64 child, const char* name) {
+ struct fuse_out_header hdr;
+ struct fuse_notify_delete_out data;
+ struct iovec vec[3];
+ size_t namelen = strlen(name);
+ int res;
+
+ hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
+ hdr.error = FUSE_NOTIFY_DELETE;
+ hdr.unique = 0;
+
+ data.parent = parent;
+ data.child = child;
+ data.namelen = namelen;
+ data.padding = 0;
+
+ vec[0].iov_base = &hdr;
+ vec[0].iov_len = sizeof(hdr);
+ vec[1].iov_base = &data;
+ vec[1].iov_len = sizeof(data);
+ vec[2].iov_base = (void*) name;
+ vec[2].iov_len = namelen + 1;
+
+ res = writev(fuse->fd, vec, 3);
+ /* Ignore ENOENT, since other views may not have seen the entry */
+ if (res < 0 && errno != ENOENT) {
+ PLOG(ERROR) << "*** NOTIFY FAILED ***";
+ }
+}
+
+static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+ const char* actual_name;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ DLOG(INFO) << "[" << handler->token << "] LOOKUP " << name << " @ " << hdr->nodeid
+ << " (" << (parent_node ? parent_node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1))) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
+ return -EACCES;
+ }
+
+ return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
+{
+ struct node* node;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = lookup_node_by_id_locked(fuse, hdr->nodeid);
+ DLOG(INFO) << "[" << handler->token << "] FORGET #" << req->nlookup
+ << " @ " << std::hex << hdr->nodeid
+ << " (" << (node ? node->name : "?") << ")";
+ if (node) {
+ __u64 n = req->nlookup;
+ while (n) {
+ n--;
+ release_node_locked(node);
+ }
+ }
+ pthread_mutex_unlock(&fuse->global->lock);
+ return NO_STATUS; /* no reply */
+}
+
+static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ DLOG(INFO) << "[" << handler->token << "] GETATTR flags=" << req->getattr_flags
+ << " fh=" << std::hex << req->fh << " @ " << hdr->nodeid << std::dec
+ << " (" << (node ? node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+ return -EACCES;
+ }
+
+ return fuse_reply_attr(fuse, hdr->unique, node, path);
+}
+
+static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ struct timespec times[2];
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ DLOG(INFO) << "[" << handler->token << "] SETATTR fh=" << std::hex << req->fh
+ << " valid=" << std::hex << req->valid << " @ " << hdr->nodeid << std::dec
+ << " (" << (node ? node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+
+ if (!(req->valid & FATTR_FH) &&
+ !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
+ return -EACCES;
+ }
+
+ /* XXX: incomplete implementation on purpose.
+ * chmod/chown should NEVER be implemented.*/
+
+ if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
+ return -errno;
+ }
+
+ /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW
+ * are both set, then set it to the current time. Else, set it to the
+ * time specified in the request. Same goes for mtime. Use utimensat(2)
+ * as it allows ATIME and MTIME to be changed independently, and has
+ * nanosecond resolution which fuse also has.
+ */
+ if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
+ times[0].tv_nsec = UTIME_OMIT;
+ times[1].tv_nsec = UTIME_OMIT;
+ if (req->valid & FATTR_ATIME) {
+ if (req->valid & FATTR_ATIME_NOW) {
+ times[0].tv_nsec = UTIME_NOW;
+ } else {
+ times[0].tv_sec = req->atime;
+ times[0].tv_nsec = req->atimensec;
+ }
+ }
+ if (req->valid & FATTR_MTIME) {
+ if (req->valid & FATTR_MTIME_NOW) {
+ times[1].tv_nsec = UTIME_NOW;
+ } else {
+ times[1].tv_sec = req->mtime;
+ times[1].tv_nsec = req->mtimensec;
+ }
+ }
+ DLOG(INFO) << "[" << handler->token << "] Calling utimensat on " << path
+ << " with atime " << times[0].tv_sec << ", mtime=" << times[1].tv_sec;
+ if (utimensat(-1, path, times, 0) < 0) {
+ return -errno;
+ }
+ }
+ return fuse_reply_attr(fuse, hdr->unique, node, path);
+}
+
+static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+ const char* actual_name;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ DLOG(INFO) << "[" << handler->token << "] MKNOD " << name << " 0" << std::oct << req->mode
+ << " @ " << std::hex << hdr->nodeid
+ << " (" << (parent_node ? parent_node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1))) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+ return -EACCES;
+ }
+ __u32 mode = (req->mode & (~0777)) | 0664;
+ if (mknod(child_path, mode, req->rdev) < 0) {
+ return -errno;
+ }
+ return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
+{
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+ const char* actual_name;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ DLOG(INFO) << "[" << handler->token << "] MKDIR " << name << " 0" << std::oct << req->mode
+ << " @ " << std::hex << hdr->nodeid
+ << " (" << (parent_node ? parent_node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!parent_node || !(actual_name = find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1))) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+ return -EACCES;
+ }
+ __u32 mode = (req->mode & (~0777)) | 0775;
+ if (mkdir(child_path, mode) < 0) {
+ return -errno;
+ }
+
+ /* When creating /Android/data and /Android/obb, mark them as .nomedia */
+ if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
+ char nomedia[PATH_MAX];
+ snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
+ if (touch(nomedia, 0664) != 0) {
+ PLOG(ERROR) << "touch(" << nomedia << ") failed";
+ return -ENOENT;
+ }
+ }
+ if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
+ char nomedia[PATH_MAX];
+ snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
+ if (touch(nomedia, 0664) != 0) {
+ PLOG(ERROR) << "touch(" << nomedia << ") failed";
+ return -ENOENT;
+ }
+ }
+
+ return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
+}
+
+static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const char* name)
+{
+ struct node* parent_node;
+ struct node* child_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+
+ pthread_mutex_lock(&fuse->global->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
+ << " (" << (parent_node ? parent_node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!parent_node || !find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1)) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+ return -EACCES;
+ }
+ if (unlink(child_path) < 0) {
+ return -errno;
+ }
+ pthread_mutex_lock(&fuse->global->lock);
+ child_node = lookup_child_by_name_locked(parent_node, name);
+ if (child_node) {
+ child_node->deleted = true;
+ }
+ pthread_mutex_unlock(&fuse->global->lock);
+ if (parent_node && child_node) {
+ /* Tell all other views that node is gone */
+ DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
+ << " parent=" << std::hex << parent_node->nid
+ << ", child=" << std::hex << child_node->nid << std::dec
+ << ", name=" << name;
+ if (fuse != fuse->global->fuse_default) {
+ fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_read) {
+ fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_write) {
+ fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+ }
+ }
+ return 0;
+}
+
+static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const char* name)
+{
+ struct node* child_node;
+ struct node* parent_node;
+ char parent_path[PATH_MAX];
+ char child_path[PATH_MAX];
+
+ pthread_mutex_lock(&fuse->global->lock);
+ parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ parent_path, sizeof(parent_path));
+ DLOG(INFO) << "[" << handler->token << "] UNLINK " << name << " @ " << std::hex << hdr->nodeid
+ << " (" << (parent_node ? parent_node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!parent_node || !find_file_within(parent_path, name,
+ child_path, sizeof(child_path), 1)) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
+ return -EACCES;
+ }
+ if (rmdir(child_path) < 0) {
+ return -errno;
+ }
+ pthread_mutex_lock(&fuse->global->lock);
+ child_node = lookup_child_by_name_locked(parent_node, name);
+ if (child_node) {
+ child_node->deleted = true;
+ }
+ pthread_mutex_unlock(&fuse->global->lock);
+ if (parent_node && child_node) {
+ /* Tell all other views that node is gone */
+ DLOG(INFO) << "[" << handler->token << "] fuse_notify_delete"
+ << " parent=" << std::hex << parent_node->nid
+ << ", child=" << std::hex << child_node->nid << std::dec
+ << ", name=" << name;
+ if (fuse != fuse->global->fuse_default) {
+ fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_read) {
+ fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
+ }
+ if (fuse != fuse->global->fuse_write) {
+ fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
+ }
+ }
+ return 0;
+}
+
+static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
+ const char* old_name, const char* new_name)
+{
+ struct node* old_parent_node;
+ struct node* new_parent_node;
+ struct node* child_node;
+ char old_parent_path[PATH_MAX];
+ char new_parent_path[PATH_MAX];
+ char old_child_path[PATH_MAX];
+ char new_child_path[PATH_MAX];
+ const char* new_actual_name;
+ int search;
+ int res;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ old_parent_path, sizeof(old_parent_path));
+ new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
+ new_parent_path, sizeof(new_parent_path));
+ DLOG(INFO) << "[" << handler->token << "] RENAME " << old_name << "->" << new_name
+ << " @ " << std::hex << hdr->nodeid
+ << " (" << (old_parent_node ? old_parent_node->name : "?") << ") -> "
+ << std::hex << req->newdir
+ << " (" << (new_parent_node ? new_parent_node->name : "?") << ")";
+ if (!old_parent_node || !new_parent_node) {
+ res = -ENOENT;
+ goto lookup_error;
+ }
+ if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
+ res = -EACCES;
+ goto lookup_error;
+ }
+ if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
+ res = -EACCES;
+ goto lookup_error;
+ }
+ child_node = lookup_child_by_name_locked(old_parent_node, old_name);
+ if (!child_node || get_node_path_locked(child_node,
+ old_child_path, sizeof(old_child_path)) < 0) {
+ res = -ENOENT;
+ goto lookup_error;
+ }
+ acquire_node_locked(child_node);
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ /* Special case for renaming a file where destination is same path
+ * differing only by case. In this case we don't want to look for a case
+ * insensitive match. This allows commands like "mv foo FOO" to work as expected.
+ */
+ search = old_parent_node != new_parent_node
+ || strcasecmp(old_name, new_name);
+ if (!(new_actual_name = find_file_within(new_parent_path, new_name,
+ new_child_path, sizeof(new_child_path), search))) {
+ res = -ENOENT;
+ goto io_error;
+ }
+
+ DLOG(INFO) << "[" << handler->token << "] RENAME " << old_child_path << "->" << new_child_path;
+ res = rename(old_child_path, new_child_path);
+ if (res < 0) {
+ res = -errno;
+ goto io_error;
+ }
+
+ pthread_mutex_lock(&fuse->global->lock);
+ res = rename_node_locked(child_node, new_name, new_actual_name);
+ if (!res) {
+ remove_node_from_parent_locked(child_node);
+ derive_permissions_locked(fuse, new_parent_node, child_node);
+ derive_permissions_recursive_locked(fuse, child_node);
+ add_node_to_parent_locked(child_node, new_parent_node);
+ }
+ goto done;
+
+io_error:
+ pthread_mutex_lock(&fuse->global->lock);
+done:
+ release_node_locked(child_node);
+lookup_error:
+ pthread_mutex_unlock(&fuse->global->lock);
+ return res;
+}
+
+static int open_flags_to_access_mode(int open_flags) {
+ if ((open_flags & O_ACCMODE) == O_RDONLY) {
+ return R_OK;
+ } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
+ return W_OK;
+ } else {
+ /* Probably O_RDRW, but treat as default to be safe */
+ return R_OK | W_OK;
+ }
+}
+
+static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_open_in* req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ struct fuse_open_out out;
+ struct handle *h;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ DLOG(INFO) << "[" << handler->token << "] OPEN 0" << std::oct << req->flags
+ << " @ " << std::hex << hdr->nodeid << std::dec
+ << " (" << (node ? node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_node(fuse, hdr, node,
+ open_flags_to_access_mode(req->flags))) {
+ return -EACCES;
+ }
+ h = static_cast<struct handle*>(malloc(sizeof(*h)));
+ if (!h) {
+ return -ENOMEM;
+ }
+ DLOG(INFO) << "[" << handler->token << "] OPEN " << path;
+ h->fd = open(path, req->flags);
+ if (h->fd < 0) {
+ free(h);
+ return -errno;
+ }
+ out.fh = ptr_to_id(h);
+ out.open_flags = 0;
+ out.padding = 0;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_read_in* req)
+{
+ struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+ __u64 unique = hdr->unique;
+ __u32 size = req->size;
+ __u64 offset = req->offset;
+ int res;
+ __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
+
+ /* Don't access any other fields of hdr or req beyond this point, the read buffer
+ * overlaps the request buffer and will clobber data in the request. This
+ * saves us 128KB per request handler thread at the cost of this scary comment. */
+
+ DLOG(INFO) << "[" << handler->token << "] READ " << std::hex << h << std::dec
+ << "(" << h->fd << ") " << size << "@" << offset;
+ if (size > MAX_READ) {
+ return -EINVAL;
+ }
+ res = pread64(h->fd, read_buffer, size, offset);
+ if (res < 0) {
+ return -errno;
+ }
+ fuse_reply(fuse, unique, read_buffer, res);
+ return NO_STATUS;
+}
+
+static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_write_in* req,
+ const void* buffer)
+{
+ struct fuse_write_out out;
+ struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+ int res;
+ __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
+
+ if (req->flags & O_DIRECT) {
+ memcpy(aligned_buffer, buffer, req->size);
+ buffer = (const __u8*) aligned_buffer;
+ }
+
+ DLOG(INFO) << "[" << handler->token << "] WRITE " << std::hex << h << std::dec
+ << "(" << h->fd << ") " << req->size << "@" << req->offset;
+ res = pwrite64(h->fd, buffer, req->size, req->offset);
+ if (res < 0) {
+ return -errno;
+ }
+ out.size = res;
+ out.padding = 0;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr)
+{
+ char path[PATH_MAX];
+ struct statfs stat;
+ struct fuse_statfs_out out;
+ int res;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ DLOG(INFO) << "[" << handler->token << "] STATFS";
+ res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
+ pthread_mutex_unlock(&fuse->global->lock);
+ if (res < 0) {
+ return -ENOENT;
+ }
+ if (statfs(fuse->global->root.name, &stat) < 0) {
+ return -errno;
+ }
+ memset(&out, 0, sizeof(out));
+ out.st.blocks = stat.f_blocks;
+ out.st.bfree = stat.f_bfree;
+ out.st.bavail = stat.f_bavail;
+ out.st.files = stat.f_files;
+ out.st.ffree = stat.f_ffree;
+ out.st.bsize = stat.f_bsize;
+ out.st.namelen = stat.f_namelen;
+ out.st.frsize = stat.f_frsize;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_release_in* req)
+{
+ struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+
+ DLOG(INFO) << "[" << handler->token << "] RELEASE " << std::hex << h << std::dec
+ << "(" << h->fd << ")";
+ close(h->fd);
+ free(h);
+ return 0;
+}
+
+static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
+{
+ bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
+ bool is_data_sync = req->fsync_flags & 1;
+
+ int fd = -1;
+ if (is_dir) {
+ struct dirhandle *dh = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
+ fd = dirfd(dh->d);
+ } else {
+ struct handle *h = static_cast<struct handle*>(id_to_ptr(req->fh));
+ fd = h->fd;
+ }
+
+ DLOG(INFO) << "[" << handler->token << "] " << (is_dir ? "FSYNCDIR" : "FSYNC") << " "
+ << std::hex << req->fh << std::dec << "(" << fd << ") is_data_sync=" << is_data_sync;
+ int res = is_data_sync ? fdatasync(fd) : fsync(fd);
+ if (res == -1) {
+ return -errno;
+ }
+ return 0;
+}
+
+static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr)
+{
+ DLOG(INFO) << "[" << handler->token << "] FLUSH";
+ return 0;
+}
+
+static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_open_in* req)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ struct fuse_open_out out;
+ struct dirhandle *h;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
+ DLOG(INFO) << "[" << handler->token << "] OPENDIR @ " << std::hex << hdr->nodeid
+ << " (" << (node ? node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+ return -EACCES;
+ }
+ h = static_cast<struct dirhandle*>(malloc(sizeof(*h)));
+ if (!h) {
+ return -ENOMEM;
+ }
+ DLOG(INFO) << "[" << handler->token << "] OPENDIR " << path;
+ h->d = opendir(path);
+ if (!h->d) {
+ free(h);
+ return -errno;
+ }
+ out.fh = ptr_to_id(h);
+ out.open_flags = 0;
+ out.padding = 0;
+ fuse_reply(fuse, hdr->unique, &out, sizeof(out));
+ return NO_STATUS;
+}
+
+static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_read_in* req)
+{
+ char buffer[8192];
+ struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
+ struct dirent *de;
+ struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
+
+ DLOG(INFO) << "[" << handler->token << "] READDIR " << h;
+ if (req->offset == 0) {
+ /* rewinddir() might have been called above us, so rewind here too */
+ DLOG(INFO) << "[" << handler->token << "] calling rewinddir()";
+ rewinddir(h->d);
+ }
+ de = readdir(h->d);
+ if (!de) {
+ return 0;
+ }
+ fde->ino = FUSE_UNKNOWN_INO;
+ /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
+ fde->off = req->offset + 1;
+ fde->type = de->d_type;
+ fde->namelen = strlen(de->d_name);
+ memcpy(fde->name, de->d_name, fde->namelen + 1);
+ fuse_reply(fuse, hdr->unique, fde,
+ FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
+ return NO_STATUS;
+}
+
+static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_release_in* req)
+{
+ struct dirhandle *h = static_cast<struct dirhandle*>(id_to_ptr(req->fh));
+
+ DLOG(INFO) << "[" << handler->token << "] RELEASEDIR " << h;
+ closedir(h->d);
+ free(h);
+ return 0;
+}
+
+static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header* hdr, const struct fuse_init_in* req)
+{
+ struct fuse_init_out out;
+ size_t fuse_struct_size;
+
+ DLOG(INFO) << "[" << handler->token << "] INIT ver=" << req->major << "." << req->minor
+ << " maxread=" << req->max_readahead << " flags=" << std::hex << req->flags;
+
+ /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
+ * defined (fuse version 7.6). The structure is the same from 7.6 through
+ * 7.22. Beginning with 7.23, the structure increased in size and added
+ * new parameters.
+ */
+ if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
+ LOG(ERROR) << "Fuse kernel version mismatch: Kernel version "
+ << req->major << "." << req->minor
+ << ", Expected at least " << FUSE_KERNEL_VERSION << ".6";
+ return -1;
+ }
+
+ /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
+ out.minor = MIN(req->minor, 15);
+ fuse_struct_size = sizeof(out);
+#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
+ /* FUSE_KERNEL_VERSION >= 23. */
+
+ /* If the kernel only works on minor revs older than or equal to 22,
+ * then use the older structure size since this code only uses the 7.22
+ * version of the structure. */
+ if (req->minor <= 22) {
+ fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
+ }
+#endif
+
+ out.major = FUSE_KERNEL_VERSION;
+ out.max_readahead = req->max_readahead;
+ out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
+ out.max_background = 32;
+ out.congestion_threshold = 32;
+ out.max_write = MAX_WRITE;
+ fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
+ return NO_STATUS;
+}
+
+static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr)
+{
+ struct node* node;
+ char path[PATH_MAX];
+ int len;
+
+ pthread_mutex_lock(&fuse->global->lock);
+ node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
+ path, sizeof(path));
+ DLOG(INFO) << "[" << handler->token << "] CANONICAL_PATH @ " << std::hex << hdr->nodeid
+ << std::dec << " (" << (node ? node->name : "?") << ")";
+ pthread_mutex_unlock(&fuse->global->lock);
+
+ if (!node) {
+ return -ENOENT;
+ }
+ if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
+ return -EACCES;
+ }
+ len = strlen(path);
+ if (len + 1 > PATH_MAX)
+ len = PATH_MAX - 1;
+ path[PATH_MAX - 1] = 0;
+ fuse_reply(fuse, hdr->unique, path, len + 1);
+ return NO_STATUS;
+}
+
+
+static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
+ const struct fuse_in_header *hdr, const void *data, size_t data_len)
+{
+ switch (hdr->opcode) {
+ case FUSE_LOOKUP: { /* bytez[] -> entry_out */
+ const char *name = static_cast<const char*>(data);
+ return handle_lookup(fuse, handler, hdr, name);
+ }
+
+ case FUSE_FORGET: {
+ const struct fuse_forget_in *req = static_cast<const struct fuse_forget_in*>(data);
+ return handle_forget(fuse, handler, hdr, req);
+ }
+
+ case FUSE_GETATTR: { /* getattr_in -> attr_out */
+ const struct fuse_getattr_in *req = static_cast<const struct fuse_getattr_in*>(data);
+ return handle_getattr(fuse, handler, hdr, req);
+ }
+
+ case FUSE_SETATTR: { /* setattr_in -> attr_out */
+ const struct fuse_setattr_in *req = static_cast<const struct fuse_setattr_in*>(data);
+ return handle_setattr(fuse, handler, hdr, req);
+ }
+
+// case FUSE_READLINK:
+// case FUSE_SYMLINK:
+ case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
+ const struct fuse_mknod_in *req = static_cast<const struct fuse_mknod_in*>(data);
+ const char *name = ((const char*) data) + sizeof(*req);
+ return handle_mknod(fuse, handler, hdr, req, name);
+ }
+
+ case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
+ const struct fuse_mkdir_in *req = static_cast<const struct fuse_mkdir_in*>(data);
+ const char *name = ((const char*) data) + sizeof(*req);
+ return handle_mkdir(fuse, handler, hdr, req, name);
+ }
+
+ case FUSE_UNLINK: { /* bytez[] -> */
+ const char *name = static_cast<const char*>(data);
+ return handle_unlink(fuse, handler, hdr, name);
+ }
+
+ case FUSE_RMDIR: { /* bytez[] -> */
+ const char *name = static_cast<const char*>(data);
+ return handle_rmdir(fuse, handler, hdr, name);
+ }
+
+ case FUSE_RENAME: { /* rename_in, oldname, newname -> */
+ const struct fuse_rename_in *req = static_cast<const struct fuse_rename_in*>(data);
+ const char *old_name = ((const char*) data) + sizeof(*req);
+ const char *new_name = old_name + strlen(old_name) + 1;
+ return handle_rename(fuse, handler, hdr, req, old_name, new_name);
+ }
+
+// case FUSE_LINK:
+ case FUSE_OPEN: { /* open_in -> open_out */
+ const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
+ return handle_open(fuse, handler, hdr, req);
+ }
+
+ case FUSE_READ: { /* read_in -> byte[] */
+ const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
+ return handle_read(fuse, handler, hdr, req);
+ }
+
+ case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
+ const struct fuse_write_in *req = static_cast<const struct fuse_write_in*>(data);
+ const void* buffer = (const __u8*)data + sizeof(*req);
+ return handle_write(fuse, handler, hdr, req, buffer);
+ }
+
+ case FUSE_STATFS: { /* getattr_in -> attr_out */
+ return handle_statfs(fuse, handler, hdr);
+ }
+
+ case FUSE_RELEASE: { /* release_in -> */
+ const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
+ return handle_release(fuse, handler, hdr, req);
+ }
+
+ case FUSE_FSYNC:
+ case FUSE_FSYNCDIR: {
+ const struct fuse_fsync_in *req = static_cast<const struct fuse_fsync_in*>(data);
+ return handle_fsync(fuse, handler, hdr, req);
+ }
+
+// case FUSE_SETXATTR:
+// case FUSE_GETXATTR:
+// case FUSE_LISTXATTR:
+// case FUSE_REMOVEXATTR:
+ case FUSE_FLUSH: {
+ return handle_flush(fuse, handler, hdr);
+ }
+
+ case FUSE_OPENDIR: { /* open_in -> open_out */
+ const struct fuse_open_in *req = static_cast<const struct fuse_open_in*>(data);
+ return handle_opendir(fuse, handler, hdr, req);
+ }
+
+ case FUSE_READDIR: {
+ const struct fuse_read_in *req = static_cast<const struct fuse_read_in*>(data);
+ return handle_readdir(fuse, handler, hdr, req);
+ }
+
+ case FUSE_RELEASEDIR: { /* release_in -> */
+ const struct fuse_release_in *req = static_cast<const struct fuse_release_in*>(data);
+ return handle_releasedir(fuse, handler, hdr, req);
+ }
+
+ case FUSE_INIT: { /* init_in -> init_out */
+ const struct fuse_init_in *req = static_cast<const struct fuse_init_in*>(data);
+ return handle_init(fuse, handler, hdr, req);
+ }
+
+ case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
+ return handle_canonical_path(fuse, handler, hdr);
+ }
+
+ default: {
+ DLOG(INFO) << "[" << handler->token << "] NOTIMPL op=" << hdr->opcode
+ << "uniq=" << std::hex << hdr->unique << "nid=" << hdr->nodeid << std::dec;
+ return -ENOSYS;
+ }
+ }
+}
+
+void handle_fuse_requests(struct fuse_handler* handler)
+{
+ struct fuse* fuse = handler->fuse;
+ for (;;) {
+ ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
+ handler->request_buffer, sizeof(handler->request_buffer)));
+ if (len < 0) {
+ if (errno == ENODEV) {
+ LOG(ERROR) << "[" << handler->token << "] someone stole our marbles!";
+ exit(2);
+ }
+ PLOG(ERROR) << "[" << handler->token << "] handle_fuse_requests";
+ continue;
+ }
+
+ if ((size_t)len < sizeof(struct fuse_in_header)) {
+ LOG(ERROR) << "[" << handler->token << "] request too short: len=" << len;
+ continue;
+ }
+
+ const struct fuse_in_header* hdr =
+ reinterpret_cast<const struct fuse_in_header*>(handler->request_buffer);
+ if (hdr->len != (size_t)len) {
+ LOG(ERROR) << "[" << handler->token << "] malformed header: len=" << len
+ << ", hdr->len=" << hdr->len;
+ continue;
+ }
+
+ const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
+ size_t data_len = len - sizeof(struct fuse_in_header);
+ __u64 unique = hdr->unique;
+ int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
+
+ /* We do not access the request again after this point because the underlying
+ * buffer storage may have been reused while processing the request. */
+
+ if (res != NO_STATUS) {
+ if (res) {
+ DLOG(INFO) << "[" << handler->token << "] ERROR " << res;
+ }
+ fuse_status(fuse, unique, res);
+ }
+ }
+}
diff --git a/sdcard/fuse.h b/sdcard/fuse.h
new file mode 100644
index 0000000..9ccd21d
--- /dev/null
+++ b/sdcard/fuse.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2016 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 FUSE_H_
+#define FUSE_H_
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <linux/fuse.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+
+#include <android-base/logging.h>
+#include <cutils/fs.h>
+#include <cutils/multiuser.h>
+#include <packagelistparser/packagelistparser.h>
+
+#include <private/android_filesystem_config.h>
+
+#define FUSE_TRACE 0
+
+#if FUSE_TRACE
+static constexpr bool kEnableDLog = true;
+#else // FUSE_TRACE == 0
+static constexpr bool kEnableDLog = false;
+#endif
+
+// Use same strategy as DCHECK().
+#define DLOG(x) \
+ if (kEnableDLog) LOG(x)
+
+/* Maximum number of bytes to write in one request. */
+#define MAX_WRITE (256 * 1024)
+
+/* Maximum number of bytes to read in one request. */
+#define MAX_READ (128 * 1024)
+
+/* Largest possible request.
+ * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
+ * the largest possible data payload. */
+#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
+
+namespace {
+struct CaseInsensitiveCompare {
+ bool operator()(const std::string& lhs, const std::string& rhs) const {
+ return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
+ }
+};
+}
+
+using AppIdMap = std::map<std::string, appid_t, CaseInsensitiveCompare>;
+
+/* Permission mode for a specific node. Controls how file permissions
+ * are derived for children nodes. */
+typedef enum {
+ /* Nothing special; this node should just inherit from its parent. */
+ PERM_INHERIT,
+ /* This node is one level above a normal root; used for legacy layouts
+ * which use the first level to represent user_id. */
+ PERM_PRE_ROOT,
+ /* This node is "/" */
+ PERM_ROOT,
+ /* This node is "/Android" */
+ PERM_ANDROID,
+ /* This node is "/Android/data" */
+ PERM_ANDROID_DATA,
+ /* This node is "/Android/obb" */
+ PERM_ANDROID_OBB,
+ /* This node is "/Android/media" */
+ PERM_ANDROID_MEDIA,
+} perm_t;
+
+struct handle {
+ int fd;
+};
+
+struct dirhandle {
+ DIR *d;
+};
+
+struct node {
+ __u32 refcount;
+ __u64 nid;
+ __u64 gen;
+ /*
+ * The inode number for this FUSE node. Note that this isn't stable across
+ * multiple invocations of the FUSE daemon.
+ */
+ __u32 ino;
+
+ /* State derived based on current position in hierarchy. */
+ perm_t perm;
+ userid_t userid;
+ uid_t uid;
+ bool under_android;
+
+ struct node *next; /* per-dir sibling list */
+ struct node *child; /* first contained file by this dir */
+ struct node *parent; /* containing directory */
+
+ size_t namelen;
+ char *name;
+ /* If non-null, this is the real name of the file in the underlying storage.
+ * This may differ from the field "name" only by case.
+ * strlen(actual_name) will always equal strlen(name), so it is safe to use
+ * namelen for both fields.
+ */
+ char *actual_name;
+
+ /* If non-null, an exact underlying path that should be grafted into this
+ * position. Used to support things like OBB. */
+ char* graft_path;
+ size_t graft_pathlen;
+
+ bool deleted;
+};
+
+/* Global data for all FUSE mounts */
+struct fuse_global {
+ pthread_mutex_t lock;
+
+ uid_t uid;
+ gid_t gid;
+ bool multi_user;
+
+ char source_path[PATH_MAX];
+ char obb_path[PATH_MAX];
+
+ AppIdMap* package_to_appid;
+
+ __u64 next_generation;
+ struct node root;
+
+ /* Used to allocate unique inode numbers for fuse nodes. We use
+ * a simple counter based scheme where inode numbers from deleted
+ * nodes aren't reused. Note that inode allocations are not stable
+ * across multiple invocation of the sdcard daemon, but that shouldn't
+ * be a huge problem in practice.
+ *
+ * Note that we restrict inodes to 32 bit unsigned integers to prevent
+ * truncation on 32 bit processes when unsigned long long stat.st_ino is
+ * assigned to an unsigned long ino_t type in an LP32 process.
+ *
+ * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
+ * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
+ * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
+ * in fs/fuse/inode.c).
+ *
+ * Accesses must be guarded by |lock|.
+ */
+ __u32 inode_ctr;
+
+ struct fuse* fuse_default;
+ struct fuse* fuse_read;
+ struct fuse* fuse_write;
+};
+
+/* Single FUSE mount */
+struct fuse {
+ struct fuse_global* global;
+
+ char dest_path[PATH_MAX];
+
+ int fd;
+
+ gid_t gid;
+ mode_t mask;
+};
+
+/* Private data used by a single FUSE handler */
+struct fuse_handler {
+ struct fuse* fuse;
+ int token;
+
+ /* To save memory, we never use the contents of the request buffer and the read
+ * buffer at the same time. This allows us to share the underlying storage. */
+ union {
+ __u8 request_buffer[MAX_REQUEST_SIZE];
+ __u8 read_buffer[MAX_READ + PAGE_SIZE];
+ };
+};
+
+void handle_fuse_requests(struct fuse_handler* handler);
+void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent);
+
+#endif /* FUSE_H_ */
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
deleted file mode 100644
index 9480e4a..0000000
--- a/sdcard/sdcard.c
+++ /dev/null
@@ -1,2137 +0,0 @@
-/*
- * Copyright (C) 2010 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 "sdcard"
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <linux/fuse.h>
-#include <pthread.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/inotify.h>
-#include <sys/mount.h>
-#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <cutils/fs.h>
-#include <cutils/hashmap.h>
-#include <cutils/log.h>
-#include <cutils/multiuser.h>
-#include <cutils/properties.h>
-#include <packagelistparser/packagelistparser.h>
-
-#include <private/android_filesystem_config.h>
-
-/* FUSE_CANONICAL_PATH is not currently upstreamed */
-#define FUSE_CANONICAL_PATH 2016
-
-/* README
- *
- * What is this?
- *
- * sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
- * directory permissions (all files are given fixed owner, group, and
- * permissions at creation, owner, group, and permissions are not
- * changeable, symlinks and hardlinks are not createable, etc.
- *
- * See usage() for command line options.
- *
- * It must be run as root, but will drop to requested UID/GID as soon as it
- * mounts a filesystem. It will refuse to run if requested UID/GID are zero.
- *
- * Things I believe to be true:
- *
- * - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
- * CREAT) must bump that node's refcount
- * - don't forget that FORGET can forget multiple references (req->nlookup)
- * - if an op that returns a fuse_entry fails writing the reply to the
- * kernel, you must rollback the refcount to reflect the reference the
- * kernel did not actually acquire
- *
- * This daemon can also derive custom filesystem permissions based on directory
- * structure when requested. These custom permissions support several features:
- *
- * - Apps can access their own files in /Android/data/com.example/ without
- * requiring any additional GIDs.
- * - Separate permissions for protecting directories like Pictures and Music.
- * - Multi-user separation on the same physical device.
- */
-
-#define FUSE_TRACE 0
-
-#if FUSE_TRACE
-#define TRACE(x...) ALOGD(x)
-#else
-#define TRACE(x...) do {} while (0)
-#endif
-
-#define ERROR(x...) ALOGE(x)
-
-#define PROP_SDCARDFS_DEVICE "ro.sys.sdcardfs"
-#define PROP_SDCARDFS_USER "persist.sys.sdcardfs"
-
-#define FUSE_UNKNOWN_INO 0xffffffff
-
-/* Maximum number of bytes to write in one request. */
-#define MAX_WRITE (256 * 1024)
-
-/* Maximum number of bytes to read in one request. */
-#define MAX_READ (128 * 1024)
-
-/* Largest possible request.
- * The request size is bounded by the maximum size of a FUSE_WRITE request because it has
- * the largest possible data payload. */
-#define MAX_REQUEST_SIZE (sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE)
-
-/* Pseudo-error constant used to indicate that no fuse status is needed
- * or that a reply has already been written. */
-#define NO_STATUS 1
-
-/* Supplementary groups to execute with */
-static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
-
-/* Permission mode for a specific node. Controls how file permissions
- * are derived for children nodes. */
-typedef enum {
- /* Nothing special; this node should just inherit from its parent. */
- PERM_INHERIT,
- /* This node is one level above a normal root; used for legacy layouts
- * which use the first level to represent user_id. */
- PERM_PRE_ROOT,
- /* This node is "/" */
- PERM_ROOT,
- /* This node is "/Android" */
- PERM_ANDROID,
- /* This node is "/Android/data" */
- PERM_ANDROID_DATA,
- /* This node is "/Android/obb" */
- PERM_ANDROID_OBB,
- /* This node is "/Android/media" */
- PERM_ANDROID_MEDIA,
-} perm_t;
-
-struct handle {
- int fd;
-};
-
-struct dirhandle {
- DIR *d;
-};
-
-struct node {
- __u32 refcount;
- __u64 nid;
- __u64 gen;
- /*
- * The inode number for this FUSE node. Note that this isn't stable across
- * multiple invocations of the FUSE daemon.
- */
- __u32 ino;
-
- /* State derived based on current position in hierarchy. */
- perm_t perm;
- userid_t userid;
- uid_t uid;
- bool under_android;
-
- struct node *next; /* per-dir sibling list */
- struct node *child; /* first contained file by this dir */
- struct node *parent; /* containing directory */
-
- size_t namelen;
- char *name;
- /* If non-null, this is the real name of the file in the underlying storage.
- * This may differ from the field "name" only by case.
- * strlen(actual_name) will always equal strlen(name), so it is safe to use
- * namelen for both fields.
- */
- char *actual_name;
-
- /* If non-null, an exact underlying path that should be grafted into this
- * position. Used to support things like OBB. */
- char* graft_path;
- size_t graft_pathlen;
-
- bool deleted;
-};
-
-static int str_hash(void *key) {
- return hashmapHash(key, strlen(key));
-}
-
-/** Test if two string keys are equal ignoring case */
-static bool str_icase_equals(void *keyA, void *keyB) {
- return strcasecmp(keyA, keyB) == 0;
-}
-
-/* Global data for all FUSE mounts */
-struct fuse_global {
- pthread_mutex_t lock;
-
- uid_t uid;
- gid_t gid;
- bool multi_user;
-
- char source_path[PATH_MAX];
- char obb_path[PATH_MAX];
-
- Hashmap* package_to_appid;
-
- __u64 next_generation;
- struct node root;
-
- /* Used to allocate unique inode numbers for fuse nodes. We use
- * a simple counter based scheme where inode numbers from deleted
- * nodes aren't reused. Note that inode allocations are not stable
- * across multiple invocation of the sdcard daemon, but that shouldn't
- * be a huge problem in practice.
- *
- * Note that we restrict inodes to 32 bit unsigned integers to prevent
- * truncation on 32 bit processes when unsigned long long stat.st_ino is
- * assigned to an unsigned long ino_t type in an LP32 process.
- *
- * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide
- * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit
- * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino
- * in fs/fuse/inode.c).
- *
- * Accesses must be guarded by |lock|.
- */
- __u32 inode_ctr;
-
- struct fuse* fuse_default;
- struct fuse* fuse_read;
- struct fuse* fuse_write;
-};
-
-/* Single FUSE mount */
-struct fuse {
- struct fuse_global* global;
-
- char dest_path[PATH_MAX];
-
- int fd;
-
- gid_t gid;
- mode_t mask;
-};
-
-/* Private data used by a single FUSE handler */
-struct fuse_handler {
- struct fuse* fuse;
- int token;
-
- /* To save memory, we never use the contents of the request buffer and the read
- * buffer at the same time. This allows us to share the underlying storage. */
- union {
- __u8 request_buffer[MAX_REQUEST_SIZE];
- __u8 read_buffer[MAX_READ + PAGE_SIZE];
- };
-};
-
-static inline void *id_to_ptr(__u64 nid)
-{
- return (void *) (uintptr_t) nid;
-}
-
-static inline __u64 ptr_to_id(void *ptr)
-{
- return (__u64) (uintptr_t) ptr;
-}
-
-static void acquire_node_locked(struct node* node)
-{
- node->refcount++;
- TRACE("ACQUIRE %p (%s) rc=%d\n", node, node->name, node->refcount);
-}
-
-static void remove_node_from_parent_locked(struct node* node);
-
-static void release_node_locked(struct node* node)
-{
- TRACE("RELEASE %p (%s) rc=%d\n", node, node->name, node->refcount);
- if (node->refcount > 0) {
- node->refcount--;
- if (!node->refcount) {
- TRACE("DESTROY %p (%s)\n", node, node->name);
- remove_node_from_parent_locked(node);
-
- /* TODO: remove debugging - poison memory */
- memset(node->name, 0xef, node->namelen);
- free(node->name);
- free(node->actual_name);
- memset(node, 0xfc, sizeof(*node));
- free(node);
- }
- } else {
- ERROR("Zero refcnt %p\n", node);
- }
-}
-
-static void add_node_to_parent_locked(struct node *node, struct node *parent) {
- node->parent = parent;
- node->next = parent->child;
- parent->child = node;
- acquire_node_locked(parent);
-}
-
-static void remove_node_from_parent_locked(struct node* node)
-{
- if (node->parent) {
- if (node->parent->child == node) {
- node->parent->child = node->parent->child->next;
- } else {
- struct node *node2;
- node2 = node->parent->child;
- while (node2->next != node)
- node2 = node2->next;
- node2->next = node->next;
- }
- release_node_locked(node->parent);
- node->parent = NULL;
- node->next = NULL;
- }
-}
-
-/* Gets the absolute path to a node into the provided buffer.
- *
- * Populates 'buf' with the path and returns the length of the path on success,
- * or returns -1 if the path is too long for the provided buffer.
- */
-static ssize_t get_node_path_locked(struct node* node, char* buf, size_t bufsize) {
- const char* name;
- size_t namelen;
- if (node->graft_path) {
- name = node->graft_path;
- namelen = node->graft_pathlen;
- } else if (node->actual_name) {
- name = node->actual_name;
- namelen = node->namelen;
- } else {
- name = node->name;
- namelen = node->namelen;
- }
-
- if (bufsize < namelen + 1) {
- return -1;
- }
-
- ssize_t pathlen = 0;
- if (node->parent && node->graft_path == NULL) {
- pathlen = get_node_path_locked(node->parent, buf, bufsize - namelen - 1);
- if (pathlen < 0) {
- return -1;
- }
- buf[pathlen++] = '/';
- }
-
- memcpy(buf + pathlen, name, namelen + 1); /* include trailing \0 */
- return pathlen + namelen;
-}
-
-/* Finds the absolute path of a file within a given directory.
- * Performs a case-insensitive search for the file and sets the buffer to the path
- * of the first matching file. If 'search' is zero or if no match is found, sets
- * the buffer to the path that the file would have, assuming the name were case-sensitive.
- *
- * Populates 'buf' with the path and returns the actual name (within 'buf') on success,
- * or returns NULL if the path is too long for the provided buffer.
- */
-static char* find_file_within(const char* path, const char* name,
- char* buf, size_t bufsize, int search)
-{
- size_t pathlen = strlen(path);
- size_t namelen = strlen(name);
- size_t childlen = pathlen + namelen + 1;
- char* actual;
-
- if (bufsize <= childlen) {
- return NULL;
- }
-
- memcpy(buf, path, pathlen);
- buf[pathlen] = '/';
- actual = buf + pathlen + 1;
- memcpy(actual, name, namelen + 1);
-
- if (search && access(buf, F_OK)) {
- struct dirent* entry;
- DIR* dir = opendir(path);
- if (!dir) {
- ERROR("opendir %s failed: %s\n", path, strerror(errno));
- return actual;
- }
- while ((entry = readdir(dir))) {
- if (!strcasecmp(entry->d_name, name)) {
- /* we have a match - replace the name, don't need to copy the null again */
- memcpy(actual, entry->d_name, namelen);
- break;
- }
- }
- closedir(dir);
- }
- return actual;
-}
-
-static void attr_from_stat(struct fuse* fuse, struct fuse_attr *attr,
- const struct stat *s, const struct node* node) {
- attr->ino = node->ino;
- attr->size = s->st_size;
- attr->blocks = s->st_blocks;
- attr->atime = s->st_atim.tv_sec;
- attr->mtime = s->st_mtim.tv_sec;
- attr->ctime = s->st_ctim.tv_sec;
- attr->atimensec = s->st_atim.tv_nsec;
- attr->mtimensec = s->st_mtim.tv_nsec;
- attr->ctimensec = s->st_ctim.tv_nsec;
- attr->mode = s->st_mode;
- attr->nlink = s->st_nlink;
-
- attr->uid = node->uid;
-
- if (fuse->gid == AID_SDCARD_RW) {
- /* As an optimization, certain trusted system components only run
- * as owner but operate across all users. Since we're now handing
- * out the sdcard_rw GID only to trusted apps, we're okay relaxing
- * the user boundary enforcement for the default view. The UIDs
- * assigned to app directories are still multiuser aware. */
- attr->gid = AID_SDCARD_RW;
- } else {
- attr->gid = multiuser_get_uid(node->userid, fuse->gid);
- }
-
- int visible_mode = 0775 & ~fuse->mask;
- if (node->perm == PERM_PRE_ROOT) {
- /* Top of multi-user view should always be visible to ensure
- * secondary users can traverse inside. */
- visible_mode = 0711;
- } else if (node->under_android) {
- /* Block "other" access to Android directories, since only apps
- * belonging to a specific user should be in there; we still
- * leave +x open for the default view. */
- if (fuse->gid == AID_SDCARD_RW) {
- visible_mode = visible_mode & ~0006;
- } else {
- visible_mode = visible_mode & ~0007;
- }
- }
- int owner_mode = s->st_mode & 0700;
- int filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
- attr->mode = (attr->mode & S_IFMT) | filtered_mode;
-}
-
-static int touch(char* path, mode_t mode) {
- int fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, mode);
- if (fd == -1) {
- if (errno == EEXIST) {
- return 0;
- } else {
- ERROR("Failed to open(%s): %s\n", path, strerror(errno));
- return -1;
- }
- }
- close(fd);
- return 0;
-}
-
-static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
- struct node *node) {
- appid_t appid;
-
- /* By default, each node inherits from its parent */
- node->perm = PERM_INHERIT;
- node->userid = parent->userid;
- node->uid = parent->uid;
- node->under_android = parent->under_android;
-
- /* Derive custom permissions based on parent and current node */
- switch (parent->perm) {
- case PERM_INHERIT:
- /* Already inherited above */
- break;
- case PERM_PRE_ROOT:
- /* Legacy internal layout places users at top level */
- node->perm = PERM_ROOT;
- node->userid = strtoul(node->name, NULL, 10);
- break;
- case PERM_ROOT:
- /* Assume masked off by default. */
- if (!strcasecmp(node->name, "Android")) {
- /* App-specific directories inside; let anyone traverse */
- node->perm = PERM_ANDROID;
- node->under_android = true;
- }
- break;
- case PERM_ANDROID:
- if (!strcasecmp(node->name, "data")) {
- /* App-specific directories inside; let anyone traverse */
- node->perm = PERM_ANDROID_DATA;
- } else if (!strcasecmp(node->name, "obb")) {
- /* App-specific directories inside; let anyone traverse */
- node->perm = PERM_ANDROID_OBB;
- /* Single OBB directory is always shared */
- node->graft_path = fuse->global->obb_path;
- node->graft_pathlen = strlen(fuse->global->obb_path);
- } else if (!strcasecmp(node->name, "media")) {
- /* App-specific directories inside; let anyone traverse */
- node->perm = PERM_ANDROID_MEDIA;
- }
- break;
- case PERM_ANDROID_DATA:
- case PERM_ANDROID_OBB:
- case PERM_ANDROID_MEDIA:
- appid = (appid_t) (uintptr_t) hashmapGet(fuse->global->package_to_appid, node->name);
- if (appid != 0) {
- node->uid = multiuser_get_uid(parent->userid, appid);
- }
- break;
- }
-}
-
-static void derive_permissions_recursive_locked(struct fuse* fuse, struct node *parent) {
- struct node *node;
- for (node = parent->child; node; node = node->next) {
- derive_permissions_locked(fuse, parent, node);
- if (node->child) {
- derive_permissions_recursive_locked(fuse, node);
- }
- }
-}
-
-/* Kernel has already enforced everything we returned through
- * derive_permissions_locked(), so this is used to lock down access
- * even further, such as enforcing that apps hold sdcard_rw. */
-static bool check_caller_access_to_name(struct fuse* fuse,
- const struct fuse_in_header *hdr, const struct node* parent_node,
- const char* name, int mode) {
- /* Always block security-sensitive files at root */
- if (parent_node && parent_node->perm == PERM_ROOT) {
- if (!strcasecmp(name, "autorun.inf")
- || !strcasecmp(name, ".android_secure")
- || !strcasecmp(name, "android_secure")) {
- return false;
- }
- }
-
- /* Root always has access; access for any other UIDs should always
- * be controlled through packages.list. */
- if (hdr->uid == 0) {
- return true;
- }
-
- /* No extra permissions to enforce */
- return true;
-}
-
-static bool check_caller_access_to_node(struct fuse* fuse,
- const struct fuse_in_header *hdr, const struct node* node, int mode) {
- return check_caller_access_to_name(fuse, hdr, node->parent, node->name, mode);
-}
-
-struct node *create_node_locked(struct fuse* fuse,
- struct node *parent, const char *name, const char* actual_name)
-{
- struct node *node;
- size_t namelen = strlen(name);
-
- // Detect overflows in the inode counter. "4 billion nodes should be enough
- // for everybody".
- if (fuse->global->inode_ctr == 0) {
- ERROR("No more inode numbers available");
- return NULL;
- }
-
- node = calloc(1, sizeof(struct node));
- if (!node) {
- return NULL;
- }
- node->name = malloc(namelen + 1);
- if (!node->name) {
- free(node);
- return NULL;
- }
- memcpy(node->name, name, namelen + 1);
- if (strcmp(name, actual_name)) {
- node->actual_name = malloc(namelen + 1);
- if (!node->actual_name) {
- free(node->name);
- free(node);
- return NULL;
- }
- memcpy(node->actual_name, actual_name, namelen + 1);
- }
- node->namelen = namelen;
- node->nid = ptr_to_id(node);
- node->ino = fuse->global->inode_ctr++;
- node->gen = fuse->global->next_generation++;
-
- node->deleted = false;
-
- derive_permissions_locked(fuse, parent, node);
- acquire_node_locked(node);
- add_node_to_parent_locked(node, parent);
- return node;
-}
-
-static int rename_node_locked(struct node *node, const char *name,
- const char* actual_name)
-{
- size_t namelen = strlen(name);
- int need_actual_name = strcmp(name, actual_name);
-
- /* make the storage bigger without actually changing the name
- * in case an error occurs part way */
- if (namelen > node->namelen) {
- char* new_name = realloc(node->name, namelen + 1);
- if (!new_name) {
- return -ENOMEM;
- }
- node->name = new_name;
- if (need_actual_name && node->actual_name) {
- char* new_actual_name = realloc(node->actual_name, namelen + 1);
- if (!new_actual_name) {
- return -ENOMEM;
- }
- node->actual_name = new_actual_name;
- }
- }
-
- /* update the name, taking care to allocate storage before overwriting the old name */
- if (need_actual_name) {
- if (!node->actual_name) {
- node->actual_name = malloc(namelen + 1);
- if (!node->actual_name) {
- return -ENOMEM;
- }
- }
- memcpy(node->actual_name, actual_name, namelen + 1);
- } else {
- free(node->actual_name);
- node->actual_name = NULL;
- }
- memcpy(node->name, name, namelen + 1);
- node->namelen = namelen;
- return 0;
-}
-
-static struct node *lookup_node_by_id_locked(struct fuse *fuse, __u64 nid)
-{
- if (nid == FUSE_ROOT_ID) {
- return &fuse->global->root;
- } else {
- return id_to_ptr(nid);
- }
-}
-
-static struct node* lookup_node_and_path_by_id_locked(struct fuse* fuse, __u64 nid,
- char* buf, size_t bufsize)
-{
- struct node* node = lookup_node_by_id_locked(fuse, nid);
- if (node && get_node_path_locked(node, buf, bufsize) < 0) {
- node = NULL;
- }
- return node;
-}
-
-static struct node *lookup_child_by_name_locked(struct node *node, const char *name)
-{
- for (node = node->child; node; node = node->next) {
- /* use exact string comparison, nodes that differ by case
- * must be considered distinct even if they refer to the same
- * underlying file as otherwise operations such as "mv x x"
- * will not work because the source and target nodes are the same. */
- if (!strcmp(name, node->name) && !node->deleted) {
- return node;
- }
- }
- return 0;
-}
-
-static struct node* acquire_or_create_child_locked(
- struct fuse* fuse, struct node* parent,
- const char* name, const char* actual_name)
-{
- struct node* child = lookup_child_by_name_locked(parent, name);
- if (child) {
- acquire_node_locked(child);
- } else {
- child = create_node_locked(fuse, parent, name, actual_name);
- }
- return child;
-}
-
-static void fuse_status(struct fuse *fuse, __u64 unique, int err)
-{
- struct fuse_out_header hdr;
- hdr.len = sizeof(hdr);
- hdr.error = err;
- hdr.unique = unique;
- write(fuse->fd, &hdr, sizeof(hdr));
-}
-
-static void fuse_reply(struct fuse *fuse, __u64 unique, void *data, int len)
-{
- struct fuse_out_header hdr;
- struct iovec vec[2];
- int res;
-
- hdr.len = len + sizeof(hdr);
- hdr.error = 0;
- hdr.unique = unique;
-
- vec[0].iov_base = &hdr;
- vec[0].iov_len = sizeof(hdr);
- vec[1].iov_base = data;
- vec[1].iov_len = len;
-
- res = writev(fuse->fd, vec, 2);
- if (res < 0) {
- ERROR("*** REPLY FAILED *** %d\n", errno);
- }
-}
-
-static int fuse_reply_entry(struct fuse* fuse, __u64 unique,
- struct node* parent, const char* name, const char* actual_name,
- const char* path)
-{
- struct node* node;
- struct fuse_entry_out out;
- struct stat s;
-
- if (lstat(path, &s) < 0) {
- return -errno;
- }
-
- pthread_mutex_lock(&fuse->global->lock);
- node = acquire_or_create_child_locked(fuse, parent, name, actual_name);
- if (!node) {
- pthread_mutex_unlock(&fuse->global->lock);
- return -ENOMEM;
- }
- memset(&out, 0, sizeof(out));
- attr_from_stat(fuse, &out.attr, &s, node);
- out.attr_valid = 10;
- out.entry_valid = 10;
- out.nodeid = node->nid;
- out.generation = node->gen;
- pthread_mutex_unlock(&fuse->global->lock);
- fuse_reply(fuse, unique, &out, sizeof(out));
- return NO_STATUS;
-}
-
-static int fuse_reply_attr(struct fuse* fuse, __u64 unique, const struct node* node,
- const char* path)
-{
- struct fuse_attr_out out;
- struct stat s;
-
- if (lstat(path, &s) < 0) {
- return -errno;
- }
- memset(&out, 0, sizeof(out));
- attr_from_stat(fuse, &out.attr, &s, node);
- out.attr_valid = 10;
- fuse_reply(fuse, unique, &out, sizeof(out));
- return NO_STATUS;
-}
-
-static void fuse_notify_delete(struct fuse* fuse, const __u64 parent,
- const __u64 child, const char* name) {
- struct fuse_out_header hdr;
- struct fuse_notify_delete_out data;
- struct iovec vec[3];
- size_t namelen = strlen(name);
- int res;
-
- hdr.len = sizeof(hdr) + sizeof(data) + namelen + 1;
- hdr.error = FUSE_NOTIFY_DELETE;
- hdr.unique = 0;
-
- data.parent = parent;
- data.child = child;
- data.namelen = namelen;
- data.padding = 0;
-
- vec[0].iov_base = &hdr;
- vec[0].iov_len = sizeof(hdr);
- vec[1].iov_base = &data;
- vec[1].iov_len = sizeof(data);
- vec[2].iov_base = (void*) name;
- vec[2].iov_len = namelen + 1;
-
- res = writev(fuse->fd, vec, 3);
- /* Ignore ENOENT, since other views may not have seen the entry */
- if (res < 0 && errno != ENOENT) {
- ERROR("*** NOTIFY FAILED *** %d\n", errno);
- }
-}
-
-static int handle_lookup(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header *hdr, const char* name)
-{
- struct node* parent_node;
- char parent_path[PATH_MAX];
- char child_path[PATH_MAX];
- const char* actual_name;
-
- pthread_mutex_lock(&fuse->global->lock);
- parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
- parent_path, sizeof(parent_path));
- TRACE("[%d] LOOKUP %s @ %"PRIx64" (%s)\n", handler->token, name, hdr->nodeid,
- parent_node ? parent_node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!parent_node || !(actual_name = find_file_within(parent_path, name,
- child_path, sizeof(child_path), 1))) {
- return -ENOENT;
- }
- if (!check_caller_access_to_name(fuse, hdr, parent_node, name, R_OK)) {
- return -EACCES;
- }
-
- return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
-}
-
-static int handle_forget(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header *hdr, const struct fuse_forget_in *req)
-{
- struct node* node;
-
- pthread_mutex_lock(&fuse->global->lock);
- node = lookup_node_by_id_locked(fuse, hdr->nodeid);
- TRACE("[%d] FORGET #%"PRIu64" @ %"PRIx64" (%s)\n", handler->token, req->nlookup,
- hdr->nodeid, node ? node->name : "?");
- if (node) {
- __u64 n = req->nlookup;
- while (n--) {
- release_node_locked(node);
- }
- }
- pthread_mutex_unlock(&fuse->global->lock);
- return NO_STATUS; /* no reply */
-}
-
-static int handle_getattr(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header *hdr, const struct fuse_getattr_in *req)
-{
- struct node* node;
- char path[PATH_MAX];
-
- pthread_mutex_lock(&fuse->global->lock);
- node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] GETATTR flags=%x fh=%"PRIx64" @ %"PRIx64" (%s)\n", handler->token,
- req->getattr_flags, req->fh, hdr->nodeid, node ? node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!node) {
- return -ENOENT;
- }
- if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
- return -EACCES;
- }
-
- return fuse_reply_attr(fuse, hdr->unique, node, path);
-}
-
-static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header *hdr, const struct fuse_setattr_in *req)
-{
- struct node* node;
- char path[PATH_MAX];
- struct timespec times[2];
-
- pthread_mutex_lock(&fuse->global->lock);
- node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] SETATTR fh=%"PRIx64" valid=%x @ %"PRIx64" (%s)\n", handler->token,
- req->fh, req->valid, hdr->nodeid, node ? node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!node) {
- return -ENOENT;
- }
-
- if (!(req->valid & FATTR_FH) &&
- !check_caller_access_to_node(fuse, hdr, node, W_OK)) {
- return -EACCES;
- }
-
- /* XXX: incomplete implementation on purpose.
- * chmod/chown should NEVER be implemented.*/
-
- if ((req->valid & FATTR_SIZE) && truncate64(path, req->size) < 0) {
- return -errno;
- }
-
- /* Handle changing atime and mtime. If FATTR_ATIME_and FATTR_ATIME_NOW
- * are both set, then set it to the current time. Else, set it to the
- * time specified in the request. Same goes for mtime. Use utimensat(2)
- * as it allows ATIME and MTIME to be changed independently, and has
- * nanosecond resolution which fuse also has.
- */
- if (req->valid & (FATTR_ATIME | FATTR_MTIME)) {
- times[0].tv_nsec = UTIME_OMIT;
- times[1].tv_nsec = UTIME_OMIT;
- if (req->valid & FATTR_ATIME) {
- if (req->valid & FATTR_ATIME_NOW) {
- times[0].tv_nsec = UTIME_NOW;
- } else {
- times[0].tv_sec = req->atime;
- times[0].tv_nsec = req->atimensec;
- }
- }
- if (req->valid & FATTR_MTIME) {
- if (req->valid & FATTR_MTIME_NOW) {
- times[1].tv_nsec = UTIME_NOW;
- } else {
- times[1].tv_sec = req->mtime;
- times[1].tv_nsec = req->mtimensec;
- }
- }
- TRACE("[%d] Calling utimensat on %s with atime %ld, mtime=%ld\n",
- handler->token, path, times[0].tv_sec, times[1].tv_sec);
- if (utimensat(-1, path, times, 0) < 0) {
- return -errno;
- }
- }
- return fuse_reply_attr(fuse, hdr->unique, node, path);
-}
-
-static int handle_mknod(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_mknod_in* req, const char* name)
-{
- struct node* parent_node;
- char parent_path[PATH_MAX];
- char child_path[PATH_MAX];
- const char* actual_name;
-
- pthread_mutex_lock(&fuse->global->lock);
- parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
- parent_path, sizeof(parent_path));
- TRACE("[%d] MKNOD %s 0%o @ %"PRIx64" (%s)\n", handler->token,
- name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!parent_node || !(actual_name = find_file_within(parent_path, name,
- child_path, sizeof(child_path), 1))) {
- return -ENOENT;
- }
- if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
- return -EACCES;
- }
- __u32 mode = (req->mode & (~0777)) | 0664;
- if (mknod(child_path, mode, req->rdev) < 0) {
- return -errno;
- }
- return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
-}
-
-static int handle_mkdir(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_mkdir_in* req, const char* name)
-{
- struct node* parent_node;
- char parent_path[PATH_MAX];
- char child_path[PATH_MAX];
- const char* actual_name;
-
- pthread_mutex_lock(&fuse->global->lock);
- parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
- parent_path, sizeof(parent_path));
- TRACE("[%d] MKDIR %s 0%o @ %"PRIx64" (%s)\n", handler->token,
- name, req->mode, hdr->nodeid, parent_node ? parent_node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!parent_node || !(actual_name = find_file_within(parent_path, name,
- child_path, sizeof(child_path), 1))) {
- return -ENOENT;
- }
- if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
- return -EACCES;
- }
- __u32 mode = (req->mode & (~0777)) | 0775;
- if (mkdir(child_path, mode) < 0) {
- return -errno;
- }
-
- /* When creating /Android/data and /Android/obb, mark them as .nomedia */
- if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "data")) {
- char nomedia[PATH_MAX];
- snprintf(nomedia, PATH_MAX, "%s/.nomedia", child_path);
- if (touch(nomedia, 0664) != 0) {
- ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
- return -ENOENT;
- }
- }
- if (parent_node->perm == PERM_ANDROID && !strcasecmp(name, "obb")) {
- char nomedia[PATH_MAX];
- snprintf(nomedia, PATH_MAX, "%s/.nomedia", fuse->global->obb_path);
- if (touch(nomedia, 0664) != 0) {
- ERROR("Failed to touch(%s): %s\n", nomedia, strerror(errno));
- return -ENOENT;
- }
- }
-
- return fuse_reply_entry(fuse, hdr->unique, parent_node, name, actual_name, child_path);
-}
-
-static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const char* name)
-{
- struct node* parent_node;
- struct node* child_node;
- char parent_path[PATH_MAX];
- char child_path[PATH_MAX];
-
- pthread_mutex_lock(&fuse->global->lock);
- parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
- parent_path, sizeof(parent_path));
- TRACE("[%d] UNLINK %s @ %"PRIx64" (%s)\n", handler->token,
- name, hdr->nodeid, parent_node ? parent_node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!parent_node || !find_file_within(parent_path, name,
- child_path, sizeof(child_path), 1)) {
- return -ENOENT;
- }
- if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
- return -EACCES;
- }
- if (unlink(child_path) < 0) {
- return -errno;
- }
- pthread_mutex_lock(&fuse->global->lock);
- child_node = lookup_child_by_name_locked(parent_node, name);
- if (child_node) {
- child_node->deleted = true;
- }
- pthread_mutex_unlock(&fuse->global->lock);
- if (parent_node && child_node) {
- /* Tell all other views that node is gone */
- TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
- handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
- if (fuse != fuse->global->fuse_default) {
- fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
- }
- if (fuse != fuse->global->fuse_read) {
- fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
- }
- if (fuse != fuse->global->fuse_write) {
- fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
- }
- }
- return 0;
-}
-
-static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const char* name)
-{
- struct node* child_node;
- struct node* parent_node;
- char parent_path[PATH_MAX];
- char child_path[PATH_MAX];
-
- pthread_mutex_lock(&fuse->global->lock);
- parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
- parent_path, sizeof(parent_path));
- TRACE("[%d] RMDIR %s @ %"PRIx64" (%s)\n", handler->token,
- name, hdr->nodeid, parent_node ? parent_node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!parent_node || !find_file_within(parent_path, name,
- child_path, sizeof(child_path), 1)) {
- return -ENOENT;
- }
- if (!check_caller_access_to_name(fuse, hdr, parent_node, name, W_OK)) {
- return -EACCES;
- }
- if (rmdir(child_path) < 0) {
- return -errno;
- }
- pthread_mutex_lock(&fuse->global->lock);
- child_node = lookup_child_by_name_locked(parent_node, name);
- if (child_node) {
- child_node->deleted = true;
- }
- pthread_mutex_unlock(&fuse->global->lock);
- if (parent_node && child_node) {
- /* Tell all other views that node is gone */
- TRACE("[%d] fuse_notify_delete parent=%"PRIx64", child=%"PRIx64", name=%s\n",
- handler->token, (uint64_t) parent_node->nid, (uint64_t) child_node->nid, name);
- if (fuse != fuse->global->fuse_default) {
- fuse_notify_delete(fuse->global->fuse_default, parent_node->nid, child_node->nid, name);
- }
- if (fuse != fuse->global->fuse_read) {
- fuse_notify_delete(fuse->global->fuse_read, parent_node->nid, child_node->nid, name);
- }
- if (fuse != fuse->global->fuse_write) {
- fuse_notify_delete(fuse->global->fuse_write, parent_node->nid, child_node->nid, name);
- }
- }
- return 0;
-}
-
-static int handle_rename(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_rename_in* req,
- const char* old_name, const char* new_name)
-{
- struct node* old_parent_node;
- struct node* new_parent_node;
- struct node* child_node;
- char old_parent_path[PATH_MAX];
- char new_parent_path[PATH_MAX];
- char old_child_path[PATH_MAX];
- char new_child_path[PATH_MAX];
- const char* new_actual_name;
- int res;
-
- pthread_mutex_lock(&fuse->global->lock);
- old_parent_node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
- old_parent_path, sizeof(old_parent_path));
- new_parent_node = lookup_node_and_path_by_id_locked(fuse, req->newdir,
- new_parent_path, sizeof(new_parent_path));
- TRACE("[%d] RENAME %s->%s @ %"PRIx64" (%s) -> %"PRIx64" (%s)\n", handler->token,
- old_name, new_name,
- hdr->nodeid, old_parent_node ? old_parent_node->name : "?",
- req->newdir, new_parent_node ? new_parent_node->name : "?");
- if (!old_parent_node || !new_parent_node) {
- res = -ENOENT;
- goto lookup_error;
- }
- if (!check_caller_access_to_name(fuse, hdr, old_parent_node, old_name, W_OK)) {
- res = -EACCES;
- goto lookup_error;
- }
- if (!check_caller_access_to_name(fuse, hdr, new_parent_node, new_name, W_OK)) {
- res = -EACCES;
- goto lookup_error;
- }
- child_node = lookup_child_by_name_locked(old_parent_node, old_name);
- if (!child_node || get_node_path_locked(child_node,
- old_child_path, sizeof(old_child_path)) < 0) {
- res = -ENOENT;
- goto lookup_error;
- }
- acquire_node_locked(child_node);
- pthread_mutex_unlock(&fuse->global->lock);
-
- /* Special case for renaming a file where destination is same path
- * differing only by case. In this case we don't want to look for a case
- * insensitive match. This allows commands like "mv foo FOO" to work as expected.
- */
- int search = old_parent_node != new_parent_node
- || strcasecmp(old_name, new_name);
- if (!(new_actual_name = find_file_within(new_parent_path, new_name,
- new_child_path, sizeof(new_child_path), search))) {
- res = -ENOENT;
- goto io_error;
- }
-
- TRACE("[%d] RENAME %s->%s\n", handler->token, old_child_path, new_child_path);
- res = rename(old_child_path, new_child_path);
- if (res < 0) {
- res = -errno;
- goto io_error;
- }
-
- pthread_mutex_lock(&fuse->global->lock);
- res = rename_node_locked(child_node, new_name, new_actual_name);
- if (!res) {
- remove_node_from_parent_locked(child_node);
- derive_permissions_locked(fuse, new_parent_node, child_node);
- derive_permissions_recursive_locked(fuse, child_node);
- add_node_to_parent_locked(child_node, new_parent_node);
- }
- goto done;
-
-io_error:
- pthread_mutex_lock(&fuse->global->lock);
-done:
- release_node_locked(child_node);
-lookup_error:
- pthread_mutex_unlock(&fuse->global->lock);
- return res;
-}
-
-static int open_flags_to_access_mode(int open_flags) {
- if ((open_flags & O_ACCMODE) == O_RDONLY) {
- return R_OK;
- } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
- return W_OK;
- } else {
- /* Probably O_RDRW, but treat as default to be safe */
- return R_OK | W_OK;
- }
-}
-
-static int handle_open(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_open_in* req)
-{
- struct node* node;
- char path[PATH_MAX];
- struct fuse_open_out out;
- struct handle *h;
-
- pthread_mutex_lock(&fuse->global->lock);
- node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] OPEN 0%o @ %"PRIx64" (%s)\n", handler->token,
- req->flags, hdr->nodeid, node ? node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!node) {
- return -ENOENT;
- }
- if (!check_caller_access_to_node(fuse, hdr, node,
- open_flags_to_access_mode(req->flags))) {
- return -EACCES;
- }
- h = malloc(sizeof(*h));
- if (!h) {
- return -ENOMEM;
- }
- TRACE("[%d] OPEN %s\n", handler->token, path);
- h->fd = open(path, req->flags);
- if (h->fd < 0) {
- free(h);
- return -errno;
- }
- out.fh = ptr_to_id(h);
- out.open_flags = 0;
- out.padding = 0;
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return NO_STATUS;
-}
-
-static int handle_read(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_read_in* req)
-{
- struct handle *h = id_to_ptr(req->fh);
- __u64 unique = hdr->unique;
- __u32 size = req->size;
- __u64 offset = req->offset;
- int res;
- __u8 *read_buffer = (__u8 *) ((uintptr_t)(handler->read_buffer + PAGE_SIZE) & ~((uintptr_t)PAGE_SIZE-1));
-
- /* Don't access any other fields of hdr or req beyond this point, the read buffer
- * overlaps the request buffer and will clobber data in the request. This
- * saves us 128KB per request handler thread at the cost of this scary comment. */
-
- TRACE("[%d] READ %p(%d) %u@%"PRIu64"\n", handler->token,
- h, h->fd, size, (uint64_t) offset);
- if (size > MAX_READ) {
- return -EINVAL;
- }
- res = pread64(h->fd, read_buffer, size, offset);
- if (res < 0) {
- return -errno;
- }
- fuse_reply(fuse, unique, read_buffer, res);
- return NO_STATUS;
-}
-
-static int handle_write(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_write_in* req,
- const void* buffer)
-{
- struct fuse_write_out out;
- struct handle *h = id_to_ptr(req->fh);
- int res;
- __u8 aligned_buffer[req->size] __attribute__((__aligned__(PAGE_SIZE)));
-
- if (req->flags & O_DIRECT) {
- memcpy(aligned_buffer, buffer, req->size);
- buffer = (const __u8*) aligned_buffer;
- }
-
- TRACE("[%d] WRITE %p(%d) %u@%"PRIu64"\n", handler->token,
- h, h->fd, req->size, req->offset);
- res = pwrite64(h->fd, buffer, req->size, req->offset);
- if (res < 0) {
- return -errno;
- }
- out.size = res;
- out.padding = 0;
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return NO_STATUS;
-}
-
-static int handle_statfs(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr)
-{
- char path[PATH_MAX];
- struct statfs stat;
- struct fuse_statfs_out out;
- int res;
-
- pthread_mutex_lock(&fuse->global->lock);
- TRACE("[%d] STATFS\n", handler->token);
- res = get_node_path_locked(&fuse->global->root, path, sizeof(path));
- pthread_mutex_unlock(&fuse->global->lock);
- if (res < 0) {
- return -ENOENT;
- }
- if (statfs(fuse->global->root.name, &stat) < 0) {
- return -errno;
- }
- memset(&out, 0, sizeof(out));
- out.st.blocks = stat.f_blocks;
- out.st.bfree = stat.f_bfree;
- out.st.bavail = stat.f_bavail;
- out.st.files = stat.f_files;
- out.st.ffree = stat.f_ffree;
- out.st.bsize = stat.f_bsize;
- out.st.namelen = stat.f_namelen;
- out.st.frsize = stat.f_frsize;
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return NO_STATUS;
-}
-
-static int handle_release(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_release_in* req)
-{
- struct handle *h = id_to_ptr(req->fh);
-
- TRACE("[%d] RELEASE %p(%d)\n", handler->token, h, h->fd);
- close(h->fd);
- free(h);
- return 0;
-}
-
-static int handle_fsync(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_fsync_in* req)
-{
- bool is_dir = (hdr->opcode == FUSE_FSYNCDIR);
- bool is_data_sync = req->fsync_flags & 1;
-
- int fd = -1;
- if (is_dir) {
- struct dirhandle *dh = id_to_ptr(req->fh);
- fd = dirfd(dh->d);
- } else {
- struct handle *h = id_to_ptr(req->fh);
- fd = h->fd;
- }
-
- TRACE("[%d] %s %p(%d) is_data_sync=%d\n", handler->token,
- is_dir ? "FSYNCDIR" : "FSYNC",
- id_to_ptr(req->fh), fd, is_data_sync);
- int res = is_data_sync ? fdatasync(fd) : fsync(fd);
- if (res == -1) {
- return -errno;
- }
- return 0;
-}
-
-static int handle_flush(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr)
-{
- TRACE("[%d] FLUSH\n", handler->token);
- return 0;
-}
-
-static int handle_opendir(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_open_in* req)
-{
- struct node* node;
- char path[PATH_MAX];
- struct fuse_open_out out;
- struct dirhandle *h;
-
- pthread_mutex_lock(&fuse->global->lock);
- node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid, path, sizeof(path));
- TRACE("[%d] OPENDIR @ %"PRIx64" (%s)\n", handler->token,
- hdr->nodeid, node ? node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!node) {
- return -ENOENT;
- }
- if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
- return -EACCES;
- }
- h = malloc(sizeof(*h));
- if (!h) {
- return -ENOMEM;
- }
- TRACE("[%d] OPENDIR %s\n", handler->token, path);
- h->d = opendir(path);
- if (!h->d) {
- free(h);
- return -errno;
- }
- out.fh = ptr_to_id(h);
- out.open_flags = 0;
- out.padding = 0;
- fuse_reply(fuse, hdr->unique, &out, sizeof(out));
- return NO_STATUS;
-}
-
-static int handle_readdir(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_read_in* req)
-{
- char buffer[8192];
- struct fuse_dirent *fde = (struct fuse_dirent*) buffer;
- struct dirent *de;
- struct dirhandle *h = id_to_ptr(req->fh);
-
- TRACE("[%d] READDIR %p\n", handler->token, h);
- if (req->offset == 0) {
- /* rewinddir() might have been called above us, so rewind here too */
- TRACE("[%d] calling rewinddir()\n", handler->token);
- rewinddir(h->d);
- }
- de = readdir(h->d);
- if (!de) {
- return 0;
- }
- fde->ino = FUSE_UNKNOWN_INO;
- /* increment the offset so we can detect when rewinddir() seeks back to the beginning */
- fde->off = req->offset + 1;
- fde->type = de->d_type;
- fde->namelen = strlen(de->d_name);
- memcpy(fde->name, de->d_name, fde->namelen + 1);
- fuse_reply(fuse, hdr->unique, fde,
- FUSE_DIRENT_ALIGN(sizeof(struct fuse_dirent) + fde->namelen));
- return NO_STATUS;
-}
-
-static int handle_releasedir(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_release_in* req)
-{
- struct dirhandle *h = id_to_ptr(req->fh);
-
- TRACE("[%d] RELEASEDIR %p\n", handler->token, h);
- closedir(h->d);
- free(h);
- return 0;
-}
-
-static int handle_init(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header* hdr, const struct fuse_init_in* req)
-{
- struct fuse_init_out out;
- size_t fuse_struct_size;
-
- TRACE("[%d] INIT ver=%d.%d maxread=%d flags=%x\n",
- handler->token, req->major, req->minor, req->max_readahead, req->flags);
-
- /* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
- * defined (fuse version 7.6). The structure is the same from 7.6 through
- * 7.22. Beginning with 7.23, the structure increased in size and added
- * new parameters.
- */
- if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
- ERROR("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
- req->major, req->minor, FUSE_KERNEL_VERSION);
- return -1;
- }
-
- /* We limit ourselves to 15 because we don't handle BATCH_FORGET yet */
- out.minor = MIN(req->minor, 15);
- fuse_struct_size = sizeof(out);
-#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
- /* FUSE_KERNEL_VERSION >= 23. */
-
- /* If the kernel only works on minor revs older than or equal to 22,
- * then use the older structure size since this code only uses the 7.22
- * version of the structure. */
- if (req->minor <= 22) {
- fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
- }
-#endif
-
- out.major = FUSE_KERNEL_VERSION;
- out.max_readahead = req->max_readahead;
- out.flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
- out.max_background = 32;
- out.congestion_threshold = 32;
- out.max_write = MAX_WRITE;
- fuse_reply(fuse, hdr->unique, &out, fuse_struct_size);
- return NO_STATUS;
-}
-
-static int handle_canonical_path(struct fuse* fuse, struct fuse_handler* handler,
- const struct fuse_in_header *hdr)
-{
- struct node* node;
- char path[PATH_MAX];
- int len;
-
- pthread_mutex_lock(&fuse->global->lock);
- node = lookup_node_and_path_by_id_locked(fuse, hdr->nodeid,
- path, sizeof(path));
- TRACE("[%d] CANONICAL_PATH @ %" PRIx64 " (%s)\n", handler->token, hdr->nodeid,
- node ? node->name : "?");
- pthread_mutex_unlock(&fuse->global->lock);
-
- if (!node) {
- return -ENOENT;
- }
- if (!check_caller_access_to_node(fuse, hdr, node, R_OK)) {
- return -EACCES;
- }
- len = strlen(path);
- if (len + 1 > PATH_MAX)
- len = PATH_MAX - 1;
- path[PATH_MAX - 1] = 0;
- fuse_reply(fuse, hdr->unique, path, len + 1);
- return NO_STATUS;
-}
-
-
-static int handle_fuse_request(struct fuse *fuse, struct fuse_handler* handler,
- const struct fuse_in_header *hdr, const void *data, size_t data_len)
-{
- switch (hdr->opcode) {
- case FUSE_LOOKUP: { /* bytez[] -> entry_out */
- const char* name = data;
- return handle_lookup(fuse, handler, hdr, name);
- }
-
- case FUSE_FORGET: {
- const struct fuse_forget_in *req = data;
- return handle_forget(fuse, handler, hdr, req);
- }
-
- case FUSE_GETATTR: { /* getattr_in -> attr_out */
- const struct fuse_getattr_in *req = data;
- return handle_getattr(fuse, handler, hdr, req);
- }
-
- case FUSE_SETATTR: { /* setattr_in -> attr_out */
- const struct fuse_setattr_in *req = data;
- return handle_setattr(fuse, handler, hdr, req);
- }
-
-// case FUSE_READLINK:
-// case FUSE_SYMLINK:
- case FUSE_MKNOD: { /* mknod_in, bytez[] -> entry_out */
- const struct fuse_mknod_in *req = data;
- const char *name = ((const char*) data) + sizeof(*req);
- return handle_mknod(fuse, handler, hdr, req, name);
- }
-
- case FUSE_MKDIR: { /* mkdir_in, bytez[] -> entry_out */
- const struct fuse_mkdir_in *req = data;
- const char *name = ((const char*) data) + sizeof(*req);
- return handle_mkdir(fuse, handler, hdr, req, name);
- }
-
- case FUSE_UNLINK: { /* bytez[] -> */
- const char* name = data;
- return handle_unlink(fuse, handler, hdr, name);
- }
-
- case FUSE_RMDIR: { /* bytez[] -> */
- const char* name = data;
- return handle_rmdir(fuse, handler, hdr, name);
- }
-
- case FUSE_RENAME: { /* rename_in, oldname, newname -> */
- const struct fuse_rename_in *req = data;
- const char *old_name = ((const char*) data) + sizeof(*req);
- const char *new_name = old_name + strlen(old_name) + 1;
- return handle_rename(fuse, handler, hdr, req, old_name, new_name);
- }
-
-// case FUSE_LINK:
- case FUSE_OPEN: { /* open_in -> open_out */
- const struct fuse_open_in *req = data;
- return handle_open(fuse, handler, hdr, req);
- }
-
- case FUSE_READ: { /* read_in -> byte[] */
- const struct fuse_read_in *req = data;
- return handle_read(fuse, handler, hdr, req);
- }
-
- case FUSE_WRITE: { /* write_in, byte[write_in.size] -> write_out */
- const struct fuse_write_in *req = data;
- const void* buffer = (const __u8*)data + sizeof(*req);
- return handle_write(fuse, handler, hdr, req, buffer);
- }
-
- case FUSE_STATFS: { /* getattr_in -> attr_out */
- return handle_statfs(fuse, handler, hdr);
- }
-
- case FUSE_RELEASE: { /* release_in -> */
- const struct fuse_release_in *req = data;
- return handle_release(fuse, handler, hdr, req);
- }
-
- case FUSE_FSYNC:
- case FUSE_FSYNCDIR: {
- const struct fuse_fsync_in *req = data;
- return handle_fsync(fuse, handler, hdr, req);
- }
-
-// case FUSE_SETXATTR:
-// case FUSE_GETXATTR:
-// case FUSE_LISTXATTR:
-// case FUSE_REMOVEXATTR:
- case FUSE_FLUSH: {
- return handle_flush(fuse, handler, hdr);
- }
-
- case FUSE_OPENDIR: { /* open_in -> open_out */
- const struct fuse_open_in *req = data;
- return handle_opendir(fuse, handler, hdr, req);
- }
-
- case FUSE_READDIR: {
- const struct fuse_read_in *req = data;
- return handle_readdir(fuse, handler, hdr, req);
- }
-
- case FUSE_RELEASEDIR: { /* release_in -> */
- const struct fuse_release_in *req = data;
- return handle_releasedir(fuse, handler, hdr, req);
- }
-
- case FUSE_INIT: { /* init_in -> init_out */
- const struct fuse_init_in *req = data;
- return handle_init(fuse, handler, hdr, req);
- }
-
- case FUSE_CANONICAL_PATH: { /* nodeid -> bytez[] */
- return handle_canonical_path(fuse, handler, hdr);
- }
-
- default: {
- TRACE("[%d] NOTIMPL op=%d uniq=%"PRIx64" nid=%"PRIx64"\n",
- handler->token, hdr->opcode, hdr->unique, hdr->nodeid);
- return -ENOSYS;
- }
- }
-}
-
-static void handle_fuse_requests(struct fuse_handler* handler)
-{
- struct fuse* fuse = handler->fuse;
- for (;;) {
- ssize_t len = TEMP_FAILURE_RETRY(read(fuse->fd,
- handler->request_buffer, sizeof(handler->request_buffer)));
- if (len < 0) {
- if (errno == ENODEV) {
- ERROR("[%d] someone stole our marbles!\n", handler->token);
- exit(2);
- }
- ERROR("[%d] handle_fuse_requests: errno=%d\n", handler->token, errno);
- continue;
- }
-
- if ((size_t)len < sizeof(struct fuse_in_header)) {
- ERROR("[%d] request too short: len=%zu\n", handler->token, (size_t)len);
- continue;
- }
-
- const struct fuse_in_header *hdr = (void*)handler->request_buffer;
- if (hdr->len != (size_t)len) {
- ERROR("[%d] malformed header: len=%zu, hdr->len=%u\n",
- handler->token, (size_t)len, hdr->len);
- continue;
- }
-
- const void *data = handler->request_buffer + sizeof(struct fuse_in_header);
- size_t data_len = len - sizeof(struct fuse_in_header);
- __u64 unique = hdr->unique;
- int res = handle_fuse_request(fuse, handler, hdr, data, data_len);
-
- /* We do not access the request again after this point because the underlying
- * buffer storage may have been reused while processing the request. */
-
- if (res != NO_STATUS) {
- if (res) {
- TRACE("[%d] ERROR %d\n", handler->token, res);
- }
- fuse_status(fuse, unique, res);
- }
- }
-}
-
-static void* start_handler(void* data)
-{
- struct fuse_handler* handler = data;
- handle_fuse_requests(handler);
- return NULL;
-}
-
-static bool remove_str_to_int(void *key, void *value, void *context) {
- Hashmap* map = context;
- hashmapRemove(map, key);
- free(key);
- return true;
-}
-
-static bool package_parse_callback(pkg_info *info, void *userdata) {
- struct fuse_global *global = (struct fuse_global *)userdata;
-
- char* name = strdup(info->name);
- hashmapPut(global->package_to_appid, name, (void*) (uintptr_t) info->uid);
- packagelist_free(info);
- return true;
-}
-
-static bool read_package_list(struct fuse_global* global) {
- pthread_mutex_lock(&global->lock);
-
- hashmapForEach(global->package_to_appid, remove_str_to_int, global->package_to_appid);
-
- bool rc = packagelist_parse(package_parse_callback, global);
- TRACE("read_package_list: found %zu packages\n",
- hashmapSize(global->package_to_appid));
-
- /* Regenerate ownership details using newly loaded mapping */
- derive_permissions_recursive_locked(global->fuse_default, &global->root);
-
- pthread_mutex_unlock(&global->lock);
-
- return rc;
-}
-
-static void watch_package_list(struct fuse_global* global) {
- struct inotify_event *event;
- char event_buf[512];
-
- int nfd = inotify_init();
- if (nfd < 0) {
- ERROR("inotify_init failed: %s\n", strerror(errno));
- return;
- }
-
- bool active = false;
- while (1) {
- if (!active) {
- int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF);
- if (res == -1) {
- if (errno == ENOENT || errno == EACCES) {
- /* Framework may not have created yet, sleep and retry */
- ERROR("missing \"%s\"; retrying\n", PACKAGES_LIST_FILE);
- sleep(3);
- continue;
- } else {
- ERROR("inotify_add_watch failed: %s\n", strerror(errno));
- return;
- }
- }
-
- /* Watch above will tell us about any future changes, so
- * read the current state. */
- if (read_package_list(global) == false) {
- ERROR("read_package_list failed\n");
- return;
- }
- active = true;
- }
-
- int event_pos = 0;
- int res = read(nfd, event_buf, sizeof(event_buf));
- if (res < (int) sizeof(*event)) {
- if (errno == EINTR)
- continue;
- ERROR("failed to read inotify event: %s\n", strerror(errno));
- return;
- }
-
- while (res >= (int) sizeof(*event)) {
- int event_size;
- event = (struct inotify_event *) (event_buf + event_pos);
-
- TRACE("inotify event: %08x\n", event->mask);
- if ((event->mask & IN_IGNORED) == IN_IGNORED) {
- /* Previously watched file was deleted, probably due to move
- * that swapped in new data; re-arm the watch and read. */
- active = false;
- }
-
- event_size = sizeof(*event) + event->len;
- res -= event_size;
- event_pos += event_size;
- }
- }
-}
-
-static int usage() {
- ERROR("usage: sdcard [OPTIONS] <source_path> <label>\n"
- " -u: specify UID to run as\n"
- " -g: specify GID to run as\n"
- " -U: specify user ID that owns device\n"
- " -m: source_path is multi-user\n"
- " -w: runtime write mount has full write access\n"
- "\n");
- return 1;
-}
-
-static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
- char opts[256];
-
- fuse->fd = open("/dev/fuse", O_RDWR);
- if (fuse->fd == -1) {
- ERROR("failed to open fuse device: %s\n", strerror(errno));
- return -1;
- }
-
- umount2(fuse->dest_path, MNT_DETACH);
-
- snprintf(opts, sizeof(opts),
- "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
- fuse->fd, fuse->global->uid, fuse->global->gid);
- if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
- MS_NOATIME, opts) != 0) {
- ERROR("failed to mount fuse filesystem: %s\n", strerror(errno));
- return -1;
- }
-
- fuse->gid = gid;
- fuse->mask = mask;
-
- return 0;
-}
-
-static void run(const char* source_path, const char* label, uid_t uid,
- gid_t gid, userid_t userid, bool multi_user, bool full_write) {
- struct fuse_global global;
- struct fuse fuse_default;
- struct fuse fuse_read;
- struct fuse fuse_write;
- struct fuse_handler handler_default;
- struct fuse_handler handler_read;
- struct fuse_handler handler_write;
- pthread_t thread_default;
- pthread_t thread_read;
- pthread_t thread_write;
-
- memset(&global, 0, sizeof(global));
- memset(&fuse_default, 0, sizeof(fuse_default));
- memset(&fuse_read, 0, sizeof(fuse_read));
- memset(&fuse_write, 0, sizeof(fuse_write));
- memset(&handler_default, 0, sizeof(handler_default));
- memset(&handler_read, 0, sizeof(handler_read));
- memset(&handler_write, 0, sizeof(handler_write));
-
- pthread_mutex_init(&global.lock, NULL);
- global.package_to_appid = hashmapCreate(256, str_hash, str_icase_equals);
- global.uid = uid;
- global.gid = gid;
- global.multi_user = multi_user;
- global.next_generation = 0;
- global.inode_ctr = 1;
-
- memset(&global.root, 0, sizeof(global.root));
- global.root.nid = FUSE_ROOT_ID; /* 1 */
- global.root.refcount = 2;
- global.root.namelen = strlen(source_path);
- global.root.name = strdup(source_path);
- global.root.userid = userid;
- global.root.uid = AID_ROOT;
- global.root.under_android = false;
-
- strcpy(global.source_path, source_path);
-
- if (multi_user) {
- global.root.perm = PERM_PRE_ROOT;
- snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
- } else {
- global.root.perm = PERM_ROOT;
- snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
- }
-
- fuse_default.global = &global;
- fuse_read.global = &global;
- fuse_write.global = &global;
-
- global.fuse_default = &fuse_default;
- global.fuse_read = &fuse_read;
- global.fuse_write = &fuse_write;
-
- snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
- snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
- snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
-
- handler_default.fuse = &fuse_default;
- handler_read.fuse = &fuse_read;
- handler_write.fuse = &fuse_write;
-
- handler_default.token = 0;
- handler_read.token = 1;
- handler_write.token = 2;
-
- umask(0);
-
- if (multi_user) {
- /* Multi-user storage is fully isolated per user, so "other"
- * permissions are completely masked off. */
- if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
- || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
- || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
- ERROR("failed to fuse_setup\n");
- exit(1);
- }
- } else {
- /* Physical storage is readable by all users on device, but
- * the Android directories are masked off to a single user
- * deep inside attr_from_stat(). */
- if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
- || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
- || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
- ERROR("failed to fuse_setup\n");
- exit(1);
- }
- }
-
- /* Drop privs */
- if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
- ERROR("cannot setgroups: %s\n", strerror(errno));
- exit(1);
- }
- if (setgid(gid) < 0) {
- ERROR("cannot setgid: %s\n", strerror(errno));
- exit(1);
- }
- if (setuid(uid) < 0) {
- ERROR("cannot setuid: %s\n", strerror(errno));
- exit(1);
- }
-
- if (multi_user) {
- fs_prepare_dir(global.obb_path, 0775, uid, gid);
- }
-
- if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
- || pthread_create(&thread_read, NULL, start_handler, &handler_read)
- || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
- ERROR("failed to pthread_create\n");
- exit(1);
- }
-
- watch_package_list(&global);
- ERROR("terminated prematurely\n");
- exit(1);
-}
-
-static int sdcardfs_setup(const char *source_path, const char *dest_path, uid_t fsuid,
- gid_t fsgid, bool multi_user, userid_t userid, gid_t gid, mode_t mask) {
- char opts[256];
-
- snprintf(opts, sizeof(opts),
- "fsuid=%d,fsgid=%d,%smask=%d,userid=%d,gid=%d",
- fsuid, fsgid, multi_user?"multiuser,":"", mask, userid, gid);
-
- if (mount(source_path, dest_path, "sdcardfs",
- MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts) != 0) {
- ERROR("failed to mount sdcardfs filesystem: %s\n", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static void run_sdcardfs(const char* source_path, const char* label, uid_t uid,
- gid_t gid, userid_t userid, bool multi_user, bool full_write) {
- char dest_path_default[PATH_MAX];
- char dest_path_read[PATH_MAX];
- char dest_path_write[PATH_MAX];
- char obb_path[PATH_MAX];
- snprintf(dest_path_default, PATH_MAX, "/mnt/runtime/default/%s", label);
- snprintf(dest_path_read, PATH_MAX, "/mnt/runtime/read/%s", label);
- snprintf(dest_path_write, PATH_MAX, "/mnt/runtime/write/%s", label);
-
- umask(0);
- if (multi_user) {
- /* Multi-user storage is fully isolated per user, so "other"
- * permissions are completely masked off. */
- if (sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
- AID_SDCARD_RW, 0006)
- || sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
- AID_EVERYBODY, 0027)
- || sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
- AID_EVERYBODY, full_write ? 0007 : 0027)) {
- ERROR("failed to fuse_setup\n");
- exit(1);
- }
- } else {
- /* Physical storage is readable by all users on device, but
- * the Android directories are masked off to a single user
- * deep inside attr_from_stat(). */
- if (sdcardfs_setup(source_path, dest_path_default, uid, gid, multi_user, userid,
- AID_SDCARD_RW, 0006)
- || sdcardfs_setup(source_path, dest_path_read, uid, gid, multi_user, userid,
- AID_EVERYBODY, full_write ? 0027 : 0022)
- || sdcardfs_setup(source_path, dest_path_write, uid, gid, multi_user, userid,
- AID_EVERYBODY, full_write ? 0007 : 0022)) {
- ERROR("failed to fuse_setup\n");
- exit(1);
- }
- }
-
- /* Drop privs */
- if (setgroups(sizeof(kGroups) / sizeof(kGroups[0]), kGroups) < 0) {
- ERROR("cannot setgroups: %s\n", strerror(errno));
- exit(1);
- }
- if (setgid(gid) < 0) {
- ERROR("cannot setgid: %s\n", strerror(errno));
- exit(1);
- }
- if (setuid(uid) < 0) {
- ERROR("cannot setuid: %s\n", strerror(errno));
- exit(1);
- }
-
- if (multi_user) {
- snprintf(obb_path, sizeof(obb_path), "%s/obb", source_path);
- fs_prepare_dir(&obb_path[0], 0775, uid, gid);
- }
-
- exit(0);
-}
-
-static bool supports_sdcardfs(void) {
- FILE *fp;
- char *buf = NULL;
- size_t buflen = 0;
-
- fp = fopen("/proc/filesystems", "r");
- if (!fp) {
- ERROR("Could not read /proc/filesystems, error: %s\n", strerror(errno));
- return false;
- }
- while ((getline(&buf, &buflen, fp)) > 0) {
- if (strstr(buf, "sdcardfs\n")) {
- free(buf);
- fclose(fp);
- return true;
- }
- }
- free(buf);
- fclose(fp);
- return false;
-}
-
-static bool should_use_sdcardfs(void) {
- char property[PROPERTY_VALUE_MAX];
-
- // Allow user to have a strong opinion about state
- property_get(PROP_SDCARDFS_USER, property, "");
- if (!strcmp(property, "force_on")) {
- ALOGW("User explicitly enabled sdcardfs");
- return supports_sdcardfs();
- } else if (!strcmp(property, "force_off")) {
- ALOGW("User explicitly disabled sdcardfs");
- return false;
- }
-
- // Fall back to device opinion about state
- if (property_get_bool(PROP_SDCARDFS_DEVICE, false)) {
- ALOGW("Device explicitly enabled sdcardfs");
- return supports_sdcardfs();
- } else {
- ALOGW("Device explicitly disabled sdcardfs");
- return false;
- }
-}
-
-int main(int argc, char **argv) {
- const char *source_path = NULL;
- const char *label = NULL;
- uid_t uid = 0;
- gid_t gid = 0;
- userid_t userid = 0;
- bool multi_user = false;
- bool full_write = false;
- int i;
- struct rlimit rlim;
- int fs_version;
-
- int opt;
- while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
- switch (opt) {
- case 'u':
- uid = strtoul(optarg, NULL, 10);
- break;
- case 'g':
- gid = strtoul(optarg, NULL, 10);
- break;
- case 'U':
- userid = strtoul(optarg, NULL, 10);
- break;
- case 'm':
- multi_user = true;
- break;
- case 'w':
- full_write = true;
- break;
- case '?':
- default:
- return usage();
- }
- }
-
- for (i = optind; i < argc; i++) {
- char* arg = argv[i];
- if (!source_path) {
- source_path = arg;
- } else if (!label) {
- label = arg;
- } else {
- ERROR("too many arguments\n");
- return usage();
- }
- }
-
- if (!source_path) {
- ERROR("no source path specified\n");
- return usage();
- }
- if (!label) {
- ERROR("no label specified\n");
- return usage();
- }
- if (!uid || !gid) {
- ERROR("uid and gid must be nonzero\n");
- return usage();
- }
-
- rlim.rlim_cur = 8192;
- rlim.rlim_max = 8192;
- if (setrlimit(RLIMIT_NOFILE, &rlim)) {
- ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno);
- }
-
- while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
- ERROR("installd fs upgrade not yet complete. Waiting...\n");
- sleep(1);
- }
-
- if (should_use_sdcardfs()) {
- run_sdcardfs(source_path, label, uid, gid, userid, multi_user, full_write);
- } else {
- run(source_path, label, uid, gid, userid, multi_user, full_write);
- }
- return 1;
-}
diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp
new file mode 100644
index 0000000..3481ec3
--- /dev/null
+++ b/sdcard/sdcard.cpp
@@ -0,0 +1,394 @@
+// Copyright (C) 2016 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 "sdcard"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/fuse.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/mount.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
+#include <cutils/fs.h>
+#include <cutils/multiuser.h>
+#include <packagelistparser/packagelistparser.h>
+
+#include <libminijail.h>
+#include <scoped_minijail.h>
+
+#include <private/android_filesystem_config.h>
+
+// README
+//
+// What is this?
+//
+// sdcard is a program that uses FUSE to emulate FAT-on-sdcard style
+// directory permissions (all files are given fixed owner, group, and
+// permissions at creation, owner, group, and permissions are not
+// changeable, symlinks and hardlinks are not createable, etc.
+//
+// See usage() for command line options.
+//
+// It must be run as root, but will drop to requested UID/GID as soon as it
+// mounts a filesystem. It will refuse to run if requested UID/GID are zero.
+//
+// Things I believe to be true:
+//
+// - ops that return a fuse_entry (LOOKUP, MKNOD, MKDIR, LINK, SYMLINK,
+// CREAT) must bump that node's refcount
+// - don't forget that FORGET can forget multiple references (req->nlookup)
+// - if an op that returns a fuse_entry fails writing the reply to the
+// kernel, you must rollback the refcount to reflect the reference the
+// kernel did not actually acquire
+//
+// This daemon can also derive custom filesystem permissions based on directory
+// structure when requested. These custom permissions support several features:
+//
+// - Apps can access their own files in /Android/data/com.example/ without
+// requiring any additional GIDs.
+// - Separate permissions for protecting directories like Pictures and Music.
+// - Multi-user separation on the same physical device.
+
+#include "fuse.h"
+
+/* Supplementary groups to execute with. */
+static const gid_t kGroups[1] = { AID_PACKAGE_INFO };
+
+static bool package_parse_callback(pkg_info *info, void *userdata) {
+ struct fuse_global *global = (struct fuse_global *)userdata;
+ bool res = global->package_to_appid->emplace(info->name, info->uid).second;
+ packagelist_free(info);
+ return res;
+}
+
+static bool read_package_list(struct fuse_global* global) {
+ pthread_mutex_lock(&global->lock);
+
+ global->package_to_appid->clear();
+ bool rc = packagelist_parse(package_parse_callback, global);
+ DLOG(INFO) << "read_package_list: found " << global->package_to_appid->size() << " packages";
+
+ // Regenerate ownership details using newly loaded mapping.
+ derive_permissions_recursive_locked(global->fuse_default, &global->root);
+
+ pthread_mutex_unlock(&global->lock);
+
+ return rc;
+}
+
+static void watch_package_list(struct fuse_global* global) {
+ struct inotify_event *event;
+ char event_buf[512];
+
+ int nfd = inotify_init();
+ if (nfd < 0) {
+ PLOG(ERROR) << "inotify_init failed";
+ return;
+ }
+
+ bool active = false;
+ while (1) {
+ if (!active) {
+ int res = inotify_add_watch(nfd, PACKAGES_LIST_FILE, IN_DELETE_SELF);
+ if (res == -1) {
+ if (errno == ENOENT || errno == EACCES) {
+ /* Framework may not have created the file yet, sleep and retry. */
+ LOG(ERROR) << "missing \"" << PACKAGES_LIST_FILE << "\"; retrying...";
+ sleep(3);
+ continue;
+ } else {
+ PLOG(ERROR) << "inotify_add_watch failed";
+ return;
+ }
+ }
+
+ /* Watch above will tell us about any future changes, so
+ * read the current state. */
+ if (read_package_list(global) == false) {
+ LOG(ERROR) << "read_package_list failed";
+ return;
+ }
+ active = true;
+ }
+
+ int event_pos = 0;
+ int res = read(nfd, event_buf, sizeof(event_buf));
+ if (res < (int) sizeof(*event)) {
+ if (errno == EINTR)
+ continue;
+ PLOG(ERROR) << "failed to read inotify event";
+ return;
+ }
+
+ while (res >= (int) sizeof(*event)) {
+ int event_size;
+ event = (struct inotify_event *) (event_buf + event_pos);
+
+ DLOG(INFO) << "inotify event: " << std::hex << event->mask << std::dec;
+ if ((event->mask & IN_IGNORED) == IN_IGNORED) {
+ /* Previously watched file was deleted, probably due to move
+ * that swapped in new data; re-arm the watch and read. */
+ active = false;
+ }
+
+ event_size = sizeof(*event) + event->len;
+ res -= event_size;
+ event_pos += event_size;
+ }
+ }
+}
+
+static int fuse_setup(struct fuse* fuse, gid_t gid, mode_t mask) {
+ char opts[256];
+
+ fuse->fd = open("/dev/fuse", O_RDWR);
+ if (fuse->fd == -1) {
+ PLOG(ERROR) << "failed to open fuse device";
+ return -1;
+ }
+
+ umount2(fuse->dest_path, MNT_DETACH);
+
+ snprintf(opts, sizeof(opts),
+ "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
+ fuse->fd, fuse->global->uid, fuse->global->gid);
+ if (mount("/dev/fuse", fuse->dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC |
+ MS_NOATIME, opts) != 0) {
+ PLOG(ERROR) << "failed to mount fuse filesystem";
+ return -1;
+ }
+
+ fuse->gid = gid;
+ fuse->mask = mask;
+
+ return 0;
+}
+
+static void drop_privs(uid_t uid, gid_t gid) {
+ ScopedMinijail j(minijail_new());
+ minijail_set_supplementary_gids(j.get(), arraysize(kGroups), kGroups);
+ minijail_change_gid(j.get(), gid);
+ minijail_change_uid(j.get(), uid);
+ /* minijail_enter() will abort if priv-dropping fails. */
+ minijail_enter(j.get());
+}
+
+static void* start_handler(void* data) {
+ struct fuse_handler* handler = static_cast<fuse_handler*>(data);
+ handle_fuse_requests(handler);
+ return NULL;
+}
+
+static void run(const char* source_path, const char* label, uid_t uid,
+ gid_t gid, userid_t userid, bool multi_user, bool full_write) {
+ struct fuse_global global;
+ struct fuse fuse_default;
+ struct fuse fuse_read;
+ struct fuse fuse_write;
+ struct fuse_handler handler_default;
+ struct fuse_handler handler_read;
+ struct fuse_handler handler_write;
+ pthread_t thread_default;
+ pthread_t thread_read;
+ pthread_t thread_write;
+
+ memset(&global, 0, sizeof(global));
+ memset(&fuse_default, 0, sizeof(fuse_default));
+ memset(&fuse_read, 0, sizeof(fuse_read));
+ memset(&fuse_write, 0, sizeof(fuse_write));
+ memset(&handler_default, 0, sizeof(handler_default));
+ memset(&handler_read, 0, sizeof(handler_read));
+ memset(&handler_write, 0, sizeof(handler_write));
+
+ pthread_mutex_init(&global.lock, NULL);
+ global.package_to_appid = new AppIdMap;
+ global.uid = uid;
+ global.gid = gid;
+ global.multi_user = multi_user;
+ global.next_generation = 0;
+ global.inode_ctr = 1;
+
+ memset(&global.root, 0, sizeof(global.root));
+ global.root.nid = FUSE_ROOT_ID; /* 1 */
+ global.root.refcount = 2;
+ global.root.namelen = strlen(source_path);
+ global.root.name = strdup(source_path);
+ global.root.userid = userid;
+ global.root.uid = AID_ROOT;
+ global.root.under_android = false;
+
+ strcpy(global.source_path, source_path);
+
+ if (multi_user) {
+ global.root.perm = PERM_PRE_ROOT;
+ snprintf(global.obb_path, sizeof(global.obb_path), "%s/obb", source_path);
+ } else {
+ global.root.perm = PERM_ROOT;
+ snprintf(global.obb_path, sizeof(global.obb_path), "%s/Android/obb", source_path);
+ }
+
+ fuse_default.global = &global;
+ fuse_read.global = &global;
+ fuse_write.global = &global;
+
+ global.fuse_default = &fuse_default;
+ global.fuse_read = &fuse_read;
+ global.fuse_write = &fuse_write;
+
+ snprintf(fuse_default.dest_path, PATH_MAX, "/mnt/runtime/default/%s", label);
+ snprintf(fuse_read.dest_path, PATH_MAX, "/mnt/runtime/read/%s", label);
+ snprintf(fuse_write.dest_path, PATH_MAX, "/mnt/runtime/write/%s", label);
+
+ handler_default.fuse = &fuse_default;
+ handler_read.fuse = &fuse_read;
+ handler_write.fuse = &fuse_write;
+
+ handler_default.token = 0;
+ handler_read.token = 1;
+ handler_write.token = 2;
+
+ umask(0);
+
+ if (multi_user) {
+ /* Multi-user storage is fully isolated per user, so "other"
+ * permissions are completely masked off. */
+ if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+ || fuse_setup(&fuse_read, AID_EVERYBODY, 0027)
+ || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0027)) {
+ PLOG(FATAL) << "failed to fuse_setup";
+ }
+ } else {
+ /* Physical storage is readable by all users on device, but
+ * the Android directories are masked off to a single user
+ * deep inside attr_from_stat(). */
+ if (fuse_setup(&fuse_default, AID_SDCARD_RW, 0006)
+ || fuse_setup(&fuse_read, AID_EVERYBODY, full_write ? 0027 : 0022)
+ || fuse_setup(&fuse_write, AID_EVERYBODY, full_write ? 0007 : 0022)) {
+ PLOG(FATAL) << "failed to fuse_setup";
+ }
+ }
+
+ // Will abort if priv-dropping fails.
+ drop_privs(uid, gid);
+
+ if (multi_user) {
+ fs_prepare_dir(global.obb_path, 0775, uid, gid);
+ }
+
+ if (pthread_create(&thread_default, NULL, start_handler, &handler_default)
+ || pthread_create(&thread_read, NULL, start_handler, &handler_read)
+ || pthread_create(&thread_write, NULL, start_handler, &handler_write)) {
+ LOG(FATAL) << "failed to pthread_create";
+ }
+
+ watch_package_list(&global);
+ LOG(FATAL) << "terminated prematurely";
+}
+
+static int usage() {
+ LOG(ERROR) << "usage: sdcard [OPTIONS] <source_path> <label>"
+ << " -u: specify UID to run as"
+ << " -g: specify GID to run as"
+ << " -U: specify user ID that owns device"
+ << " -m: source_path is multi-user"
+ << " -w: runtime write mount has full write access";
+ return 1;
+}
+
+int main(int argc, char **argv) {
+ const char *source_path = NULL;
+ const char *label = NULL;
+ uid_t uid = 0;
+ gid_t gid = 0;
+ userid_t userid = 0;
+ bool multi_user = false;
+ bool full_write = false;
+ int i;
+ struct rlimit rlim;
+ int fs_version;
+
+ int opt;
+ while ((opt = getopt(argc, argv, "u:g:U:mw")) != -1) {
+ switch (opt) {
+ case 'u':
+ uid = strtoul(optarg, NULL, 10);
+ break;
+ case 'g':
+ gid = strtoul(optarg, NULL, 10);
+ break;
+ case 'U':
+ userid = strtoul(optarg, NULL, 10);
+ break;
+ case 'm':
+ multi_user = true;
+ break;
+ case 'w':
+ full_write = true;
+ break;
+ case '?':
+ default:
+ return usage();
+ }
+ }
+
+ for (i = optind; i < argc; i++) {
+ char* arg = argv[i];
+ if (!source_path) {
+ source_path = arg;
+ } else if (!label) {
+ label = arg;
+ } else {
+ LOG(ERROR) << "too many arguments";
+ return usage();
+ }
+ }
+
+ if (!source_path) {
+ LOG(ERROR) << "no source path specified";
+ return usage();
+ }
+ if (!label) {
+ LOG(ERROR) << "no label specified";
+ return usage();
+ }
+ if (!uid || !gid) {
+ LOG(ERROR) << "uid and gid must be nonzero";
+ return usage();
+ }
+
+ rlim.rlim_cur = 8192;
+ rlim.rlim_max = 8192;
+ if (setrlimit(RLIMIT_NOFILE, &rlim)) {
+ PLOG(ERROR) << "setting RLIMIT_NOFILE failed";
+ }
+
+ while ((fs_read_atomic_int("/data/.layout_version", &fs_version) == -1) || (fs_version < 3)) {
+ LOG(ERROR) << "installd fs upgrade not yet complete; waiting...";
+ sleep(1);
+ }
+
+ run(source_path, label, uid, gid, userid, multi_user, full_write);
+ return 1;
+}
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 9ade759..4852fa4 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -3,7 +3,6 @@
common_cflags := \
-Werror -Wno-unused-parameter -Wno-unused-const-variable \
- -I$(LOCAL_PATH)/upstream-netbsd/include/ \
-include bsd-compatibility.h \
@@ -21,6 +20,7 @@
upstream-netbsd/lib/libc/string/swab.c \
upstream-netbsd/lib/libutil/raise_default_signal.c
LOCAL_CFLAGS += $(common_cflags) -Dmain=dd_main -DNO_CONV
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
LOCAL_MODULE := libtoolbox_dd
include $(BUILD_STATIC_LIBRARY)
@@ -32,31 +32,20 @@
OUR_TOOLS := \
getevent \
- iftop \
- ioctl \
- log \
- nandread \
newfs_msdos \
- ps \
- prlimit \
- sendevent \
- start \
- stop \
- top \
ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
LOCAL_SRC_FILES := \
- start_stop.cpp \
toolbox.c \
$(patsubst %,%.c,$(OUR_TOOLS)) \
LOCAL_CFLAGS += $(common_cflags)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
LOCAL_CONLYFLAGS += -std=gnu99
LOCAL_SHARED_LIBRARIES := \
libcutils \
- libselinux \
LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
@@ -72,7 +61,7 @@
$(LOCAL_PATH)/toolbox.c: $(intermediates)/tools.h
TOOLS_H := $(intermediates)/tools.h
-$(TOOLS_H): PRIVATE_TOOLS := $(ALL_TOOLS)
+$(TOOLS_H): PRIVATE_TOOLS := toolbox $(ALL_TOOLS)
$(TOOLS_H): PRIVATE_CUSTOM_TOOL = echo "/* file generated automatically */" > $@ ; for t in $(PRIVATE_TOOLS) ; do echo "TOOL($$t)" >> $@ ; done
$(TOOLS_H): $(LOCAL_PATH)/Android.mk
$(TOOLS_H):
@@ -80,7 +69,7 @@
$(LOCAL_PATH)/getevent.c: $(intermediates)/input.h-labels.h
-UAPI_INPUT_EVENT_CODES_H := bionic/libc/kernel/uapi/linux/input-event-codes.h
+UAPI_INPUT_EVENT_CODES_H := bionic/libc/kernel/uapi/linux/input.h bionic/libc/kernel/uapi/linux/input-event-codes.h
INPUT_H_LABELS_H := $(intermediates)/input.h-labels.h
$(INPUT_H_LABELS_H): PRIVATE_LOCAL_PATH := $(LOCAL_PATH)
# The PRIVATE_CUSTOM_TOOL line uses = to evaluate the output path late.
@@ -97,6 +86,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := r.c
LOCAL_CFLAGS += $(common_cflags)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
LOCAL_MODULE := r
LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)
@@ -111,6 +101,7 @@
upstream-netbsd/usr.bin/grep/queue.c \
upstream-netbsd/usr.bin/grep/util.c
LOCAL_CFLAGS += $(common_cflags)
+LOCAL_C_INCLUDES += $(LOCAL_PATH)/upstream-netbsd/include/
LOCAL_MODULE := grep
LOCAL_POST_INSTALL_CMD := $(hide) $(foreach t,egrep fgrep,ln -sf grep $(TARGET_OUT)/bin/$(t);)
include $(BUILD_EXECUTABLE)
diff --git a/toolbox/bsd-compatibility.h b/toolbox/bsd-compatibility.h
index 434d370..7c3ddd4 100644
--- a/toolbox/bsd-compatibility.h
+++ b/toolbox/bsd-compatibility.h
@@ -43,7 +43,7 @@
#define __type_fit(t, a) (0 == 0)
// TODO: should this be in our <sys/cdefs.h>?
-#define __arraycount(a) (sizeof(a) / sizeof(a[0]))
+#define __arraycount(a) (sizeof(a) / sizeof((a)[0]))
// This at least matches GNU dd(1) behavior.
#define SIGINFO SIGUSR1
diff --git a/toolbox/generate-input.h-labels.py b/toolbox/generate-input.h-labels.py
index a2b9111..c0e9fce 100755
--- a/toolbox/generate-input.h-labels.py
+++ b/toolbox/generate-input.h-labels.py
@@ -38,39 +38,40 @@
r = re.compile(r'#define\s+(\S+)\s+((?:0x)?\d+)')
-with open(sys.argv[1], 'r') as f:
- for line in f:
- m = r.match(line)
- if m:
- name = m.group(1)
- if name.startswith("INPUT_PROP_"):
- input_prop_list.append(name)
- elif name.startswith("EV_"):
- ev_list.append(name)
- elif name.startswith("SYN_"):
- syn_list.append(name)
- elif name.startswith("KEY_") or name.startswith("BTN_"):
- key_list.append(name)
- elif name.startswith("REL_"):
- rel_list.append(name)
- elif name.startswith("ABS_"):
- abs_list.append(name)
- elif name.startswith("SW_"):
- sw_list.append(name)
- elif name.startswith("MSC_"):
- msc_list.append(name)
- elif name.startswith("LED_"):
- led_list.append(name)
- elif name.startswith("REP_"):
- rep_list.append(name)
- elif name.startswith("SND_"):
- snd_list.append(name)
- elif name.startswith("MT_TOOL_"):
- mt_tool_list.append(name)
- elif name.startswith("FF_STATUS_"):
- ff_status_list.append(name)
- elif name.startswith("FF_"):
- ff_list.append(name)
+for arg in sys.argv[1:]:
+ with open(arg, 'r') as f:
+ for line in f:
+ m = r.match(line)
+ if m:
+ name = m.group(1)
+ if name.startswith("INPUT_PROP_"):
+ input_prop_list.append(name)
+ elif name.startswith("EV_"):
+ ev_list.append(name)
+ elif name.startswith("SYN_"):
+ syn_list.append(name)
+ elif name.startswith("KEY_") or name.startswith("BTN_"):
+ key_list.append(name)
+ elif name.startswith("REL_"):
+ rel_list.append(name)
+ elif name.startswith("ABS_"):
+ abs_list.append(name)
+ elif name.startswith("SW_"):
+ sw_list.append(name)
+ elif name.startswith("MSC_"):
+ msc_list.append(name)
+ elif name.startswith("LED_"):
+ led_list.append(name)
+ elif name.startswith("REP_"):
+ rep_list.append(name)
+ elif name.startswith("SND_"):
+ snd_list.append(name)
+ elif name.startswith("MT_TOOL_"):
+ mt_tool_list.append(name)
+ elif name.startswith("FF_STATUS_"):
+ ff_status_list.append(name)
+ elif name.startswith("FF_"):
+ ff_list.append(name)
def Dump(struct_name, values):
print('static struct label %s[] = {' % (struct_name))
diff --git a/toolbox/iftop.c b/toolbox/iftop.c
deleted file mode 100644
index 800c0f0..0000000
--- a/toolbox/iftop.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 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 <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-
-#define PROC_NET_DEV "/proc/net/dev"
-
-#define MAX_IF 8 /* max interfaces we can handle */
-
-#ifndef PAGE_SIZE
-# define PAGE_SIZE 4096
-#endif
-
-#define _STR(s) #s
-#define STR(s) _STR(s)
-
-struct if_stats {
- char name[IFNAMSIZ];
-
- unsigned int mtu;
-
- unsigned int rx_bytes;
- unsigned int rx_packets;
- unsigned int rx_errors;
- unsigned int rx_dropped;
-
- unsigned int tx_bytes;
- unsigned int tx_packets;
- unsigned int tx_errors;
- unsigned int tx_dropped;
-};
-
-static int get_mtu(const char *if_name)
-{
- struct ifreq ifr;
- int s, ret;
-
- s = socket(AF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket");
- exit(EXIT_FAILURE);
- }
-
- memset(&ifr, 0, sizeof(struct ifreq));
- ifr.ifr_addr.sa_family = AF_INET;
- strcpy(ifr.ifr_name, if_name);
-
- ret = ioctl(s, SIOCGIFMTU, &ifr);
- if (ret < 0) {
- perror("ioctl");
- exit(EXIT_FAILURE);
- }
-
- ret = close(s);
- if (ret < 0) {
- perror("close");
- exit(EXIT_FAILURE);
- }
-
- return ifr.ifr_mtu;
-}
-
-static int get_interfaces(struct if_stats *ifs)
-{
- char buf[PAGE_SIZE];
- char *p;
- int ret, nr, fd;
-
- fd = open(PROC_NET_DEV, O_RDONLY);
- if (fd < 0) {
- perror("open");
- exit(EXIT_FAILURE);
- }
-
- ret = read(fd, buf, sizeof(buf) - 1);
- if (ret < 0) {
- perror("read");
- exit(EXIT_FAILURE);
- } else if (!ret) {
- fprintf(stderr, "reading " PROC_NET_DEV " returned premature EOF\n");
- exit(EXIT_FAILURE);
- }
- buf[ret] = '\0';
-
- /* skip down to the third line */
- p = strchr(buf, '\n');
- if (!p) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
- p = strchr(p + 1, '\n');
- if (!p) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
- p += 1;
-
- /*
- * Key:
- * if: (Rx) bytes packets errs drop fifo frame compressed multicast \
- * (Tx) bytes packets errs drop fifo colls carrier compressed
- */
- for (nr = 0; nr < MAX_IF; nr++) {
- char *c;
-
- ret = sscanf(p, "%" STR(IFNAMSIZ) "s", ifs->name);
- if (ret != 1) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
-
- /*
- * This works around a bug in the proc file where large interface names
- * or Rx byte counts eat the delimiter, breaking sscanf.
- */
- c = strchr(ifs->name, ':');
- if (c)
- *c = '\0';
-
- p = strchr(p, ':') + 1;
-
- ret = sscanf(p, "%u %u %u %u %*u %*u %*u %*u %u %u %u %u %*u %*u "
- "%*u %*u\n", &ifs->rx_bytes, &ifs->rx_packets,
- &ifs->rx_errors, &ifs->rx_dropped, &ifs->tx_bytes,
- &ifs->tx_packets, &ifs->tx_errors, &ifs->tx_dropped);
- if (ret != 8) {
- fprintf(stderr, "parsing " PROC_NET_DEV " failed unexpectedly\n");
- exit(EXIT_FAILURE);
- }
-
- ifs->mtu = get_mtu(ifs->name);
-
- p = strchr(p, '\n') + 1;
- if (*p == '\0') {
- nr++;
- break;
- }
-
- ifs++;
- }
-
- ret = close(fd);
- if (ret) {
- perror("close");
- exit(EXIT_FAILURE);
- }
-
- return nr;
-}
-
-static void print_header(void)
-{
- printf(" Rx Tx\n");
- printf("%-8s %-5s %-10s %-8s %-5s %-5s %-10s %-8s %-5s %-5s\n",
- "name", "MTU", "bytes", "packets", "errs", "drpd", "bytes",
- "packets", "errs", "drpd");
-}
-
-static int print_interfaces(struct if_stats *old, struct if_stats *new, int nr)
-{
- int i = 0;
-
- while (nr--) {
- if (old->rx_packets || old->tx_packets) {
- printf("%-8s %-5u %-10u %-8u %-5u %-5u %-10u %-8u %-5u %-5u\n",
- new->name, new->mtu,
- new->rx_bytes - old->rx_bytes,
- new->rx_packets - old->rx_packets,
- new->rx_errors - old->rx_errors,
- new->rx_dropped - old->rx_dropped,
- new->tx_bytes - old->tx_bytes,
- new->tx_packets - old->tx_packets,
- new->tx_errors - old->tx_errors,
- new->tx_dropped - old->tx_dropped);
- i++;
- }
- old++;
- new++;
- }
-
- return i;
-}
-
-static void usage(const char *cmd)
-{
- fprintf(stderr, "usage: %s [ -r repeats] [ -d delay ]\n", cmd);
-}
-
-int iftop_main(int argc, char *argv[])
-{
- struct if_stats ifs[2][MAX_IF];
- int count = 0, header_interval = 22, delay = 1, i;
- unsigned int toggle = 0;
-
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-d")) {
- if (i >= argc - 1) {
- fprintf(stderr, "Option -d requires an argument.\n");
- exit(EXIT_FAILURE);
- }
- delay = atoi(argv[i++]);
- if (!delay)
- delay = 1;
- continue;
- }
- if (!strcmp(argv[i], "-r")) {
- if (i >= argc - 1) {
- fprintf(stderr, "Option -r requires an argument.\n");
- exit(EXIT_FAILURE);
- }
- header_interval = atoi(argv[i++]);
- if (header_interval < MAX_IF)
- header_interval = MAX_IF;
- continue;
- }
- if (!strcmp(argv[i], "-h")) {
- usage(argv[0]);
- exit(EXIT_SUCCESS);
- }
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- get_interfaces(ifs[!toggle]);
- if (header_interval)
- print_header();
- while (1) {
- int nr;
-
- sleep(delay);
- nr = get_interfaces(ifs[toggle]);
- if (header_interval && count + nr > header_interval) {
- print_header();
- count = 0;
- }
- count += print_interfaces(ifs[!toggle], ifs[toggle], nr);
- toggle = !toggle;
- }
-
- return 0;
-}
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
deleted file mode 100644
index 093e467..0000000
--- a/toolbox/ioctl.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 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 <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-static void usage() {
- fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
- " -l <length> Length of io buffer\n"
- " -a <argsize> Size of each argument (1-8)\n"
- " -r Open device in read only mode\n"
- " -d Direct argument (no iobuffer)\n"
- " -h Print help\n", getprogname());
- exit(1);
-}
-
-static int xstrtoi(const char* s, const char* what) {
- char* endp;
- errno = 0;
- long result = strtol(s, &endp, 0);
- if (errno != 0 || *endp != '\0') {
- error(1, errno, "couldn't parse %s '%s'", what, s);
- }
- if (result > INT_MAX || result < INT_MIN) {
- error(1, errno, "%s '%s' out of range", what, s);
- }
- return result;
-}
-
-int ioctl_main(int argc, char* argv[]) {
- int read_only = 0;
- int length = -1;
- int arg_size = 4;
- int direct_arg = 0;
-
- void *ioctl_args = NULL;
- uint8_t *ioctl_argp;
- uint8_t *ioctl_argp_save = NULL;
- int rem;
-
- int c;
- while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
- switch (c) {
- case 'r':
- read_only = 1;
- break;
- case 'd':
- direct_arg = 1;
- break;
- case 'l':
- length = xstrtoi(optarg, "length");
- break;
- case 'a':
- arg_size = xstrtoi(optarg, "argument size");
- break;
- case 'h':
- usage();
- break;
- default:
- error(1, 0, "invalid option -%c", optopt);
- }
- }
-
- if (optind + 2 > argc) {
- usage();
- }
-
- const char* device = argv[optind];
- int fd;
- if (strcmp(device, "-") == 0) {
- fd = STDIN_FILENO;
- } else {
- fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
- if (fd == -1) {
- error(1, errno, "cannot open %s", argv[optind]);
- }
- }
- optind++;
-
- // IOCTL(2) wants second parameter as a signed int.
- // Let's let the user specify either negative numbers or large positive
- // numbers, for the case where ioctl number is larger than INT_MAX.
- errno = 0;
- char* endp;
- int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0);
- if (errno != 0 || *endp != '\0') {
- error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]);
- }
- optind++;
-
- if(direct_arg) {
- arg_size = 4;
- length = 4;
- }
-
- if(length < 0) {
- length = (argc - optind) * arg_size;
- }
- if(length) {
- ioctl_args = calloc(1, length);
-
- ioctl_argp_save = ioctl_argp = ioctl_args;
- rem = length;
- while (optind < argc) {
- uint64_t tmp = strtoull(argv[optind], NULL, 0);
- if (rem < arg_size) {
- error(1, 0, "too many arguments");
- }
- memcpy(ioctl_argp, &tmp, arg_size);
- ioctl_argp += arg_size;
- rem -= arg_size;
- optind++;
- }
- }
- printf("sending ioctl 0x%x", ioctl_nr);
- rem = length;
- while(rem--) {
- printf(" 0x%02x", *ioctl_argp_save++);
- }
- printf(" to %s\n", device);
-
- int res;
- if(direct_arg)
- res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
- else if(length)
- res = ioctl(fd, ioctl_nr, ioctl_args);
- else
- res = ioctl(fd, ioctl_nr, 0);
- if (res < 0) {
- free(ioctl_args);
- error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
- }
-
- if (length) {
- printf("return buf:");
- ioctl_argp = ioctl_args;
- rem = length;
- while(rem--) {
- printf(" %02x", *ioctl_argp++);
- }
- printf("\n");
- }
- free(ioctl_args);
- close(fd);
- return 0;
-}
diff --git a/toolbox/log.c b/toolbox/log.c
deleted file mode 100644
index 2f020a8..0000000
--- a/toolbox/log.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 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 <log/logd.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <cutils/sockets.h>
-#include <unistd.h>
-
-/*
- * Note: also accepts 0-9 priorities
- * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
- */
-static android_LogPriority filterCharToPri (char c)
-{
- android_LogPriority pri;
-
- c = tolower(c);
-
- if (c >= '0' && c <= '9') {
- if (c >= ('0'+ANDROID_LOG_SILENT)) {
- pri = ANDROID_LOG_VERBOSE;
- } else {
- pri = (android_LogPriority)(c - '0');
- }
- } else if (c == 'v') {
- pri = ANDROID_LOG_VERBOSE;
- } else if (c == 'd') {
- pri = ANDROID_LOG_DEBUG;
- } else if (c == 'i') {
- pri = ANDROID_LOG_INFO;
- } else if (c == 'w') {
- pri = ANDROID_LOG_WARN;
- } else if (c == 'e') {
- pri = ANDROID_LOG_ERROR;
- } else if (c == 'f') {
- pri = ANDROID_LOG_FATAL;
- } else if (c == 's') {
- pri = ANDROID_LOG_SILENT;
- } else if (c == '*') {
- pri = ANDROID_LOG_DEFAULT;
- } else {
- pri = ANDROID_LOG_UNKNOWN;
- }
-
- return pri;
-}
-
-static int usage(const char *s)
-{
- fprintf(stderr, "USAGE: %s [-p priorityChar] [-t tag] message\n", s);
-
- fprintf(stderr, "\tpriorityChar should be one of:\n"
- "\t\tv,d,i,w,e\n");
- exit(-1);
-}
-
-
-int log_main(int argc, char *argv[])
-{
- android_LogPriority priority;
- const char *tag = "log";
- char buffer[4096];
- int i;
-
- priority = ANDROID_LOG_INFO;
-
- for (;;) {
- int ret;
-
- ret = getopt(argc, argv, "t:p:h");
-
- if (ret < 0) {
- break;
- }
-
- switch(ret) {
- case 't':
- tag = optarg;
- break;
-
- case 'p':
- priority = filterCharToPri(optarg[0]);
- if (priority == ANDROID_LOG_UNKNOWN) {
- usage(argv[0]);
- }
- break;
-
- case 'h':
- usage(argv[0]);
- break;
- }
- }
-
- if (optind == argc) {
- usage(argv[0]);
- }
-
- buffer[0] = '\0';
-
- for (i = optind ; i < argc ; i++) {
- strlcat(buffer, argv[i], sizeof(buffer)-1);
- strlcat(buffer, " ", sizeof(buffer)-1);
- }
-
- if(buffer[0] == 0) {
- usage(argv[0]);
- }
-
- __android_log_print(priority, tag, "%s", buffer);
-
- return 0;
-}
-
diff --git a/toolbox/nandread.c b/toolbox/nandread.c
deleted file mode 100644
index bd19942..0000000
--- a/toolbox/nandread.c
+++ /dev/null
@@ -1,287 +0,0 @@
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <mtd/mtd-user.h>
-#include <sys/ioctl.h>
-
-static int test_empty(const char *buf, size_t size)
-{
- while(size--) {
- if (*buf++ != (char) 0xff)
- return 0;
- }
- return 1;
-}
-
-int nandread_main(int argc, char **argv)
-{
- char *devname = NULL;
- char *filename = NULL;
- char *statusfilename = NULL;
- char *statusext = ".stat";
- int fd;
- int outfd = -1;
- FILE *statusfile = NULL;
- int ret;
- int verbose = 0;
- void *buffer;
- loff_t pos, opos, end, bpos;
- loff_t start = 0, len = 0;
- int c;
- int i;
- int empty_pages = 0;
- int page_count = 0;
- int bad_block;
- int rawmode = 0;
- uint32_t *oob_data;
- uint8_t *oob_fixed;
- size_t spare_size = 64;
- struct mtd_info_user mtdinfo;
- struct mtd_ecc_stats initial_ecc, last_ecc, ecc;
- struct mtd_oob_buf oobbuf;
- nand_ecclayout_t ecclayout;
-
- do {
- c = getopt(argc, argv, "d:f:s:S:L:Rhv");
- if (c == EOF)
- break;
- switch (c) {
- case 'd':
- devname = optarg;
- break;
- case 'f':
- filename = optarg;
- break;
- case 's':
- spare_size = atoi(optarg);
- break;
- case 'S':
- start = strtoll(optarg, NULL, 0);
- break;
- case 'L':
- len = strtoll(optarg, NULL, 0);
- break;
- case 'R':
- rawmode = 1;
- break;
- case 'v':
- verbose++;
- break;
- case 'h':
- fprintf(stderr, "%s [-d <dev>] [-f file] [-s sparesize] [-vh]\n"
- " -d <dev> Read from <dev>\n"
- " -f <file> Write to <file>\n"
- " -s <size> Number of spare bytes in file (default 64)\n"
- " -R Raw mode\n"
- " -S <start> Start offset (default 0)\n"
- " -L <len> Length (default 0)\n"
- " -v Print info\n"
- " -h Print help\n", argv[0]);
- return -1;
- case '?':
- fprintf(stderr, "%s: invalid option -%c\n",
- argv[0], optopt);
- exit(1);
- }
- } while (1);
-
- if (optind < argc) {
- fprintf(stderr, "%s: extra arguments\n", argv[0]);
- return 1;
- }
- if (!devname) {
- fprintf(stderr, "%s: specify device name\n", argv[0]);
- return 1;
- }
-
- fd = open(devname, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "cannot open %s, %s\n", devname, strerror(errno));
- return 1;
- }
-
- if (filename) {
- outfd = creat(filename, 0666);
- if (outfd < 0) {
- fprintf(stderr, "cannot open %s, %s\n", filename, strerror(errno));
- return 1;
- }
- statusfilename = malloc(strlen(filename) + strlen(statusext) + 1);
- strcpy(statusfilename, filename);
- strcat(statusfilename, statusext);
- statusfile = fopen(statusfilename, "w+");
- if (!statusfile) {
- fprintf(stderr, "cannot open %s, %s\n", statusfilename, strerror(errno));
- return 1;
- }
- }
-
- ret = ioctl(fd, MEMGETINFO, &mtdinfo);
- if (ret) {
- fprintf(stderr, "failed get mtd info for %s, %s\n",
- devname, strerror(errno));
- return 1;
- }
-
- if (verbose) {
- printf("size: %u\n", mtdinfo.size);
- printf("erase size: %u\n", mtdinfo.erasesize);
- printf("write size: %u\n", mtdinfo.writesize);
- printf("oob size: %u\n", mtdinfo.oobsize);
- }
-
- buffer = malloc(mtdinfo.writesize + mtdinfo.oobsize + spare_size);
- if (!buffer) {
- fprintf(stderr, "failed allocate readbuffer size %u\n",
- mtdinfo.writesize + mtdinfo.oobsize);
- return 1;
- }
-
- oobbuf.length = mtdinfo.oobsize;
- oob_data = (uint32_t *)((uint8_t *)buffer + mtdinfo.writesize);
- memset(oob_data, 0xff, mtdinfo.oobsize + spare_size);
- oobbuf.ptr = (uint8_t *)oob_data + spare_size;
-
- ret = ioctl(fd, ECCGETLAYOUT, &ecclayout);
- if (ret) {
- fprintf(stderr, "failed get ecc layout for %s, %s\n",
- devname, strerror(errno));
- return 1;
- }
- if (verbose) {
- printf("ecc bytes: %u\n", ecclayout.eccbytes);
- printf("oobavail: %u\n", ecclayout.oobavail);
- }
- if (ecclayout.oobavail > spare_size)
- printf("oobavail, %d > image spare size, %zu\n", ecclayout.oobavail, spare_size);
-
- ret = ioctl(fd, ECCGETSTATS, &initial_ecc);
- if (ret) {
- fprintf(stderr, "failed get ecc stats for %s, %s\n",
- devname, strerror(errno));
- return 1;
- }
- last_ecc = initial_ecc;
-
- if (verbose) {
- printf("initial ecc corrected: %u\n", initial_ecc.corrected);
- printf("initial ecc failed: %u\n", initial_ecc.failed);
- printf("initial ecc badblocks: %u\n", initial_ecc.badblocks);
- printf("initial ecc bbtblocks: %u\n", initial_ecc.bbtblocks);
- }
-
- if (rawmode) {
- rawmode = mtdinfo.oobsize;
- ret = ioctl(fd, MTDFILEMODE, MTD_FILE_MODE_RAW);
- if (ret) {
- fprintf(stderr, "failed set raw mode for %s, %s\n",
- devname, strerror(errno));
- return 1;
- }
- }
-
- end = len ? (start + len) : mtdinfo.size;
- for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) {
- bad_block = 0;
- if (verbose > 3)
- printf("reading at %" PRIx64 "\n", pos);
- lseek64(fd, pos, SEEK_SET);
- ret = read(fd, buffer, mtdinfo.writesize + rawmode);
- if (ret < (int)mtdinfo.writesize) {
- fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret);
- bad_block = 2;
- }
- if (!rawmode) {
- oobbuf.start = pos;
- ret = ioctl(fd, MEMREADOOB, &oobbuf);
- if (ret) {
- fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret);
- bad_block = 2;
- }
- }
- ret = ioctl(fd, ECCGETSTATS, &ecc);
- if (ret) {
- fprintf(stderr, "failed get ecc stats for %s, %s\n",
- devname, strerror(errno));
- return 1;
- }
- bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize;
- ret = ioctl(fd, MEMGETBADBLOCK, &bpos);
- if (ret && errno != EOPNOTSUPP) {
- printf("badblock at %" PRIx64 "\n", pos);
- bad_block = 1;
- }
- if (ecc.corrected != last_ecc.corrected)
- printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos);
- if (ecc.failed != last_ecc.failed)
- printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos);
- if (ecc.badblocks != last_ecc.badblocks)
- printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos);
- if (ecc.bbtblocks != last_ecc.bbtblocks)
- printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos);
-
- if (!rawmode) {
- oob_fixed = (uint8_t *)oob_data;
- for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES; i++) {
- int len = ecclayout.oobfree[i].length;
- if (oob_fixed + len > oobbuf.ptr)
- len = oobbuf.ptr - oob_fixed;
- if (len) {
- memcpy(oob_fixed, oobbuf.ptr + ecclayout.oobfree[i].offset, len);
- oob_fixed += len;
- }
- }
- }
-
- if (outfd >= 0) {
- ret = write(outfd, buffer, mtdinfo.writesize + spare_size);
- if (ret < (int)(mtdinfo.writesize + spare_size)) {
- fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret);
- close(outfd);
- outfd = -1;
- }
- if (ecc.corrected != last_ecc.corrected)
- fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos);
- if (ecc.failed != last_ecc.failed)
- fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos);
- if (bad_block == 1)
- fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos);
- if (bad_block == 2)
- fprintf(statusfile, "%08" PRIx64 ": read error\n", opos);
- opos += mtdinfo.writesize + spare_size;
- }
-
- last_ecc = ecc;
- page_count++;
- if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size))
- empty_pages++;
- else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1))))
- printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x "
- "%08x %08x %08x %08x\n", pos, oobbuf.start,
- oob_data[0], oob_data[1], oob_data[2], oob_data[3],
- oob_data[4], oob_data[5], oob_data[6], oob_data[7]);
- }
-
- if (outfd >= 0) {
- fprintf(statusfile, "read %d pages, %d empty\n", page_count, empty_pages);
- fprintf(statusfile, "total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
- fprintf(statusfile, "total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
- fprintf(statusfile, "total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
- fprintf(statusfile, "total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
- }
- if (verbose) {
- printf("total ecc corrected, %u\n", ecc.corrected - initial_ecc.corrected);
- printf("total ecc failed, %u\n", ecc.failed - initial_ecc.failed);
- printf("total ecc badblocks, %u\n", ecc.badblocks - initial_ecc.badblocks);
- printf("total ecc bbtblocks, %u\n", ecc.bbtblocks - initial_ecc.bbtblocks);
- }
- printf("read %d pages, %d empty\n", page_count, empty_pages);
-
- return 0;
-}
diff --git a/toolbox/newfs_msdos.c b/toolbox/newfs_msdos.c
index 5b98a01..27ea9e8 100644
--- a/toolbox/newfs_msdos.c
+++ b/toolbox/newfs_msdos.c
@@ -695,7 +695,7 @@
(u_int)tm->tm_min));
mk4(bsx->volid, x);
mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
- sprintf(buf, "FAT%u", fat);
+ snprintf(buf, sizeof(buf), "FAT%u", fat);
setstr(bsx->type, buf, sizeof(bsx->type));
if (!opt_B) {
x1 += sizeof(struct bsx);
diff --git a/toolbox/prlimit.c b/toolbox/prlimit.c
deleted file mode 100644
index 8cf202a..0000000
--- a/toolbox/prlimit.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2014, 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.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 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 <unistd.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-static void
-usage(const char *s)
-{
- fprintf(stderr, "usage: %s pid resource cur max\n", s);
- exit(EXIT_FAILURE);
-}
-
-int prlimit_main(int argc, char *argv[])
-{
- pid_t pid;
- struct rlimit64 rl;
- int resource;
- int rc;
-
- if (argc != 5)
- usage(*argv);
-
- if (sscanf(argv[1], "%d", &pid) != 1)
- usage(*argv);
-
- if (sscanf(argv[2], "%d", &resource) != 1)
- usage(*argv);
-
- if (sscanf(argv[3], "%llu", &rl.rlim_cur) != 1)
- usage(*argv);
-
- if (sscanf(argv[4], "%llu", &rl.rlim_max) != 1)
- usage(*argv);
-
- printf("setting resource %d of pid %d to [%llu,%llu]\n", resource, pid,
- rl.rlim_cur, rl.rlim_max);
- rc = prlimit64(pid, resource, &rl, NULL);
- if (rc < 0) {
- perror("prlimit");
- exit(EXIT_FAILURE);
- }
-
- return 0;
-}
diff --git a/toolbox/ps.c b/toolbox/ps.c
deleted file mode 100644
index 7e70c71..0000000
--- a/toolbox/ps.c
+++ /dev/null
@@ -1,334 +0,0 @@
-#include <ctype.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/sched_policy.h>
-
-static char *nexttoksep(char **strp, char *sep)
-{
- char *p = strsep(strp,sep);
- return (p == 0) ? "" : p;
-}
-static char *nexttok(char **strp)
-{
- return nexttoksep(strp, " ");
-}
-
-#define SHOW_PRIO 1
-#define SHOW_TIME 2
-#define SHOW_POLICY 4
-#define SHOW_CPU 8
-#define SHOW_MACLABEL 16
-#define SHOW_NUMERIC_UID 32
-#define SHOW_ABI 64
-
-#if __LP64__
-#define PC_WIDTH 10 /* Realistically, the top bits will be 0, so don't waste space. */
-#else
-#define PC_WIDTH (2*sizeof(uintptr_t))
-#endif
-
-static int display_flags = 0;
-static int ppid_filter = 0;
-
-static void print_exe_abi(int pid);
-
-static int ps_line(int pid, int tid)
-{
- char statline[1024];
- char cmdline[1024];
- char macline[1024];
- char user[32];
- struct stat stats;
- int r;
- char *ptr, *name, *state;
- int ppid;
- unsigned rss, vss;
- uintptr_t eip;
- unsigned utime, stime;
- int prio, nice, rtprio, sched, psr;
- struct passwd *pw;
-
- sprintf(statline, "/proc/%d", tid ? tid : pid);
- stat(statline, &stats);
-
- if(tid) {
- sprintf(statline, "/proc/%d/task/%d/stat", pid, tid);
- cmdline[0] = 0;
- snprintf(macline, sizeof(macline), "/proc/%d/task/%d/attr/current", pid, tid);
- } else {
- sprintf(statline, "/proc/%d/stat", pid);
- sprintf(cmdline, "/proc/%d/cmdline", pid);
- snprintf(macline, sizeof(macline), "/proc/%d/attr/current", pid);
- int fd = open(cmdline, O_RDONLY);
- if(fd == 0) {
- r = 0;
- } else {
- r = read(fd, cmdline, 1023);
- close(fd);
- if(r < 0) r = 0;
- }
- cmdline[r] = 0;
- }
-
- int fd = open(statline, O_RDONLY);
- if(fd == 0) return -1;
- r = read(fd, statline, 1023);
- close(fd);
- if(r < 0) return -1;
- statline[r] = 0;
-
- ptr = statline;
- nexttok(&ptr); // skip pid
- ptr++; // skip "("
-
- name = ptr;
- ptr = strrchr(ptr, ')'); // Skip to *last* occurence of ')',
- *ptr++ = '\0'; // and null-terminate name.
-
- ptr++; // skip " "
- state = nexttok(&ptr);
- ppid = atoi(nexttok(&ptr));
- nexttok(&ptr); // pgrp
- nexttok(&ptr); // sid
- nexttok(&ptr); // tty
- nexttok(&ptr); // tpgid
- nexttok(&ptr); // flags
- nexttok(&ptr); // minflt
- nexttok(&ptr); // cminflt
- nexttok(&ptr); // majflt
- nexttok(&ptr); // cmajflt
-#if 1
- utime = atoi(nexttok(&ptr));
- stime = atoi(nexttok(&ptr));
-#else
- nexttok(&ptr); // utime
- nexttok(&ptr); // stime
-#endif
- nexttok(&ptr); // cutime
- nexttok(&ptr); // cstime
- prio = atoi(nexttok(&ptr));
- nice = atoi(nexttok(&ptr));
- nexttok(&ptr); // threads
- nexttok(&ptr); // itrealvalue
- nexttok(&ptr); // starttime
- vss = strtoul(nexttok(&ptr), 0, 10); // vsize
- rss = strtoul(nexttok(&ptr), 0, 10); // rss
- nexttok(&ptr); // rlim
- nexttok(&ptr); // startcode
- nexttok(&ptr); // endcode
- nexttok(&ptr); // startstack
- nexttok(&ptr); // kstkesp
- eip = strtoul(nexttok(&ptr), 0, 10); // kstkeip
- nexttok(&ptr); // signal
- nexttok(&ptr); // blocked
- nexttok(&ptr); // sigignore
- nexttok(&ptr); // sigcatch
- nexttok(&ptr); // wchan
- nexttok(&ptr); // nswap
- nexttok(&ptr); // cnswap
- nexttok(&ptr); // exit signal
- psr = atoi(nexttok(&ptr)); // processor
- rtprio = atoi(nexttok(&ptr)); // rt_priority
- sched = atoi(nexttok(&ptr)); // scheduling policy
-
- nexttok(&ptr); // tty
-
- if(tid != 0) {
- ppid = pid;
- pid = tid;
- }
-
- pw = getpwuid(stats.st_uid);
- if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) {
- sprintf(user,"%d",(int)stats.st_uid);
- } else {
- strcpy(user,pw->pw_name);
- }
-
- if(ppid_filter != 0 && ppid != ppid_filter) {
- return 0;
- }
-
- if (display_flags & SHOW_MACLABEL) {
- fd = open(macline, O_RDONLY);
- strcpy(macline, "-");
- if (fd >= 0) {
- r = read(fd, macline, sizeof(macline)-1);
- close(fd);
- if (r > 0)
- macline[r] = 0;
- }
- printf("%-30s ", macline);
- }
-
- printf("%-9s %-5d %-5d %-6d %-5d", user, pid, ppid, vss / 1024, rss * 4);
- if (display_flags & SHOW_CPU)
- printf(" %-2d", psr);
- if (display_flags & SHOW_PRIO)
- printf(" %-5d %-5d %-5d %-5d", prio, nice, rtprio, sched);
- if (display_flags & SHOW_POLICY) {
- SchedPolicy p;
- if (get_sched_policy(pid, &p) < 0)
- printf(" un ");
- else
- printf(" %.2s ", get_sched_policy_name(p));
- }
- char path[PATH_MAX];
- snprintf(path, sizeof(path), "/proc/%d/wchan", pid);
- char wchan[10];
- fd = open(path, O_RDONLY);
- ssize_t wchan_len = read(fd, wchan, sizeof(wchan));
- if (wchan_len == -1) {
- wchan[wchan_len = 0] = '\0';
- }
- close(fd);
- printf(" %10.*s %0*" PRIxPTR " %s ", (int) wchan_len, wchan, (int) PC_WIDTH, eip, state);
- if (display_flags & SHOW_ABI) {
- print_exe_abi(pid);
- }
- printf("%s", cmdline[0] ? cmdline : name);
- if(display_flags&SHOW_TIME)
- printf(" (u:%d, s:%d)", utime, stime);
-
- printf("\n");
- return 0;
-}
-
-static void print_exe_abi(int pid)
-{
- int fd, r;
- char exeline[1024];
-
- sprintf(exeline, "/proc/%d/exe", pid);
- fd = open(exeline, O_RDONLY);
- if(fd == 0) {
- printf(" ");
- return;
- }
- r = read(fd, exeline, 5 /* 4 byte ELFMAG + 1 byte EI_CLASS */);
- close(fd);
- if(r < 0) {
- printf(" ");
- return;
- }
- if (memcmp("\177ELF", exeline, 4) != 0) {
- printf("?? ");
- return;
- }
- switch (exeline[4]) {
- case 1:
- printf("32 ");
- return;
- case 2:
- printf("64 ");
- return;
- default:
- printf("?? ");
- return;
- }
-}
-
-void ps_threads(int pid)
-{
- char tmp[128];
- DIR *d;
- struct dirent *de;
-
- sprintf(tmp,"/proc/%d/task",pid);
- d = opendir(tmp);
- if(d == 0) return;
-
- while((de = readdir(d)) != 0){
- if(isdigit(de->d_name[0])){
- int tid = atoi(de->d_name);
- if(tid == pid) continue;
- ps_line(pid, tid);
- }
- }
- closedir(d);
-}
-
-int ps_main(int argc, char **argv)
-{
- DIR *d;
- struct dirent *de;
- int pidfilter = 0;
- int threads = 0;
-
- while(argc > 1){
- if(!strcmp(argv[1],"-t")) {
- threads = 1;
- } else if(!strcmp(argv[1],"-n")) {
- display_flags |= SHOW_NUMERIC_UID;
- } else if(!strcmp(argv[1],"-x")) {
- display_flags |= SHOW_TIME;
- } else if(!strcmp(argv[1], "-Z")) {
- display_flags |= SHOW_MACLABEL;
- } else if(!strcmp(argv[1],"-P")) {
- display_flags |= SHOW_POLICY;
- } else if(!strcmp(argv[1],"-p")) {
- display_flags |= SHOW_PRIO;
- } else if(!strcmp(argv[1],"-c")) {
- display_flags |= SHOW_CPU;
- } else if(!strcmp(argv[1],"--abi")) {
- display_flags |= SHOW_ABI;
- } else if(!strcmp(argv[1],"--ppid")) {
- ppid_filter = atoi(argv[2]);
- if (ppid_filter == 0) {
- /* Bug 26554285: Use printf because some apps require at least
- * one line of output to stdout even for errors.
- */
- printf("bad ppid '%s'\n", argv[2]);
- return 1;
- }
- argc--;
- argv++;
- } else {
- pidfilter = atoi(argv[1]);
- if (pidfilter == 0) {
- /* Bug 26554285: Use printf because some apps require at least
- * one line of output to stdout even for errors.
- */
- printf("bad pid '%s'\n", argv[1]);
- return 1;
- }
- }
- argc--;
- argv++;
- }
-
- if (display_flags & SHOW_MACLABEL) {
- printf("LABEL ");
- }
- printf("USER PID PPID VSIZE RSS %s%s %sWCHAN %*s %sNAME\n",
- (display_flags&SHOW_CPU)?"CPU ":"",
- (display_flags&SHOW_PRIO)?"PRIO NICE RTPRI SCHED ":"",
- (display_flags&SHOW_POLICY)?"PCY " : "",
- (int) PC_WIDTH, "PC",
- (display_flags&SHOW_ABI)?"ABI " : "");
-
- d = opendir("/proc");
- if(d == 0) return -1;
-
- while((de = readdir(d)) != 0){
- if(isdigit(de->d_name[0])){
- int pid = atoi(de->d_name);
- if(!pidfilter || (pidfilter == pid)) {
- ps_line(pid, 0);
- if(threads) ps_threads(pid);
- }
- }
- }
- closedir(d);
- return 0;
-}
-
diff --git a/toolbox/sendevent.c b/toolbox/sendevent.c
deleted file mode 100644
index 4d0ca17..0000000
--- a/toolbox/sendevent.c
+++ /dev/null
@@ -1,42 +0,0 @@
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-int sendevent_main(int argc, char *argv[])
-{
- int fd;
- ssize_t ret;
- int version;
- struct input_event event;
-
- if(argc != 5) {
- fprintf(stderr, "use: %s device type code value\n", argv[0]);
- return 1;
- }
-
- fd = open(argv[1], O_RDWR);
- if(fd < 0) {
- fprintf(stderr, "could not open %s, %s\n", argv[optind], strerror(errno));
- return 1;
- }
- if (ioctl(fd, EVIOCGVERSION, &version)) {
- fprintf(stderr, "could not get driver version for %s, %s\n", argv[optind], strerror(errno));
- return 1;
- }
- memset(&event, 0, sizeof(event));
- event.type = atoi(argv[2]);
- event.code = atoi(argv[3]);
- event.value = atoi(argv[4]);
- ret = write(fd, &event, sizeof(event));
- if(ret < (ssize_t) sizeof(event)) {
- fprintf(stderr, "write event failed, %s\n", strerror(errno));
- return -1;
- }
- return 0;
-}
diff --git a/toolbox/start.c b/toolbox/start.c
deleted file mode 100644
index cca5fef..0000000
--- a/toolbox/start.c
+++ /dev/null
@@ -1 +0,0 @@
-/* Needed by Android.mk. Actual code in start_stop.cpp. */
diff --git a/toolbox/start_stop.cpp b/toolbox/start_stop.cpp
deleted file mode 100644
index dc48c0c..0000000
--- a/toolbox/start_stop.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <error.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <cutils/properties.h>
-
-static const char* services[] = {
- "netd",
- "surfaceflinger",
- "zygote",
- "zygote_secondary",
-};
-
-static int start_stop(bool start, int argc, char* argv[]) {
- if (getuid() != 0) error(1, 0, "must be root");
- const char* property = start ? "ctl.start" : "ctl.stop";
- if (argc > 2) {
- error(1, 0, "usage: %s [SERVICE]\n", argv[0]);
- } else if (argc == 2) {
- property_set(property, argv[1]);
- } else {
- if (start) {
- for (size_t i = 0; i < sizeof(services)/sizeof(services[0]); ++i) {
- property_set(property, services[i]);
- }
- } else {
- for (int i = sizeof(services)/sizeof(services[0]) - 1; i >= 0; --i) {
- property_set(property, services[i]);
- }
- }
- }
- return 0;
-}
-
-extern "C" int start_main(int argc, char* argv[]) {
- return start_stop(true, argc, argv);
-}
-
-extern "C" int stop_main(int argc, char* argv[]) {
- return start_stop(false, argc, argv);
-}
diff --git a/toolbox/stop.c b/toolbox/stop.c
deleted file mode 100644
index cca5fef..0000000
--- a/toolbox/stop.c
+++ /dev/null
@@ -1 +0,0 @@
-/* Needed by Android.mk. Actual code in start_stop.cpp. */
diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c
index 915da44..b5a942c 100644
--- a/toolbox/toolbox.c
+++ b/toolbox/toolbox.c
@@ -4,29 +4,14 @@
#include <string.h>
#include <unistd.h>
-int main(int, char **);
-
-static int toolbox_main(int argc, char **argv)
-{
- // "toolbox foo ..." is equivalent to "foo ..."
- if (argc > 1) {
- return main(argc - 1, argv + 1);
- } else {
- printf("Toolbox!\n");
- return 0;
- }
-}
-
#define TOOL(name) int name##_main(int, char**);
#include "tools.h"
#undef TOOL
-static struct
-{
- const char *name;
+static struct {
+ const char* name;
int (*func)(int, char**);
} tools[] = {
- { "toolbox", toolbox_main },
#define TOOL(name) { #name, name##_main },
#include "tools.h"
#undef TOOL
@@ -40,33 +25,35 @@
_exit(0);
}
-int main(int argc, char **argv)
-{
- int i;
- char *name = argv[0];
-
+int main(int argc, char** argv) {
// Let's assume that none of this code handles broken pipes. At least ls,
// ps, and top were broken (though I'd previously added this fix locally
// to top). We exit rather than use SIG_IGN because tools like top will
// just keep on writing to nowhere forever if we don't stop them.
signal(SIGPIPE, SIGPIPE_handler);
- if((argc > 1) && (argv[1][0] == '@')) {
- name = argv[1] + 1;
- argc--;
- argv++;
- } else {
- char *cmd = strrchr(argv[0], '/');
- if (cmd)
- name = cmd + 1;
- }
+ char* cmd = strrchr(argv[0], '/');
+ char* name = cmd ? (cmd + 1) : argv[0];
- for(i = 0; tools[i].name; i++){
- if(!strcmp(tools[i].name, name)){
+ for (size_t i = 0; tools[i].name; i++) {
+ if (!strcmp(tools[i].name, name)) {
return tools[i].func(argc, argv);
}
}
printf("%s: no such tool\n", argv[0]);
- return -1;
+ return 127;
+}
+
+int toolbox_main(int argc, char** argv) {
+ // "toolbox foo ..." is equivalent to "foo ..."
+ if (argc > 1) {
+ return main(argc - 1, argv + 1);
+ }
+
+ // Plain "toolbox" lists the tools.
+ for (size_t i = 1; tools[i].name; i++) {
+ printf("%s%c", tools[i].name, tools[i+1].name ? ' ' : '\n');
+ }
+ return 0;
}
diff --git a/toolbox/top.c b/toolbox/top.c
deleted file mode 100644
index 6fda132..0000000
--- a/toolbox/top.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 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 <ctype.h>
-#include <dirent.h>
-#include <grp.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/sched_policy.h>
-
-struct cpu_info {
- long unsigned utime, ntime, stime, itime;
- long unsigned iowtime, irqtime, sirqtime;
-};
-
-#define PROC_NAME_LEN 64
-#define THREAD_NAME_LEN 32
-#define POLICY_NAME_LEN 4
-
-struct proc_info {
- struct proc_info *next;
- pid_t pid;
- pid_t tid;
- uid_t uid;
- gid_t gid;
- char name[PROC_NAME_LEN];
- char tname[THREAD_NAME_LEN];
- char state;
- uint64_t utime;
- uint64_t stime;
- char pr[3];
- long ni;
- uint64_t delta_utime;
- uint64_t delta_stime;
- uint64_t delta_time;
- uint64_t vss;
- uint64_t rss;
- int num_threads;
- char policy[POLICY_NAME_LEN];
-};
-
-struct proc_list {
- struct proc_info **array;
- int size;
-};
-
-#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
-
-#define INIT_PROCS 50
-#define THREAD_MULT 8
-static struct proc_info **old_procs, **new_procs;
-static int num_old_procs, num_new_procs;
-static struct proc_info *free_procs;
-static int num_used_procs, num_free_procs;
-
-static int max_procs, delay, iterations, threads;
-
-static struct cpu_info old_cpu, new_cpu;
-
-static struct proc_info *alloc_proc(void);
-static void free_proc(struct proc_info *proc);
-static void read_procs(void);
-static int read_stat(char *filename, struct proc_info *proc);
-static void read_policy(int pid, struct proc_info *proc);
-static void add_proc(int proc_num, struct proc_info *proc);
-static int read_cmdline(char *filename, struct proc_info *proc);
-static int read_status(char *filename, struct proc_info *proc);
-static void print_procs(void);
-static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
-static void free_old_procs(void);
-static int (*proc_cmp)(const void *a, const void *b);
-static int proc_cpu_cmp(const void *a, const void *b);
-static int proc_vss_cmp(const void *a, const void *b);
-static int proc_rss_cmp(const void *a, const void *b);
-static int proc_thr_cmp(const void *a, const void *b);
-static int numcmp(long long a, long long b);
-static void usage(char *cmd);
-
-int top_main(int argc, char *argv[]) {
- num_used_procs = num_free_procs = 0;
-
- max_procs = 0;
- delay = 3;
- iterations = -1;
- proc_cmp = &proc_cpu_cmp;
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-m")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -m expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- max_procs = atoi(argv[++i]);
- continue;
- }
- if (!strcmp(argv[i], "-n")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -n expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- iterations = atoi(argv[++i]);
- continue;
- }
- if (!strcmp(argv[i], "-d")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -d expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- delay = atoi(argv[++i]);
- continue;
- }
- if (!strcmp(argv[i], "-s")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -s expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- ++i;
- if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
- if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
- if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
- if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
- fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
- exit(EXIT_FAILURE);
- }
- if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "-t")) { threads = 1; continue; }
- if (!strcmp(argv[i], "-h")) {
- usage(argv[0]);
- exit(EXIT_SUCCESS);
- }
- fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (threads && proc_cmp == &proc_thr_cmp) {
- fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
- exit(EXIT_FAILURE);
- }
-
- free_procs = NULL;
-
- num_new_procs = num_old_procs = 0;
- new_procs = old_procs = NULL;
-
- read_procs();
- while ((iterations == -1) || (iterations-- > 0)) {
- old_procs = new_procs;
- num_old_procs = num_new_procs;
- memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
- read_procs();
- print_procs();
- free_old_procs();
- fflush(stdout);
- if (iterations != 0) sleep(delay);
- }
-
- return 0;
-}
-
-static struct proc_info *alloc_proc(void) {
- struct proc_info *proc;
-
- if (free_procs) {
- proc = free_procs;
- free_procs = free_procs->next;
- num_free_procs--;
- } else {
- proc = malloc(sizeof(*proc));
- if (!proc) die("Could not allocate struct process_info.\n");
- }
-
- num_used_procs++;
-
- return proc;
-}
-
-static void free_proc(struct proc_info *proc) {
- proc->next = free_procs;
- free_procs = proc;
-
- num_used_procs--;
- num_free_procs++;
-}
-
-#define MAX_LINE 256
-
-static void read_procs(void) {
- DIR *proc_dir, *task_dir;
- struct dirent *pid_dir, *tid_dir;
- char filename[64];
- FILE *file;
- int proc_num;
- struct proc_info *proc;
- pid_t pid, tid;
-
- int i;
-
- proc_dir = opendir("/proc");
- if (!proc_dir) die("Could not open /proc.\n");
-
- new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
- num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
-
- file = fopen("/proc/stat", "r");
- if (!file) die("Could not open /proc/stat.\n");
- fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
- &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
- fclose(file);
-
- proc_num = 0;
- while ((pid_dir = readdir(proc_dir))) {
- if (!isdigit(pid_dir->d_name[0]))
- continue;
-
- pid = atoi(pid_dir->d_name);
-
- struct proc_info cur_proc;
-
- if (!threads) {
- proc = alloc_proc();
-
- proc->pid = proc->tid = pid;
-
- sprintf(filename, "/proc/%d/stat", pid);
- read_stat(filename, proc);
-
- sprintf(filename, "/proc/%d/cmdline", pid);
- read_cmdline(filename, proc);
-
- sprintf(filename, "/proc/%d/status", pid);
- read_status(filename, proc);
-
- read_policy(pid, proc);
-
- proc->num_threads = 0;
- } else {
- sprintf(filename, "/proc/%d/cmdline", pid);
- read_cmdline(filename, &cur_proc);
-
- sprintf(filename, "/proc/%d/status", pid);
- read_status(filename, &cur_proc);
-
- proc = NULL;
- }
-
- sprintf(filename, "/proc/%d/task", pid);
- task_dir = opendir(filename);
- if (!task_dir) continue;
-
- while ((tid_dir = readdir(task_dir))) {
- if (!isdigit(tid_dir->d_name[0]))
- continue;
-
- if (threads) {
- tid = atoi(tid_dir->d_name);
-
- proc = alloc_proc();
-
- proc->pid = pid; proc->tid = tid;
-
- sprintf(filename, "/proc/%d/task/%d/stat", pid, tid);
- read_stat(filename, proc);
-
- read_policy(tid, proc);
-
- strcpy(proc->name, cur_proc.name);
- proc->uid = cur_proc.uid;
- proc->gid = cur_proc.gid;
-
- add_proc(proc_num++, proc);
- } else {
- proc->num_threads++;
- }
- }
-
- closedir(task_dir);
-
- if (!threads)
- add_proc(proc_num++, proc);
- }
-
- for (i = proc_num; i < num_new_procs; i++)
- new_procs[i] = NULL;
-
- closedir(proc_dir);
-}
-
-static int read_stat(char *filename, struct proc_info *proc) {
- FILE *file;
- char buf[MAX_LINE], *open_paren, *close_paren;
-
- file = fopen(filename, "r");
- if (!file) return 1;
- fgets(buf, MAX_LINE, file);
- fclose(file);
-
- /* Split at first '(' and last ')' to get process name. */
- open_paren = strchr(buf, '(');
- close_paren = strrchr(buf, ')');
- if (!open_paren || !close_paren) return 1;
-
- *open_paren = *close_paren = '\0';
- strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
- proc->tname[THREAD_NAME_LEN-1] = 0;
-
- // Scan rest of string.
- long pr;
- sscanf(close_paren + 1,
- " %c "
- "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%" SCNu64 // utime %lu (14)
- "%" SCNu64 // stime %lu (15)
- "%*d %*d "
- "%ld " // priority %ld (18)
- "%ld " // nice %ld (19)
- "%*d %*d %*d "
- "%" SCNu64 // vsize %lu (23)
- "%" SCNu64, // rss %ld (24)
- &proc->state,
- &proc->utime,
- &proc->stime,
- &pr,
- &proc->ni,
- &proc->vss,
- &proc->rss);
-
- // Translate the PR field.
- if (pr < -9) strcpy(proc->pr, "RT");
- else snprintf(proc->pr, sizeof(proc->pr), "%ld", pr);
-
- return 0;
-}
-
-static void add_proc(int proc_num, struct proc_info *proc) {
- int i;
-
- if (proc_num >= num_new_procs) {
- new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *));
- if (!new_procs) die("Could not expand procs array.\n");
- for (i = num_new_procs; i < 2 * num_new_procs; i++)
- new_procs[i] = NULL;
- num_new_procs = 2 * num_new_procs;
- }
- new_procs[proc_num] = proc;
-}
-
-static int read_cmdline(char *filename, struct proc_info *proc) {
- FILE *file;
- char line[MAX_LINE];
-
- line[0] = '\0';
- file = fopen(filename, "r");
- if (!file) return 1;
- fgets(line, MAX_LINE, file);
- fclose(file);
- if (strlen(line) > 0) {
- strncpy(proc->name, line, PROC_NAME_LEN);
- proc->name[PROC_NAME_LEN-1] = 0;
- } else
- proc->name[0] = 0;
- return 0;
-}
-
-static void read_policy(int pid, struct proc_info *proc) {
- SchedPolicy p;
- if (get_sched_policy(pid, &p) < 0)
- strlcpy(proc->policy, "unk", POLICY_NAME_LEN);
- else {
- strlcpy(proc->policy, get_sched_policy_name(p), POLICY_NAME_LEN);
- proc->policy[2] = '\0';
- }
-}
-
-static int read_status(char *filename, struct proc_info *proc) {
- FILE *file;
- char line[MAX_LINE];
- unsigned int uid, gid;
-
- file = fopen(filename, "r");
- if (!file) return 1;
- while (fgets(line, MAX_LINE, file)) {
- sscanf(line, "Uid: %u", &uid);
- sscanf(line, "Gid: %u", &gid);
- }
- fclose(file);
- proc->uid = uid; proc->gid = gid;
- return 0;
-}
-
-static void print_procs(void) {
- static int call = 0;
- int i;
- struct proc_info *old_proc, *proc;
- long unsigned total_delta_time;
-
- for (i = 0; i < num_new_procs; i++) {
- if (new_procs[i]) {
- old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
- if (old_proc) {
- new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
- new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
- } else {
- new_procs[i]->delta_utime = 0;
- new_procs[i]->delta_stime = 0;
- }
- new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
- }
- }
-
- total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
- + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
- - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
- + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
-
- qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
-
- if (call++ > 0) printf("\n\n\n");
- printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
- ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time,
- ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
- ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time,
- ((new_cpu.irqtime + new_cpu.sirqtime)
- - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time);
- printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n",
- new_cpu.utime - old_cpu.utime,
- new_cpu.ntime - old_cpu.ntime,
- new_cpu.stime - old_cpu.stime,
- new_cpu.itime - old_cpu.itime,
- new_cpu.iowtime - old_cpu.iowtime,
- new_cpu.irqtime - old_cpu.irqtime,
- new_cpu.sirqtime - old_cpu.sirqtime,
- total_delta_time);
- printf("\n");
- if (!threads)
- printf("%5s %-8s %2s %3s %4s %1s %5s %7s %7s %3s %s\n", "PID", "USER", "PR", "NI", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "Name");
- else
- printf("%5s %5s %-8s %2s %3s %4s %1s %7s %7s %3s %-15s %s\n", "PID", "TID", "USER", "PR", "NI", "CPU%", "S", "VSS", "RSS", "PCY", "Thread", "Proc");
-
- for (i = 0; i < num_new_procs; i++) {
- proc = new_procs[i];
-
- if (!proc || (max_procs && (i >= max_procs)))
- break;
- struct passwd* user = getpwuid(proc->uid);
- char user_buf[20];
- char* user_str;
- if (user && user->pw_name) {
- user_str = user->pw_name;
- } else {
- snprintf(user_buf, 20, "%d", proc->uid);
- user_str = user_buf;
- }
- if (!threads) {
- printf("%5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %s\n",
- proc->pid, user_str, proc->pr, proc->ni,
- proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
- proc->name[0] != 0 ? proc->name : proc->tname);
- } else {
- printf("%5d %5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-15s %s\n",
- proc->pid, proc->tid, user_str, proc->pr, proc->ni,
- proc->delta_time * 100 / total_delta_time, proc->state,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
- proc->tname, proc->name);
- }
- }
-}
-
-static struct proc_info *find_old_proc(pid_t pid, pid_t tid) {
- int i;
-
- for (i = 0; i < num_old_procs; i++)
- if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid))
- return old_procs[i];
-
- return NULL;
-}
-
-static void free_old_procs(void) {
- int i;
-
- for (i = 0; i < num_old_procs; i++)
- if (old_procs[i])
- free_proc(old_procs[i]);
-
- free(old_procs);
-}
-
-static int proc_cpu_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->delta_time, pb->delta_time);
-}
-
-static int proc_vss_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->vss, pb->vss);
-}
-
-static int proc_rss_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->rss, pb->rss);
-}
-
-static int proc_thr_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->num_threads, pb->num_threads);
-}
-
-static int numcmp(long long a, long long b) {
- if (a < b) return -1;
- if (a > b) return 1;
- return 0;
-}
-
-static void usage(char *cmd) {
- fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n"
- " -m num Maximum number of processes to display.\n"
- " -n num Updates to show before exiting.\n"
- " -d num Seconds to wait between updates.\n"
- " -s col Column to sort by (cpu,vss,rss,thr).\n"
- " -H Show threads instead of processes.\n"
- " -h Display this help screen.\n",
- cmd);
-}
diff --git a/toolbox/upstream-netbsd/include/util.h b/toolbox/upstream-netbsd/include/util.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/toolbox/upstream-netbsd/include/util.h
diff --git a/trusty/gatekeeper/Android.mk b/trusty/gatekeeper/Android.mk
index 13e9a09..3982c8f 100644
--- a/trusty/gatekeeper/Android.mk
+++ b/trusty/gatekeeper/Android.mk
@@ -43,8 +43,4 @@
LOCAL_MODULE_TAGS := optional
-# Symlink gatekeeper.trusty.so -> gatekeeper.<device>.so so libhardware can find it.
-LOCAL_POST_INSTALL_CMD = \
- $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))gatekeeper.$(TARGET_DEVICE).so
-
include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/gatekeeper/trusty_gatekeeper.h b/trusty/gatekeeper/trusty_gatekeeper.h
index 82108dc..2becc49 100644
--- a/trusty/gatekeeper/trusty_gatekeeper.h
+++ b/trusty/gatekeeper/trusty_gatekeeper.h
@@ -27,7 +27,7 @@
class TrustyGateKeeperDevice {
public:
- TrustyGateKeeperDevice(const hw_module_t* module);
+ explicit TrustyGateKeeperDevice(const hw_module_t* module);
~TrustyGateKeeperDevice();
hw_device_t* hw_device();
diff --git a/trusty/keymaster/Android.mk b/trusty/keymaster/Android.mk
new file mode 100644
index 0000000..0ebf52d
--- /dev/null
+++ b/trusty/keymaster/Android.mk
@@ -0,0 +1,67 @@
+#
+# Copyright (C) 2015 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.
+#
+
+# WARNING: Everything listed here will be built on ALL platforms,
+# including x86, the emulator, and the SDK. Modules must be uniquely
+# named (liblights.panda), and must build everywhere, or limit themselves
+# to only building on ARM if they include assembly. Individual makefiles
+# are responsible for having their own logic, for fine-grained control.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+###
+# trusty_keymaster is a binary used only for on-device testing. It
+# runs Trusty Keymaster through a basic set of operations with RSA
+# and ECDSA keys.
+###
+LOCAL_MODULE := trusty_keymaster_tipc
+LOCAL_SRC_FILES := \
+ trusty_keymaster_device.cpp \
+ trusty_keymaster_ipc.c \
+ trusty_keymaster_main.cpp
+LOCAL_SHARED_LIBRARIES := \
+ libcrypto \
+ libcutils \
+ libkeymaster1 \
+ libtrusty \
+ libkeymaster_messages \
+ liblog
+
+include $(BUILD_EXECUTABLE)
+
+###
+# keystore.trusty is the HAL used by keystore on Trusty devices.
+##
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := keystore.trusty
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := module.cpp \
+ trusty_keymaster_ipc.c \
+ trusty_keymaster_device.cpp
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+LOCAL_SHARED_LIBRARIES := \
+ libcrypto \
+ libkeymaster_messages \
+ libtrusty \
+ liblog \
+ libcutils
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/keymaster/Makefile b/trusty/keymaster/Makefile
new file mode 100644
index 0000000..f575381
--- /dev/null
+++ b/trusty/keymaster/Makefile
@@ -0,0 +1,199 @@
+#####
+# Local unit test Makefile
+#
+# This makefile builds and runs the trusty_keymaster unit tests locally on the development
+# machine, not on an Android device.
+#
+# To build and run these tests, one pre-requisite must be manually installed: BoringSSL.
+# This Makefile expects to find BoringSSL in a directory adjacent to $ANDROID_BUILD_TOP.
+# To get and build it, first install the Ninja build tool (e.g. apt-get install
+# ninja-build), then do:
+#
+# cd $ANDROID_BUILD_TOP/..
+# git clone https://boringssl.googlesource.com/boringssl
+# cd boringssl
+# mdkir build
+# cd build
+# cmake -GNinja ..
+# ninja
+#
+# Then return to $ANDROID_BUILD_TOP/system/keymaster and run "make".
+#####
+
+BASE=../../../..
+SUBS=system/core \
+ system/keymaster \
+ hardware/libhardware \
+ external/gtest
+GTEST=$(BASE)/external/gtest
+KM=$(BASE)/system/keymaster
+
+INCLUDES=$(foreach dir,$(SUBS),-I $(BASE)/$(dir)/include) \
+ -I $(BASE)/libnativehelper/include/nativehelper \
+ -I ../tipc/include \
+ -I $(BASE)/system/keymaster \
+ -I $(GTEST) \
+ -I$(BASE)/../boringssl/include
+
+ifdef USE_CLANG
+CC=/usr/bin/clang
+CXX=/usr/bin/clang
+CLANG_TEST_DEFINE=-DKEYMASTER_CLANG_TEST_BUILD
+COMPILER_SPECIFIC_ARGS=-std=c++11 $(CLANG_TEST_DEFINE)
+else
+COMPILER_SPECIFIC_ARGS=-std=c++0x -fprofile-arcs
+endif
+
+CPPFLAGS=$(INCLUDES) -g -O0 -MD
+CXXFLAGS=-Wall -Werror -Wno-unused -Winit-self -Wpointer-arith -Wunused-parameter \
+ -Wmissing-declarations -ftest-coverage \
+ -Wno-deprecated-declarations -fno-exceptions -DKEYMASTER_NAME_TAGS \
+ $(COMPILER_SPECIFIC_ARGS)
+LDLIBS=-L$(BASE)/../boringssl/build/crypto -lcrypto -lpthread -lstdc++
+
+CPPSRCS=\
+ $(KM)/aead_mode_operation.cpp \
+ $(KM)/aes_key.cpp \
+ $(KM)/aes_operation.cpp \
+ $(KM)/android_keymaster.cpp \
+ $(KM)/android_keymaster_messages.cpp \
+ $(KM)/android_keymaster_messages_test.cpp \
+ $(KM)/android_keymaster_test.cpp \
+ $(KM)/android_keymaster_test_utils.cpp \
+ $(KM)/android_keymaster_utils.cpp \
+ $(KM)/asymmetric_key.cpp \
+ $(KM)/auth_encrypted_key_blob.cpp \
+ $(KM)/auth_encrypted_key_blob.cpp \
+ $(KM)/authorization_set.cpp \
+ $(KM)/authorization_set_test.cpp \
+ $(KM)/ec_key.cpp \
+ $(KM)/ec_keymaster0_key.cpp \
+ $(KM)/ecdsa_operation.cpp \
+ $(KM)/hmac_key.cpp \
+ $(KM)/hmac_operation.cpp \
+ $(KM)/integrity_assured_key_blob.cpp \
+ $(KM)/key.cpp \
+ $(KM)/key_blob_test.cpp \
+ $(KM)/keymaster0_engine.cpp \
+ $(KM)/logger.cpp \
+ $(KM)/ocb_utils.cpp \
+ $(KM)/openssl_err.cpp \
+ $(KM)/openssl_utils.cpp \
+ $(KM)/operation.cpp \
+ $(KM)/operation_table.cpp \
+ $(KM)/rsa_key.cpp \
+ $(KM)/rsa_keymaster0_key.cpp \
+ $(KM)/rsa_operation.cpp \
+ $(KM)/serializable.cpp \
+ $(KM)/soft_keymaster_context.cpp \
+ $(KM)/symmetric_key.cpp \
+ $(KM)/unencrypted_key_blob.cpp \
+ trusty_keymaster_device.cpp \
+ trusty_keymaster_device_test.cpp
+CCSRCS=$(GTEST)/src/gtest-all.cc
+CSRCS=ocb.c
+
+OBJS=$(CPPSRCS:.cpp=.o) $(CCSRCS:.cc=.o) $(CSRCS:.c=.o)
+DEPS=$(CPPSRCS:.cpp=.d) $(CCSRCS:.cc=.d) $(CSRCS:.c=.d)
+GCDA=$(CPPSRCS:.cpp=.gcda) $(CCSRCS:.cc=.gcda) $(CSRCS:.c=.gcda)
+GCNO=$(CPPSRCS:.cpp=.gcno) $(CCSRCS:.cc=.gcno) $(CSRCS:.c=.gcno)
+
+LINK.o=$(LINK.cc)
+
+BINARIES=trusty_keymaster_device_test
+
+ifdef TRUSTY
+BINARIES += trusty_keymaster_device_test
+endif # TRUSTY
+
+.PHONY: coverage memcheck massif clean run
+
+%.run: %
+ ./$<
+ touch $@
+
+run: $(BINARIES:=.run)
+
+coverage: coverage.info
+ genhtml coverage.info --output-directory coverage
+
+coverage.info: run
+ lcov --capture --directory=. --output-file coverage.info
+
+%.coverage : %
+ $(MAKE) clean && $(MAKE) $<
+ ./$<
+ lcov --capture --directory=. --output-file coverage.info
+ genhtml coverage.info --output-directory coverage
+
+#UNINIT_OPTS=--track-origins=yes
+UNINIT_OPTS=--undef-value-errors=no
+
+MEMCHECK_OPTS=--leak-check=full \
+ --show-reachable=yes \
+ --vgdb=full \
+ $(UNINIT_OPTS) \
+ --error-exitcode=1
+
+MASSIF_OPTS=--tool=massif \
+ --stacks=yes
+
+%.memcheck : %
+ valgrind $(MEMCHECK_OPTS) ./$< && \
+ touch $@
+
+%.massif : %
+ valgrind $(MASSIF_OPTS) --massif-out-file=$@ ./$<
+
+memcheck: $(BINARIES:=.memcheck)
+
+massif: $(BINARIES:=.massif)
+
+trusty_keymaster_device_test: trusty_keymaster_device_test.o \
+ trusty_keymaster_device.o \
+ $(KM)/aead_mode_operation.o \
+ $(KM)/aes_key.o \
+ $(KM)/aes_operation.o \
+ $(KM)/android_keymaster.o \
+ $(KM)/android_keymaster_messages.o \
+ $(KM)/android_keymaster_test_utils.o \
+ $(KM)/android_keymaster_utils.o \
+ $(KM)/asymmetric_key.o \
+ $(KM)/auth_encrypted_key_blob.o \
+ $(KM)/auth_encrypted_key_blob.o \
+ $(KM)/authorization_set.o \
+ $(KM)/ec_key.o \
+ $(KM)/ec_keymaster0_key.cpp \
+ $(KM)/ecdsa_operation.o \
+ $(KM)/hmac_key.o \
+ $(KM)/hmac_operation.o \
+ $(KM)/integrity_assured_key_blob.o \
+ $(KM)/key.o \
+ $(KM)/keymaster0_engine.o \
+ $(KM)/logger.o \
+ $(KM)/ocb.o \
+ $(KM)/ocb_utils.o \
+ $(KM)/openssl_err.o \
+ $(KM)/openssl_utils.o \
+ $(KM)/operation.o \
+ $(KM)/operation_table.o \
+ $(KM)/rsa_key.o \
+ $(KM)/rsa_keymaster0_key.o \
+ $(KM)/rsa_operation.o \
+ $(KM)/serializable.o \
+ $(KM)/soft_keymaster_context.o \
+ $(KM)/symmetric_key.o \
+ $(GTEST)/src/gtest-all.o
+
+$(GTEST)/src/gtest-all.o: CXXFLAGS:=$(subst -Wmissing-declarations,,$(CXXFLAGS))
+ocb.o: CFLAGS=$(CLANG_TEST_DEFINE)
+
+clean:
+ rm -f $(OBJS) $(DEPS) $(GCDA) $(GCNO) $(BINARIES) \
+ $(BINARIES:=.run) $(BINARIES:=.memcheck) $(BINARIES:=.massif) \
+ coverage.info
+ rm -rf coverage
+
+-include $(CPPSRCS:.cpp=.d)
+-include $(CCSRCS:.cc=.d)
+
diff --git a/trusty/keymaster/keymaster_ipc.h b/trusty/keymaster/keymaster_ipc.h
new file mode 100644
index 0000000..48fa53d
--- /dev/null
+++ b/trusty/keymaster/keymaster_ipc.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define KEYMASTER_PORT "com.android.trusty.keymaster"
+#define KEYMASTER_MAX_BUFFER_LENGTH 4096
+
+// Commands
+enum keymaster_command {
+ KEYMASTER_RESP_BIT = 1,
+ KEYMASTER_REQ_SHIFT = 1,
+
+ KM_GENERATE_KEY = (0 << KEYMASTER_REQ_SHIFT),
+ KM_BEGIN_OPERATION = (1 << KEYMASTER_REQ_SHIFT),
+ KM_UPDATE_OPERATION = (2 << KEYMASTER_REQ_SHIFT),
+ KM_FINISH_OPERATION = (3 << KEYMASTER_REQ_SHIFT),
+ KM_ABORT_OPERATION = (4 << KEYMASTER_REQ_SHIFT),
+ KM_IMPORT_KEY = (5 << KEYMASTER_REQ_SHIFT),
+ KM_EXPORT_KEY = (6 << KEYMASTER_REQ_SHIFT),
+ KM_GET_VERSION = (7 << KEYMASTER_REQ_SHIFT),
+ KM_ADD_RNG_ENTROPY = (8 << KEYMASTER_REQ_SHIFT),
+ KM_GET_SUPPORTED_ALGORITHMS = (9 << KEYMASTER_REQ_SHIFT),
+ KM_GET_SUPPORTED_BLOCK_MODES = (10 << KEYMASTER_REQ_SHIFT),
+ KM_GET_SUPPORTED_PADDING_MODES = (11 << KEYMASTER_REQ_SHIFT),
+ KM_GET_SUPPORTED_DIGESTS = (12 << KEYMASTER_REQ_SHIFT),
+ KM_GET_SUPPORTED_IMPORT_FORMATS = (13 << KEYMASTER_REQ_SHIFT),
+ KM_GET_SUPPORTED_EXPORT_FORMATS = (14 << KEYMASTER_REQ_SHIFT),
+ KM_GET_KEY_CHARACTERISTICS = (15 << KEYMASTER_REQ_SHIFT),
+};
+
+#ifdef __ANDROID__
+
+/**
+ * keymaster_message - Serial header for communicating with KM server
+ * @cmd: the command, one of keymaster_command.
+ * @payload: start of the serialized command specific payload
+ */
+struct keymaster_message {
+ uint32_t cmd;
+ uint8_t payload[0];
+};
+
+#endif
diff --git a/trusty/keymaster/module.cpp b/trusty/keymaster/module.cpp
new file mode 100644
index 0000000..81597d9
--- /dev/null
+++ b/trusty/keymaster/module.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 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 <errno.h>
+#include <string.h>
+
+#include <hardware/hardware.h>
+#include <hardware/keymaster0.h>
+
+#include "trusty_keymaster_device.h"
+
+using keymaster::TrustyKeymasterDevice;
+
+/*
+ * Generic device handling
+ */
+static int trusty_keymaster_open(const hw_module_t* module, const char* name,
+ hw_device_t** device) {
+ if (strcmp(name, KEYSTORE_KEYMASTER) != 0)
+ return -EINVAL;
+
+ TrustyKeymasterDevice* dev = new TrustyKeymasterDevice(module);
+ if (dev == NULL)
+ return -ENOMEM;
+ *device = dev->hw_device();
+ // Do not delete dev; it will get cleaned up when the caller calls device->close(), and must
+ // exist until then.
+ return 0;
+}
+
+static struct hw_module_methods_t keystore_module_methods = {
+ .open = trusty_keymaster_open,
+};
+
+struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) = {
+ .common =
+ {
+ .tag = HARDWARE_MODULE_TAG,
+ .module_api_version = KEYMASTER_MODULE_API_VERSION_0_3,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = KEYSTORE_HARDWARE_MODULE_ID,
+ .name = "Trusty Keymaster HAL",
+ .author = "The Android Open Source Project",
+ .methods = &keystore_module_methods,
+ .dso = 0,
+ .reserved = {},
+ },
+};
diff --git a/trusty/keymaster/trusty_keymaster_device.cpp b/trusty/keymaster/trusty_keymaster_device.cpp
new file mode 100644
index 0000000..069b4fe
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright 2014 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 "trusty_keymaster_device.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <stddef.h>
+
+#include <type_traits>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+
+#define LOG_TAG "TrustyKeymaster"
+#include <cutils/log.h>
+#include <hardware/keymaster0.h>
+
+#include <keymaster/authorization_set.h>
+
+#include "trusty_keymaster_ipc.h"
+#include "keymaster_ipc.h"
+
+const uint32_t SEND_BUF_SIZE = 8192;
+const uint32_t RECV_BUF_SIZE = 8192;
+
+namespace keymaster {
+
+static keymaster_error_t translate_error(int err) {
+ switch (err) {
+ case 0:
+ return KM_ERROR_OK;
+ case -EPERM:
+ case -EACCES:
+ return KM_ERROR_SECURE_HW_ACCESS_DENIED;
+
+ case -ECANCELED:
+ return KM_ERROR_OPERATION_CANCELLED;
+
+ case -ENODEV:
+ return KM_ERROR_UNIMPLEMENTED;
+
+ case -ENOMEM:
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+
+ case -EBUSY:
+ return KM_ERROR_SECURE_HW_BUSY;
+
+ case -EIO:
+ return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
+
+ case -EOVERFLOW:
+ return KM_ERROR_INVALID_INPUT_LENGTH;
+
+ default:
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+}
+
+TrustyKeymasterDevice::TrustyKeymasterDevice(const hw_module_t* module) {
+ static_assert(std::is_standard_layout<TrustyKeymasterDevice>::value,
+ "TrustyKeymasterDevice must be standard layout");
+ static_assert(offsetof(TrustyKeymasterDevice, device_) == 0,
+ "device_ must be the first member of KeymasterOpenSsl");
+ static_assert(offsetof(TrustyKeymasterDevice, device_.common) == 0,
+ "common must be the first member of keymaster_device");
+
+ ALOGI("Creating device");
+ ALOGD("Device address: %p", this);
+
+ memset(&device_, 0, sizeof(device_));
+
+ device_.common.tag = HARDWARE_DEVICE_TAG;
+ device_.common.version = 1;
+ device_.common.module = const_cast<hw_module_t*>(module);
+ device_.common.close = close_device;
+
+ device_.flags = KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_EC;
+
+ device_.generate_keypair = generate_keypair;
+ device_.import_keypair = import_keypair;
+ device_.get_keypair_public = get_keypair_public;
+ device_.delete_keypair = NULL;
+ device_.delete_all = NULL;
+ device_.sign_data = sign_data;
+ device_.verify_data = verify_data;
+
+ device_.context = NULL;
+
+ int rc = trusty_keymaster_connect();
+ error_ = translate_error(rc);
+ if (rc < 0) {
+ ALOGE("failed to connect to keymaster (%d)", rc);
+ return;
+ }
+
+ GetVersionRequest version_request;
+ GetVersionResponse version_response;
+ error_ = Send(version_request, &version_response);
+ if (error_ == KM_ERROR_INVALID_ARGUMENT || error_ == KM_ERROR_UNIMPLEMENTED) {
+ ALOGI("\"Bad parameters\" error on GetVersion call. Assuming version 0.");
+ message_version_ = 0;
+ error_ = KM_ERROR_OK;
+ }
+ message_version_ = MessageVersion(version_response.major_ver, version_response.minor_ver,
+ version_response.subminor_ver);
+ if (message_version_ < 0) {
+ // Can't translate version? Keymaster implementation must be newer.
+ ALOGE("Keymaster version %d.%d.%d not supported.", version_response.major_ver,
+ version_response.minor_ver, version_response.subminor_ver);
+ error_ = KM_ERROR_VERSION_MISMATCH;
+ }
+}
+
+TrustyKeymasterDevice::~TrustyKeymasterDevice() {
+ trusty_keymaster_disconnect();
+}
+
+const uint64_t HUNDRED_YEARS = 1000LL * 60 * 60 * 24 * 365 * 100;
+
+int TrustyKeymasterDevice::generate_keypair(const keymaster_keypair_t key_type,
+ const void* key_params, uint8_t** key_blob,
+ size_t* key_blob_length) {
+ ALOGD("Device received generate_keypair");
+
+ if (error_ != KM_ERROR_OK)
+ return error_;
+
+ GenerateKeyRequest req(message_version_);
+ StoreNewKeyParams(&req.key_description);
+
+ switch (key_type) {
+ case TYPE_RSA: {
+ req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_RSA);
+ const keymaster_rsa_keygen_params_t* rsa_params =
+ static_cast<const keymaster_rsa_keygen_params_t*>(key_params);
+ ALOGD("Generating RSA pair, modulus size: %u, public exponent: %lu",
+ rsa_params->modulus_size, rsa_params->public_exponent);
+ req.key_description.push_back(TAG_KEY_SIZE, rsa_params->modulus_size);
+ req.key_description.push_back(TAG_RSA_PUBLIC_EXPONENT, rsa_params->public_exponent);
+ break;
+ }
+
+ case TYPE_EC: {
+ req.key_description.push_back(TAG_ALGORITHM, KM_ALGORITHM_EC);
+ const keymaster_ec_keygen_params_t* ec_params =
+ static_cast<const keymaster_ec_keygen_params_t*>(key_params);
+ ALOGD("Generating ECDSA pair, key size: %u", ec_params->field_size);
+ req.key_description.push_back(TAG_KEY_SIZE, ec_params->field_size);
+ break;
+ }
+ default:
+ ALOGD("Received request for unsuported key type %d", key_type);
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ }
+
+ GenerateKeyResponse rsp(message_version_);
+ ALOGD("Sending generate request");
+ keymaster_error_t err = Send(req, &rsp);
+ if (err != KM_ERROR_OK) {
+ ALOGE("Got error %d from send", err);
+ return err;
+ }
+
+ *key_blob_length = rsp.key_blob.key_material_size;
+ *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+ memcpy(*key_blob, rsp.key_blob.key_material, *key_blob_length);
+ ALOGD("Returning %d bytes in key blob\n", (int)*key_blob_length);
+
+ return KM_ERROR_OK;
+}
+
+struct EVP_PKEY_Delete {
+ void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct PKCS8_PRIV_KEY_INFO_Delete {
+ void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
+};
+
+int TrustyKeymasterDevice::import_keypair(const uint8_t* key, const size_t key_length,
+ uint8_t** key_blob, size_t* key_blob_length) {
+ ALOGD("Device received import_keypair");
+ if (error_ != KM_ERROR_OK)
+ return error_;
+
+ if (!key)
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+
+ if (!key_blob || !key_blob_length)
+ return KM_ERROR_OUTPUT_PARAMETER_NULL;
+
+ ImportKeyRequest request(message_version_);
+ StoreNewKeyParams(&request.key_description);
+ keymaster_algorithm_t algorithm;
+ keymaster_error_t err = GetPkcs8KeyAlgorithm(key, key_length, &algorithm);
+ if (err != KM_ERROR_OK)
+ return err;
+ request.key_description.push_back(TAG_ALGORITHM, algorithm);
+
+ request.SetKeyMaterial(key, key_length);
+ request.key_format = KM_KEY_FORMAT_PKCS8;
+ ImportKeyResponse response(message_version_);
+ err = Send(request, &response);
+ if (err != KM_ERROR_OK)
+ return err;
+
+ *key_blob_length = response.key_blob.key_material_size;
+ *key_blob = static_cast<uint8_t*>(malloc(*key_blob_length));
+ memcpy(*key_blob, response.key_blob.key_material, *key_blob_length);
+ printf("Returning %d bytes in key blob\n", (int)*key_blob_length);
+
+ return KM_ERROR_OK;
+}
+
+keymaster_error_t TrustyKeymasterDevice::GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+ keymaster_algorithm_t* algorithm) {
+ if (key == NULL) {
+ ALOGE("No key specified for import");
+ return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ }
+
+ UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> pkcs8(
+ d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, key_length));
+ if (pkcs8.get() == NULL) {
+ ALOGE("Could not parse PKCS8 key blob");
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(EVP_PKCS82PKEY(pkcs8.get()));
+ if (pkey.get() == NULL) {
+ ALOGE("Could not extract key from PKCS8 key blob");
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+
+ switch (EVP_PKEY_type(pkey->type)) {
+ case EVP_PKEY_RSA:
+ *algorithm = KM_ALGORITHM_RSA;
+ break;
+ case EVP_PKEY_EC:
+ *algorithm = KM_ALGORITHM_EC;
+ break;
+ default:
+ ALOGE("Unsupported algorithm %d", EVP_PKEY_type(pkey->type));
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ }
+
+ return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
+ uint8_t** x509_data, size_t* x509_data_length) {
+ ALOGD("Device received get_keypair_public");
+ if (error_ != KM_ERROR_OK)
+ return error_;
+
+ ExportKeyRequest request(message_version_);
+ request.SetKeyMaterial(key_blob, key_blob_length);
+ request.key_format = KM_KEY_FORMAT_X509;
+ ExportKeyResponse response(message_version_);
+ keymaster_error_t err = Send(request, &response);
+ if (err != KM_ERROR_OK)
+ return err;
+
+ *x509_data_length = response.key_data_length;
+ *x509_data = static_cast<uint8_t*>(malloc(*x509_data_length));
+ memcpy(*x509_data, response.key_data, *x509_data_length);
+ printf("Returning %d bytes in x509 key\n", (int)*x509_data_length);
+
+ return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::sign_data(const void* signing_params, const uint8_t* key_blob,
+ const size_t key_blob_length, const uint8_t* data,
+ const size_t data_length, uint8_t** signed_data,
+ size_t* signed_data_length) {
+ ALOGD("Device received sign_data, %d", error_);
+ if (error_ != KM_ERROR_OK)
+ return error_;
+
+ BeginOperationRequest begin_request(message_version_);
+ begin_request.purpose = KM_PURPOSE_SIGN;
+ begin_request.SetKeyMaterial(key_blob, key_blob_length);
+ keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
+ &begin_request.additional_params);
+ if (err != KM_ERROR_OK) {
+ ALOGE("Error extracting signing params: %d", err);
+ return err;
+ }
+
+ BeginOperationResponse begin_response(message_version_);
+ ALOGD("Sending signing request begin");
+ err = Send(begin_request, &begin_response);
+ if (err != KM_ERROR_OK) {
+ ALOGE("Error sending sign begin: %d", err);
+ return err;
+ }
+
+ UpdateOperationRequest update_request(message_version_);
+ update_request.op_handle = begin_response.op_handle;
+ update_request.input.Reinitialize(data, data_length);
+ UpdateOperationResponse update_response(message_version_);
+ ALOGD("Sending signing request update");
+ err = Send(update_request, &update_response);
+ if (err != KM_ERROR_OK) {
+ ALOGE("Error sending sign update: %d", err);
+ return err;
+ }
+
+ FinishOperationRequest finish_request(message_version_);
+ finish_request.op_handle = begin_response.op_handle;
+ FinishOperationResponse finish_response(message_version_);
+ ALOGD("Sending signing request finish");
+ err = Send(finish_request, &finish_response);
+ if (err != KM_ERROR_OK) {
+ ALOGE("Error sending sign finish: %d", err);
+ return err;
+ }
+
+ *signed_data_length = finish_response.output.available_read();
+ *signed_data = static_cast<uint8_t*>(malloc(*signed_data_length));
+ if (!finish_response.output.read(*signed_data, *signed_data_length)) {
+ ALOGE("Error reading response data: %d", err);
+ return KM_ERROR_UNKNOWN_ERROR;
+ }
+ return KM_ERROR_OK;
+}
+
+int TrustyKeymasterDevice::verify_data(const void* signing_params, const uint8_t* key_blob,
+ const size_t key_blob_length, const uint8_t* signed_data,
+ const size_t signed_data_length, const uint8_t* signature,
+ const size_t signature_length) {
+ ALOGD("Device received verify_data");
+ if (error_ != KM_ERROR_OK)
+ return error_;
+
+ BeginOperationRequest begin_request(message_version_);
+ begin_request.purpose = KM_PURPOSE_VERIFY;
+ begin_request.SetKeyMaterial(key_blob, key_blob_length);
+ keymaster_error_t err = StoreSigningParams(signing_params, key_blob, key_blob_length,
+ &begin_request.additional_params);
+ if (err != KM_ERROR_OK)
+ return err;
+
+ BeginOperationResponse begin_response(message_version_);
+ err = Send(begin_request, &begin_response);
+ if (err != KM_ERROR_OK)
+ return err;
+
+ UpdateOperationRequest update_request(message_version_);
+ update_request.op_handle = begin_response.op_handle;
+ update_request.input.Reinitialize(signed_data, signed_data_length);
+ UpdateOperationResponse update_response(message_version_);
+ err = Send(update_request, &update_response);
+ if (err != KM_ERROR_OK)
+ return err;
+
+ FinishOperationRequest finish_request(message_version_);
+ finish_request.op_handle = begin_response.op_handle;
+ finish_request.signature.Reinitialize(signature, signature_length);
+ FinishOperationResponse finish_response(message_version_);
+ err = Send(finish_request, &finish_response);
+ if (err != KM_ERROR_OK)
+ return err;
+ return KM_ERROR_OK;
+}
+
+hw_device_t* TrustyKeymasterDevice::hw_device() {
+ return &device_.common;
+}
+
+static inline TrustyKeymasterDevice* convert_device(const keymaster0_device_t* dev) {
+ return reinterpret_cast<TrustyKeymasterDevice*>(const_cast<keymaster0_device_t*>(dev));
+}
+
+/* static */
+int TrustyKeymasterDevice::close_device(hw_device_t* dev) {
+ delete reinterpret_cast<TrustyKeymasterDevice*>(dev);
+ return 0;
+}
+
+/* static */
+int TrustyKeymasterDevice::generate_keypair(const keymaster0_device_t* dev,
+ const keymaster_keypair_t key_type,
+ const void* key_params, uint8_t** keyBlob,
+ size_t* keyBlobLength) {
+ ALOGD("Generate keypair, sending to device: %p", convert_device(dev));
+ return convert_device(dev)->generate_keypair(key_type, key_params, keyBlob, keyBlobLength);
+}
+
+/* static */
+int TrustyKeymasterDevice::import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
+ const size_t key_length, uint8_t** key_blob,
+ size_t* key_blob_length) {
+ return convert_device(dev)->import_keypair(key, key_length, key_blob, key_blob_length);
+}
+
+/* static */
+int TrustyKeymasterDevice::get_keypair_public(const keymaster0_device_t* dev,
+ const uint8_t* key_blob, const size_t key_blob_length,
+ uint8_t** x509_data, size_t* x509_data_length) {
+ return convert_device(dev)
+ ->get_keypair_public(key_blob, key_blob_length, x509_data, x509_data_length);
+}
+
+/* static */
+int TrustyKeymasterDevice::sign_data(const keymaster0_device_t* dev, const void* params,
+ const uint8_t* keyBlob, const size_t keyBlobLength,
+ const uint8_t* data, const size_t dataLength,
+ uint8_t** signedData, size_t* signedDataLength) {
+ return convert_device(dev)
+ ->sign_data(params, keyBlob, keyBlobLength, data, dataLength, signedData, signedDataLength);
+}
+
+/* static */
+int TrustyKeymasterDevice::verify_data(const keymaster0_device_t* dev, const void* params,
+ const uint8_t* keyBlob, const size_t keyBlobLength,
+ const uint8_t* signedData, const size_t signedDataLength,
+ const uint8_t* signature, const size_t signatureLength) {
+ return convert_device(dev)->verify_data(params, keyBlob, keyBlobLength, signedData,
+ signedDataLength, signature, signatureLength);
+}
+
+keymaster_error_t TrustyKeymasterDevice::Send(uint32_t command, const Serializable& req,
+ KeymasterResponse* rsp) {
+ uint32_t req_size = req.SerializedSize();
+ if (req_size > SEND_BUF_SIZE)
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ uint8_t send_buf[SEND_BUF_SIZE];
+ Eraser send_buf_eraser(send_buf, SEND_BUF_SIZE);
+ req.Serialize(send_buf, send_buf + req_size);
+
+ // Send it
+ uint8_t recv_buf[RECV_BUF_SIZE];
+ Eraser recv_buf_eraser(recv_buf, RECV_BUF_SIZE);
+ uint32_t rsp_size = RECV_BUF_SIZE;
+ printf("Sending %d byte request\n", (int)req.SerializedSize());
+ int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
+ if (rc < 0) {
+ ALOGE("tipc error: %d\n", rc);
+ // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
+ return translate_error(rc);
+ } else {
+ ALOGV("Received %d byte response\n", rsp_size);
+ }
+
+ const keymaster_message* msg = (keymaster_message *) recv_buf;
+ const uint8_t *p = msg->payload;
+ if (!rsp->Deserialize(&p, p + rsp_size)) {
+ ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
+ return KM_ERROR_UNKNOWN_ERROR;
+ } else if (rsp->error != KM_ERROR_OK) {
+ ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
+ return rsp->error;
+ }
+ return rsp->error;
+}
+
+keymaster_error_t TrustyKeymasterDevice::StoreSigningParams(const void* signing_params,
+ const uint8_t* key_blob,
+ size_t key_blob_length,
+ AuthorizationSet* auth_set) {
+ uint8_t* pub_key_data;
+ size_t pub_key_data_length;
+ int err = get_keypair_public(&device_, key_blob, key_blob_length, &pub_key_data,
+ &pub_key_data_length);
+ if (err < 0) {
+ ALOGE("Error %d extracting public key to determine algorithm", err);
+ return KM_ERROR_INVALID_KEY_BLOB;
+ }
+ UniquePtr<uint8_t, Malloc_Delete> pub_key(pub_key_data);
+
+ const uint8_t* p = pub_key_data;
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(
+ d2i_PUBKEY(nullptr /* allocate new struct */, &p, pub_key_data_length));
+
+ switch (EVP_PKEY_type(pkey->type)) {
+ case EVP_PKEY_RSA: {
+ const keymaster_rsa_sign_params_t* rsa_params =
+ reinterpret_cast<const keymaster_rsa_sign_params_t*>(signing_params);
+ if (rsa_params->digest_type != DIGEST_NONE)
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ if (rsa_params->padding_type != PADDING_NONE)
+ return KM_ERROR_UNSUPPORTED_PADDING_MODE;
+ if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE) ||
+ !auth_set->push_back(TAG_PADDING, KM_PAD_NONE))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ } break;
+ case EVP_PKEY_EC: {
+ const keymaster_ec_sign_params_t* ecdsa_params =
+ reinterpret_cast<const keymaster_ec_sign_params_t*>(signing_params);
+ if (ecdsa_params->digest_type != DIGEST_NONE)
+ return KM_ERROR_UNSUPPORTED_DIGEST;
+ if (!auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE))
+ return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ } break;
+ default:
+ return KM_ERROR_UNSUPPORTED_ALGORITHM;
+ }
+ return KM_ERROR_OK;
+}
+
+void TrustyKeymasterDevice::StoreNewKeyParams(AuthorizationSet* auth_set) {
+ auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_SIGN);
+ auth_set->push_back(TAG_PURPOSE, KM_PURPOSE_VERIFY);
+ auth_set->push_back(TAG_ALL_USERS);
+ auth_set->push_back(TAG_NO_AUTH_REQUIRED);
+ uint64_t now = java_time(time(NULL));
+ auth_set->push_back(TAG_CREATION_DATETIME, now);
+ auth_set->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, now + HUNDRED_YEARS);
+ if (message_version_ == 0) {
+ auth_set->push_back(TAG_DIGEST_OLD, KM_DIGEST_NONE);
+ auth_set->push_back(TAG_PADDING_OLD, KM_PAD_NONE);
+ } else {
+ auth_set->push_back(TAG_DIGEST, KM_DIGEST_NONE);
+ auth_set->push_back(TAG_PADDING, KM_PAD_NONE);
+ }
+}
+
+} // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_device.h b/trusty/keymaster/trusty_keymaster_device.h
new file mode 100644
index 0000000..68cf40c
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 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 EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+#define EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
+
+#include <hardware/keymaster0.h>
+
+#include <keymaster/android_keymaster_messages.h>
+
+#include "keymaster_ipc.h"
+
+namespace keymaster {
+
+/**
+ * Software OpenSSL-based Keymaster device.
+ *
+ * IMPORTANT MAINTAINER NOTE: Pointers to instances of this class must be castable to hw_device_t
+ * and keymaster_device. This means it must remain a standard layout class (no virtual functions and
+ * no data members which aren't standard layout), and device_ must be the first data member.
+ * Assertions in the constructor validate compliance with those constraints.
+ */
+class TrustyKeymasterDevice {
+ public:
+ /*
+ * These are the only symbols that will be exported by libtrustykeymaster. All functionality
+ * can be reached via the function pointers in device_.
+ */
+ __attribute__((visibility("default"))) explicit TrustyKeymasterDevice(const hw_module_t* module);
+ __attribute__((visibility("default"))) hw_device_t* hw_device();
+
+ ~TrustyKeymasterDevice();
+
+ keymaster_error_t session_error() { return error_; }
+
+ int generate_keypair(const keymaster_keypair_t key_type, const void* key_params,
+ uint8_t** key_blob, size_t* key_blob_length);
+ int import_keypair(const uint8_t* key, const size_t key_length, uint8_t** key_blob,
+ size_t* key_blob_length);
+ int get_keypair_public(const uint8_t* key_blob, const size_t key_blob_length,
+ uint8_t** x509_data, size_t* x509_data_length);
+ int sign_data(const void* signing_params, const uint8_t* key_blob, const size_t key_blob_length,
+ const uint8_t* data, const size_t data_length, uint8_t** signed_data,
+ size_t* signed_data_length);
+ int verify_data(const void* signing_params, const uint8_t* key_blob,
+ const size_t key_blob_length, const uint8_t* signed_data,
+ const size_t signed_data_length, const uint8_t* signature,
+ const size_t signature_length);
+
+ private:
+ keymaster_error_t Send(uint32_t command, const Serializable& request,
+ KeymasterResponse* response);
+ keymaster_error_t Send(const GenerateKeyRequest& request, GenerateKeyResponse* response) {
+ return Send(KM_GENERATE_KEY, request, response);
+ }
+ keymaster_error_t Send(const BeginOperationRequest& request, BeginOperationResponse* response) {
+ return Send(KM_BEGIN_OPERATION, request, response);
+ }
+ keymaster_error_t Send(const UpdateOperationRequest& request,
+ UpdateOperationResponse* response) {
+ return Send(KM_UPDATE_OPERATION, request, response);
+ }
+ keymaster_error_t Send(const FinishOperationRequest& request,
+ FinishOperationResponse* response) {
+ return Send(KM_FINISH_OPERATION, request, response);
+ }
+ keymaster_error_t Send(const ImportKeyRequest& request, ImportKeyResponse* response) {
+ return Send(KM_IMPORT_KEY, request, response);
+ }
+ keymaster_error_t Send(const ExportKeyRequest& request, ExportKeyResponse* response) {
+ return Send(KM_EXPORT_KEY, request, response);
+ }
+ keymaster_error_t Send(const GetVersionRequest& request, GetVersionResponse* response) {
+ return Send(KM_GET_VERSION, request, response);
+ }
+
+ keymaster_error_t StoreSigningParams(const void* signing_params, const uint8_t* key_blob,
+ size_t key_blob_length, AuthorizationSet* auth_set);
+ void StoreNewKeyParams(AuthorizationSet* auth_set);
+ keymaster_error_t GetPkcs8KeyAlgorithm(const uint8_t* key, size_t key_length,
+ keymaster_algorithm_t* algorithm);
+
+ /*
+ * These static methods are the functions referenced through the function pointers in
+ * keymaster_device. They're all trivial wrappers.
+ */
+ static int close_device(hw_device_t* dev);
+ static int generate_keypair(const keymaster0_device_t* dev, const keymaster_keypair_t key_type,
+ const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength);
+ static int import_keypair(const keymaster0_device_t* dev, const uint8_t* key,
+ const size_t key_length, uint8_t** key_blob, size_t* key_blob_length);
+ static int get_keypair_public(const keymaster0_device_t* dev, const uint8_t* key_blob,
+ const size_t key_blob_length, uint8_t** x509_data,
+ size_t* x509_data_length);
+ static int sign_data(const keymaster0_device_t* dev, const void* signing_params,
+ const uint8_t* key_blob, const size_t key_blob_length, const uint8_t* data,
+ const size_t data_length, uint8_t** signed_data,
+ size_t* signed_data_length);
+ static int verify_data(const keymaster0_device_t* dev, const void* signing_params,
+ const uint8_t* key_blob, const size_t key_blob_length,
+ const uint8_t* signed_data, const size_t signed_data_length,
+ const uint8_t* signature, const size_t signature_length);
+
+ keymaster0_device_t device_;
+ keymaster_error_t error_;
+ int32_t message_version_;
+};
+
+} // namespace keymaster
+
+#endif // EXTERNAL_KEYMASTER_TRUSTY_KEYMASTER_DEVICE_H_
diff --git a/trusty/keymaster/trusty_keymaster_device_test.cpp b/trusty/keymaster/trusty_keymaster_device_test.cpp
new file mode 100644
index 0000000..3bb5430
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_device_test.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2014 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 <algorithm>
+#include <fstream>
+
+#include <UniquePtr.h>
+#include <gtest/gtest.h>
+#include <openssl/engine.h>
+
+#include <hardware/keymaster0.h>
+
+#include <keymaster/android_keymaster.h>
+#include <keymaster/android_keymaster_messages.h>
+#include <keymaster/android_keymaster_utils.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/soft_keymaster_context.h>
+
+#include "android_keymaster_test_utils.h"
+#include "trusty_keymaster_device.h"
+#include "openssl_utils.h"
+
+using std::string;
+using std::ifstream;
+using std::istreambuf_iterator;
+
+static keymaster::AndroidKeymaster *impl_ = nullptr;
+
+extern "C" {
+int __android_log_print();
+}
+
+int __android_log_print() {
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int result = RUN_ALL_TESTS();
+ // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+ return result;
+}
+
+int trusty_keymaster_connect() {
+ impl_ = new keymaster::AndroidKeymaster(new keymaster::SoftKeymasterContext(nullptr), 16);
+}
+
+void trusty_keymaster_disconnect() {
+ delete static_cast<keymaster::AndroidKeymaster*>(priv_);
+}
+
+template <typename Req, typename Rsp>
+static int fake_call(keymaster::AndroidKeymaster* device,
+ void (keymaster::AndroidKeymaster::*method)(const Req&, Rsp*), void* in_buf,
+ uint32_t in_size, void* out_buf, uint32_t* out_size) {
+ Req req;
+ const uint8_t* in = static_cast<uint8_t*>(in_buf);
+ req.Deserialize(&in, in + in_size);
+ Rsp rsp;
+ (device->*method)(req, &rsp);
+
+ *out_size = rsp.SerializedSize();
+ uint8_t* out = static_cast<uint8_t*>(out_buf);
+ rsp.Serialize(out, out + *out_size);
+ return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void* in_buf, uint32_t in_size, void* out_buf,
+ uint32_t* out_size) {
+ switch (cmd) {
+ case KM_GENERATE_KEY:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::GenerateKey, in_buf, in_size,
+ out_buf, out_size);
+ case KM_BEGIN_OPERATION:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::BeginOperation, in_buf, in_size,
+ out_buf, out_size);
+ case KM_UPDATE_OPERATION:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::UpdateOperation, in_buf, in_size,
+ out_buf, out_size);
+ case KM_FINISH_OPERATION:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::FinishOperation, in_buf, in_size,
+ out_buf, out_size);
+ case KM_IMPORT_KEY:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::ImportKey, in_buf, in_size, out_buf,
+ out_size);
+ case KM_EXPORT_KEY:
+ return fake_call(impl_, &keymaster::AndroidKeymaster::ExportKey, in_buf, in_size, out_buf,
+ out_size);
+ }
+ return -EINVAL;
+
+}
+
+namespace keymaster {
+namespace test {
+
+class TrustyKeymasterTest : public testing::Test {
+ protected:
+ TrustyKeymasterTest() : device(NULL) {}
+
+ keymaster_rsa_keygen_params_t build_rsa_params() {
+ keymaster_rsa_keygen_params_t rsa_params;
+ rsa_params.public_exponent = 65537;
+ rsa_params.modulus_size = 2048;
+ return rsa_params;
+ }
+
+ uint8_t* build_message(size_t length) {
+ uint8_t* msg = new uint8_t[length];
+ memset(msg, 'a', length);
+ return msg;
+ }
+
+ size_t dsa_message_len(const keymaster_dsa_keygen_params_t& params) {
+ switch (params.key_size) {
+ case 256:
+ case 1024:
+ return 48;
+ case 2048:
+ case 4096:
+ return 72;
+ default:
+ // Oops.
+ return 0;
+ }
+ }
+
+ TrustyKeymasterDevice device;
+};
+
+class Malloc_Delete {
+ public:
+ Malloc_Delete(void* p) : p_(p) {}
+ ~Malloc_Delete() { free(p_); }
+
+ private:
+ void* p_;
+};
+
+typedef TrustyKeymasterTest KeyGenTest;
+TEST_F(KeyGenTest, RsaSuccess) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+}
+
+TEST_F(KeyGenTest, EcdsaSuccess) {
+ keymaster_ec_keygen_params_t ec_params = {256};
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_EC, &ec_params, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+}
+
+typedef TrustyKeymasterTest SigningTest;
+TEST_F(SigningTest, RsaSuccess) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(message_len, siglen);
+}
+
+TEST_F(SigningTest, RsaShortMessage) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8 - 1;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
+ message_len, &signature, &siglen));
+}
+
+TEST_F(SigningTest, RsaLongMessage) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8 + 1;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_UNKNOWN_ERROR, device.sign_data(&sig_params, ptr, size, message.get(),
+ message_len, &signature, &siglen));
+}
+
+TEST_F(SigningTest, EcdsaSuccess) {
+ keymaster_ec_keygen_params_t params = {256};
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+ uint8_t message[] = "12345678901234567890123456789012";
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+ array_size(message) - 1, &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_GT(siglen, 69U);
+ EXPECT_LT(siglen, 73U);
+}
+
+TEST_F(SigningTest, EcdsaEmptyMessageSuccess) {
+ keymaster_ec_keygen_params_t params = {256};
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+ uint8_t message[] = "";
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+ array_size(message) - 1, &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_GT(siglen, 69U);
+ EXPECT_LT(siglen, 73U);
+}
+
+TEST_F(SigningTest, EcdsaLargeMessageSuccess) {
+ keymaster_ec_keygen_params_t params = {256};
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+ size_t message_len = 1024 * 7;
+ UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ // contents of message don't matter.
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_GT(siglen, 69U);
+ EXPECT_LT(siglen, 73U);
+}
+
+typedef TrustyKeymasterTest VerificationTest;
+TEST_F(VerificationTest, RsaSuccess) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+
+ EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
+ signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaBadSignature) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+
+ Malloc_Delete sig_deleter(signature);
+ signature[siglen / 2]++;
+ EXPECT_EQ(
+ KM_ERROR_VERIFICATION_FAILED,
+ device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaBadMessage) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ message[0]++;
+ EXPECT_EQ(
+ KM_ERROR_VERIFICATION_FAILED,
+ device.verify_data(&sig_params, ptr, size, message.get(), message_len, signature, siglen));
+}
+
+TEST_F(VerificationTest, RsaShortMessage) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
+ device.verify_data(&sig_params, ptr, size, message.get(), message_len - 1, signature,
+ siglen));
+}
+
+TEST_F(VerificationTest, RsaLongMessage) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(build_message(message_len + 1));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(KM_ERROR_INVALID_INPUT_LENGTH,
+ device.verify_data(&sig_params, ptr, size, message.get(), message_len + 1, signature,
+ siglen));
+}
+
+TEST_F(VerificationTest, EcdsaSuccess) {
+ keymaster_ec_keygen_params_t params = {256};
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+ uint8_t message[] = "12345678901234567890123456789012";
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message,
+ array_size(message) - 1, &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message,
+ array_size(message) - 1, signature, siglen));
+}
+
+TEST_F(VerificationTest, EcdsaLargeMessageSuccess) {
+ keymaster_ec_keygen_params_t params = {256};
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+ size_t message_len = 1024 * 7;
+ UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ // contents of message don't matter.
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, ptr, size, message.get(), message_len,
+ signature, siglen));
+}
+
+static string read_file(const string& file_name) {
+ ifstream file_stream(file_name, std::ios::binary);
+ istreambuf_iterator<char> file_begin(file_stream);
+ istreambuf_iterator<char> file_end;
+ return string(file_begin, file_end);
+}
+
+typedef TrustyKeymasterTest ImportKeyTest;
+TEST_F(ImportKeyTest, RsaSuccess) {
+ string pk8_key = read_file("../../../../system/keymaster/rsa_privkey_pk8.der");
+ ASSERT_EQ(633U, pk8_key.size());
+
+ uint8_t* key = NULL;
+ size_t size;
+ ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
+ pk8_key.size(), &key, &size));
+ Malloc_Delete key_deleter(key);
+
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_size = 1024 /* key size */ / 8;
+ UniquePtr<uint8_t[]> message(new uint8_t[message_size]);
+ memset(message.get(), 'a', message_size);
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message.get(), message_size,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message.get(), message_size,
+ signature, siglen));
+}
+
+TEST_F(ImportKeyTest, EcdsaSuccess) {
+ string pk8_key = read_file("../../../../system/keymaster/ec_privkey_pk8.der");
+ ASSERT_EQ(138U, pk8_key.size());
+
+ uint8_t* key = NULL;
+ size_t size;
+ ASSERT_EQ(KM_ERROR_OK, device.import_keypair(reinterpret_cast<const uint8_t*>(pk8_key.data()),
+ pk8_key.size(), &key, &size));
+ Malloc_Delete key_deleter(key);
+
+ keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+ uint8_t message[] = "12345678901234567890123456789012";
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
+ array_size(message) - 1, &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
+ array_size(message) - 1, signature, siglen));
+}
+
+struct EVP_PKEY_CTX_Delete {
+ void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+static void VerifySignature(const uint8_t* key, size_t key_len, const uint8_t* signature,
+ size_t signature_len, const uint8_t* message, size_t message_len) {
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &key, key_len));
+ ASSERT_TRUE(pkey.get() != NULL);
+ UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ ASSERT_TRUE(ctx.get() != NULL);
+ ASSERT_EQ(1, EVP_PKEY_verify_init(ctx.get()));
+ if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA)
+ ASSERT_EQ(1, EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING));
+ EXPECT_EQ(1, EVP_PKEY_verify(ctx.get(), signature, signature_len, message, message_len));
+}
+
+typedef TrustyKeymasterTest ExportKeyTest;
+TEST_F(ExportKeyTest, RsaSuccess) {
+ keymaster_rsa_keygen_params_t params = build_rsa_params();
+ uint8_t* ptr = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_RSA, ¶ms, &ptr, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(ptr);
+
+ uint8_t* exported;
+ size_t exported_size;
+ EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(ptr, size, &exported, &exported_size));
+ Malloc_Delete exported_deleter(exported);
+
+ // Sign a message so we can verify it with the exported pubkey.
+ keymaster_rsa_sign_params_t sig_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(build_message(message_len));
+ uint8_t* signature;
+ size_t siglen;
+ EXPECT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, ptr, size, message.get(), message_len,
+ &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(message_len, siglen);
+ const uint8_t* tmp = exported;
+
+ VerifySignature(exported, exported_size, signature, siglen, message.get(), message_len);
+}
+
+typedef TrustyKeymasterTest ExportKeyTest;
+TEST_F(ExportKeyTest, EcdsaSuccess) {
+ keymaster_ec_keygen_params_t params = {256};
+ uint8_t* key = NULL;
+ size_t size;
+ ASSERT_EQ(0, device.generate_keypair(TYPE_EC, ¶ms, &key, &size));
+ EXPECT_GT(size, 0U);
+ Malloc_Delete key_deleter(key);
+
+ uint8_t* exported;
+ size_t exported_size;
+ EXPECT_EQ(KM_ERROR_OK, device.get_keypair_public(key, size, &exported, &exported_size));
+ Malloc_Delete exported_deleter(exported);
+
+ // Sign a message so we can verify it with the exported pubkey.
+ keymaster_ec_sign_params_t sig_params = {DIGEST_NONE};
+ uint8_t message[] = "12345678901234567890123456789012";
+ uint8_t* signature;
+ size_t siglen;
+ ASSERT_EQ(KM_ERROR_OK, device.sign_data(&sig_params, key, size, message,
+ array_size(message) - 1, &signature, &siglen));
+ Malloc_Delete sig_deleter(signature);
+ EXPECT_EQ(KM_ERROR_OK, device.verify_data(&sig_params, key, size, message,
+ array_size(message) - 1, signature, siglen));
+
+ VerifySignature(exported, exported_size, signature, siglen, message, array_size(message) - 1);
+}
+
+} // namespace test
+} // namespace keymaster
diff --git a/trusty/keymaster/trusty_keymaster_ipc.c b/trusty/keymaster/trusty_keymaster_ipc.c
new file mode 100644
index 0000000..b68209e
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_ipc.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+// TODO: make this generic in libtrusty
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define LOG_TAG "TrustyKeymaster"
+#include <cutils/log.h>
+
+#include <trusty/tipc.h>
+
+#include "trusty_keymaster_ipc.h"
+#include "keymaster_ipc.h"
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+static int handle_ = 0;
+
+int trusty_keymaster_connect() {
+ int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
+ if (rc < 0) {
+ return rc;
+ }
+
+ handle_ = rc;
+ return 0;
+}
+
+int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+ uint32_t *out_size) {
+ if (handle_ == 0) {
+ ALOGE("not connected\n");
+ return -EINVAL;
+ }
+
+ size_t msg_size = in_size + sizeof(struct keymaster_message);
+ struct keymaster_message *msg = malloc(msg_size);
+ msg->cmd = cmd;
+ memcpy(msg->payload, in, in_size);
+
+ ssize_t rc = write(handle_, msg, msg_size);
+ free(msg);
+
+ if (rc < 0) {
+ ALOGE("failed to send cmd (%d) to %s: %s\n", cmd,
+ KEYMASTER_PORT, strerror(errno));
+ return -errno;
+ }
+
+ rc = read(handle_, out, *out_size);
+ if (rc < 0) {
+ ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n",
+ cmd, KEYMASTER_PORT, strerror(errno));
+ return -errno;
+ }
+
+ if ((size_t) rc < sizeof(struct keymaster_message)) {
+ ALOGE("invalid response size (%d)\n", (int) rc);
+ return -EINVAL;
+ }
+
+ msg = (struct keymaster_message *) out;
+
+ if ((cmd | KEYMASTER_RESP_BIT) != msg->cmd) {
+ ALOGE("invalid command (%d)", msg->cmd);
+ return -EINVAL;
+ }
+
+ *out_size = ((size_t) rc) - sizeof(struct keymaster_message);
+ return rc;
+}
+
+void trusty_keymaster_disconnect() {
+ if (handle_ != 0) {
+ tipc_close(handle_);
+ }
+}
+
diff --git a/libcutils/atomic.c b/trusty/keymaster/trusty_keymaster_ipc.h
similarity index 62%
copy from libcutils/atomic.c
copy to trusty/keymaster/trusty_keymaster_ipc.h
index d34aa00..9785247 100644
--- a/libcutils/atomic.c
+++ b/trusty/keymaster/trusty_keymaster_ipc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+__BEGIN_DECLS
-#define ANDROID_ATOMIC_INLINE
+int trusty_keymaster_connect(void);
+int trusty_keymaster_call(uint32_t cmd, void *in, uint32_t in_size, uint8_t *out,
+ uint32_t *out_size);
+void trusty_keymaster_disconnect(void);
-#include <cutils/atomic.h>
+__END_DECLS
diff --git a/trusty/keymaster/trusty_keymaster_main.cpp b/trusty/keymaster/trusty_keymaster_main.cpp
new file mode 100644
index 0000000..7ed880e
--- /dev/null
+++ b/trusty/keymaster/trusty_keymaster_main.cpp
@@ -0,0 +1,368 @@
+/*
+ * Copyright 2014 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 <openssl/evp.h>
+#include <openssl/x509.h>
+
+#include "trusty_keymaster_device.h"
+
+using keymaster::TrustyKeymasterDevice;
+
+unsigned char rsa_privkey_pk8_der[] = {
+ 0x30, 0x82, 0x02, 0x75, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x02, 0x5f, 0x30, 0x82, 0x02, 0x5b, 0x02, 0x01,
+ 0x00, 0x02, 0x81, 0x81, 0x00, 0xc6, 0x09, 0x54, 0x09, 0x04, 0x7d, 0x86, 0x34, 0x81, 0x2d, 0x5a,
+ 0x21, 0x81, 0x76, 0xe4, 0x5c, 0x41, 0xd6, 0x0a, 0x75, 0xb1, 0x39, 0x01, 0xf2, 0x34, 0x22, 0x6c,
+ 0xff, 0xe7, 0x76, 0x52, 0x1c, 0x5a, 0x77, 0xb9, 0xe3, 0x89, 0x41, 0x7b, 0x71, 0xc0, 0xb6, 0xa4,
+ 0x4d, 0x13, 0xaf, 0xe4, 0xe4, 0xa2, 0x80, 0x5d, 0x46, 0xc9, 0xda, 0x29, 0x35, 0xad, 0xb1, 0xff,
+ 0x0c, 0x1f, 0x24, 0xea, 0x06, 0xe6, 0x2b, 0x20, 0xd7, 0x76, 0x43, 0x0a, 0x4d, 0x43, 0x51, 0x57,
+ 0x23, 0x3c, 0x6f, 0x91, 0x67, 0x83, 0xc3, 0x0e, 0x31, 0x0f, 0xcb, 0xd8, 0x9b, 0x85, 0xc2, 0xd5,
+ 0x67, 0x71, 0x16, 0x97, 0x85, 0xac, 0x12, 0xbc, 0xa2, 0x44, 0xab, 0xda, 0x72, 0xbf, 0xb1, 0x9f,
+ 0xc4, 0x4d, 0x27, 0xc8, 0x1e, 0x1d, 0x92, 0xde, 0x28, 0x4f, 0x40, 0x61, 0xed, 0xfd, 0x99, 0x28,
+ 0x07, 0x45, 0xea, 0x6d, 0x25, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x81, 0x80, 0x1b, 0xe0, 0xf0,
+ 0x4d, 0x9c, 0xae, 0x37, 0x18, 0x69, 0x1f, 0x03, 0x53, 0x38, 0x30, 0x8e, 0x91, 0x56, 0x4b, 0x55,
+ 0x89, 0x9f, 0xfb, 0x50, 0x84, 0xd2, 0x46, 0x0e, 0x66, 0x30, 0x25, 0x7e, 0x05, 0xb3, 0xce, 0xab,
+ 0x02, 0x97, 0x2d, 0xfa, 0xbc, 0xd6, 0xce, 0x5f, 0x6e, 0xe2, 0x58, 0x9e, 0xb6, 0x79, 0x11, 0xed,
+ 0x0f, 0xac, 0x16, 0xe4, 0x3a, 0x44, 0x4b, 0x8c, 0x86, 0x1e, 0x54, 0x4a, 0x05, 0x93, 0x36, 0x57,
+ 0x72, 0xf8, 0xba, 0xf6, 0xb2, 0x2f, 0xc9, 0xe3, 0xc5, 0xf1, 0x02, 0x4b, 0x06, 0x3a, 0xc0, 0x80,
+ 0xa7, 0xb2, 0x23, 0x4c, 0xf8, 0xae, 0xe8, 0xf6, 0xc4, 0x7b, 0xbf, 0x4f, 0xd3, 0xac, 0xe7, 0x24,
+ 0x02, 0x90, 0xbe, 0xf1, 0x6c, 0x0b, 0x3f, 0x7f, 0x3c, 0xdd, 0x64, 0xce, 0x3a, 0xb5, 0x91, 0x2c,
+ 0xf6, 0xe3, 0x2f, 0x39, 0xab, 0x18, 0x83, 0x58, 0xaf, 0xcc, 0xcd, 0x80, 0x81, 0x02, 0x41, 0x00,
+ 0xe4, 0xb4, 0x9e, 0xf5, 0x0f, 0x76, 0x5d, 0x3b, 0x24, 0xdd, 0xe0, 0x1a, 0xce, 0xaa, 0xf1, 0x30,
+ 0xf2, 0xc7, 0x66, 0x70, 0xa9, 0x1a, 0x61, 0xae, 0x08, 0xaf, 0x49, 0x7b, 0x4a, 0x82, 0xbe, 0x6d,
+ 0xee, 0x8f, 0xcd, 0xd5, 0xe3, 0xf7, 0xba, 0x1c, 0xfb, 0x1f, 0x0c, 0x92, 0x6b, 0x88, 0xf8, 0x8c,
+ 0x92, 0xbf, 0xab, 0x13, 0x7f, 0xba, 0x22, 0x85, 0x22, 0x7b, 0x83, 0xc3, 0x42, 0xff, 0x7c, 0x55,
+ 0x02, 0x41, 0x00, 0xdd, 0xab, 0xb5, 0x83, 0x9c, 0x4c, 0x7f, 0x6b, 0xf3, 0xd4, 0x18, 0x32, 0x31,
+ 0xf0, 0x05, 0xb3, 0x1a, 0xa5, 0x8a, 0xff, 0xdd, 0xa5, 0xc7, 0x9e, 0x4c, 0xce, 0x21, 0x7f, 0x6b,
+ 0xc9, 0x30, 0xdb, 0xe5, 0x63, 0xd4, 0x80, 0x70, 0x6c, 0x24, 0xe9, 0xeb, 0xfc, 0xab, 0x28, 0xa6,
+ 0xcd, 0xef, 0xd3, 0x24, 0xb7, 0x7e, 0x1b, 0xf7, 0x25, 0x1b, 0x70, 0x90, 0x92, 0xc2, 0x4f, 0xf5,
+ 0x01, 0xfd, 0x91, 0x02, 0x40, 0x23, 0xd4, 0x34, 0x0e, 0xda, 0x34, 0x45, 0xd8, 0xcd, 0x26, 0xc1,
+ 0x44, 0x11, 0xda, 0x6f, 0xdc, 0xa6, 0x3c, 0x1c, 0xcd, 0x4b, 0x80, 0xa9, 0x8a, 0xd5, 0x2b, 0x78,
+ 0xcc, 0x8a, 0xd8, 0xbe, 0xb2, 0x84, 0x2c, 0x1d, 0x28, 0x04, 0x05, 0xbc, 0x2f, 0x6c, 0x1b, 0xea,
+ 0x21, 0x4a, 0x1d, 0x74, 0x2a, 0xb9, 0x96, 0xb3, 0x5b, 0x63, 0xa8, 0x2a, 0x5e, 0x47, 0x0f, 0xa8,
+ 0x8d, 0xbf, 0x82, 0x3c, 0xdd, 0x02, 0x40, 0x1b, 0x7b, 0x57, 0x44, 0x9a, 0xd3, 0x0d, 0x15, 0x18,
+ 0x24, 0x9a, 0x5f, 0x56, 0xbb, 0x98, 0x29, 0x4d, 0x4b, 0x6a, 0xc1, 0x2f, 0xfc, 0x86, 0x94, 0x04,
+ 0x97, 0xa5, 0xa5, 0x83, 0x7a, 0x6c, 0xf9, 0x46, 0x26, 0x2b, 0x49, 0x45, 0x26, 0xd3, 0x28, 0xc1,
+ 0x1e, 0x11, 0x26, 0x38, 0x0f, 0xde, 0x04, 0xc2, 0x4f, 0x91, 0x6d, 0xec, 0x25, 0x08, 0x92, 0xdb,
+ 0x09, 0xa6, 0xd7, 0x7c, 0xdb, 0xa3, 0x51, 0x02, 0x40, 0x77, 0x62, 0xcd, 0x8f, 0x4d, 0x05, 0x0d,
+ 0xa5, 0x6b, 0xd5, 0x91, 0xad, 0xb5, 0x15, 0xd2, 0x4d, 0x7c, 0xcd, 0x32, 0xcc, 0xa0, 0xd0, 0x5f,
+ 0x86, 0x6d, 0x58, 0x35, 0x14, 0xbd, 0x73, 0x24, 0xd5, 0xf3, 0x36, 0x45, 0xe8, 0xed, 0x8b, 0x4a,
+ 0x1c, 0xb3, 0xcc, 0x4a, 0x1d, 0x67, 0x98, 0x73, 0x99, 0xf2, 0xa0, 0x9f, 0x5b, 0x3f, 0xb6, 0x8c,
+ 0x88, 0xd5, 0xe5, 0xd9, 0x0a, 0xc3, 0x34, 0x92, 0xd6};
+unsigned int rsa_privkey_pk8_der_len = 633;
+
+unsigned char dsa_privkey_pk8_der[] = {
+ 0x30, 0x82, 0x01, 0x4b, 0x02, 0x01, 0x00, 0x30, 0x82, 0x01, 0x2b, 0x06, 0x07, 0x2a, 0x86, 0x48,
+ 0xce, 0x38, 0x04, 0x01, 0x30, 0x82, 0x01, 0x1e, 0x02, 0x81, 0x81, 0x00, 0xa3, 0xf3, 0xe9, 0xb6,
+ 0x7e, 0x7d, 0x88, 0xf6, 0xb7, 0xe5, 0xf5, 0x1f, 0x3b, 0xee, 0xac, 0xd7, 0xad, 0xbc, 0xc9, 0xd1,
+ 0x5a, 0xf8, 0x88, 0xc4, 0xef, 0x6e, 0x3d, 0x74, 0x19, 0x74, 0xe7, 0xd8, 0xe0, 0x26, 0x44, 0x19,
+ 0x86, 0xaf, 0x19, 0xdb, 0x05, 0xe9, 0x3b, 0x8b, 0x58, 0x58, 0xde, 0xe5, 0x4f, 0x48, 0x15, 0x01,
+ 0xea, 0xe6, 0x83, 0x52, 0xd7, 0xc1, 0x21, 0xdf, 0xb9, 0xb8, 0x07, 0x66, 0x50, 0xfb, 0x3a, 0x0c,
+ 0xb3, 0x85, 0xee, 0xbb, 0x04, 0x5f, 0xc2, 0x6d, 0x6d, 0x95, 0xfa, 0x11, 0x93, 0x1e, 0x59, 0x5b,
+ 0xb1, 0x45, 0x8d, 0xe0, 0x3d, 0x73, 0xaa, 0xf2, 0x41, 0x14, 0x51, 0x07, 0x72, 0x3d, 0xa2, 0xf7,
+ 0x58, 0xcd, 0x11, 0xa1, 0x32, 0xcf, 0xda, 0x42, 0xb7, 0xcc, 0x32, 0x80, 0xdb, 0x87, 0x82, 0xec,
+ 0x42, 0xdb, 0x5a, 0x55, 0x24, 0x24, 0xa2, 0xd1, 0x55, 0x29, 0xad, 0xeb, 0x02, 0x15, 0x00, 0xeb,
+ 0xea, 0x17, 0xd2, 0x09, 0xb3, 0xd7, 0x21, 0x9a, 0x21, 0x07, 0x82, 0x8f, 0xab, 0xfe, 0x88, 0x71,
+ 0x68, 0xf7, 0xe3, 0x02, 0x81, 0x80, 0x19, 0x1c, 0x71, 0xfd, 0xe0, 0x03, 0x0c, 0x43, 0xd9, 0x0b,
+ 0xf6, 0xcd, 0xd6, 0xa9, 0x70, 0xe7, 0x37, 0x86, 0x3a, 0x78, 0xe9, 0xa7, 0x47, 0xa7, 0x47, 0x06,
+ 0x88, 0xb1, 0xaf, 0xd7, 0xf3, 0xf1, 0xa1, 0xd7, 0x00, 0x61, 0x28, 0x88, 0x31, 0x48, 0x60, 0xd8,
+ 0x11, 0xef, 0xa5, 0x24, 0x1a, 0x81, 0xc4, 0x2a, 0xe2, 0xea, 0x0e, 0x36, 0xd2, 0xd2, 0x05, 0x84,
+ 0x37, 0xcf, 0x32, 0x7d, 0x09, 0xe6, 0x0f, 0x8b, 0x0c, 0xc8, 0xc2, 0xa4, 0xb1, 0xdc, 0x80, 0xca,
+ 0x68, 0xdf, 0xaf, 0xd2, 0x90, 0xc0, 0x37, 0x58, 0x54, 0x36, 0x8f, 0x49, 0xb8, 0x62, 0x75, 0x8b,
+ 0x48, 0x47, 0xc0, 0xbe, 0xf7, 0x9a, 0x92, 0xa6, 0x68, 0x05, 0xda, 0x9d, 0xaf, 0x72, 0x9a, 0x67,
+ 0xb3, 0xb4, 0x14, 0x03, 0xae, 0x4f, 0x4c, 0x76, 0xb9, 0xd8, 0x64, 0x0a, 0xba, 0x3b, 0xa8, 0x00,
+ 0x60, 0x4d, 0xae, 0x81, 0xc3, 0xc5, 0x04, 0x17, 0x02, 0x15, 0x00, 0x81, 0x9d, 0xfd, 0x53, 0x0c,
+ 0xc1, 0x8f, 0xbe, 0x8b, 0xea, 0x00, 0x26, 0x19, 0x29, 0x33, 0x91, 0x84, 0xbe, 0xad, 0x81};
+unsigned int dsa_privkey_pk8_der_len = 335;
+
+unsigned char ec_privkey_pk8_der[] = {
+ 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+ 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02,
+ 0x01, 0x01, 0x04, 0x20, 0x73, 0x7c, 0x2e, 0xcd, 0x7b, 0x8d, 0x19, 0x40, 0xbf, 0x29, 0x30, 0xaa,
+ 0x9b, 0x4e, 0xd3, 0xff, 0x94, 0x1e, 0xed, 0x09, 0x36, 0x6b, 0xc0, 0x32, 0x99, 0x98, 0x64, 0x81,
+ 0xf3, 0xa4, 0xd8, 0x59, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xbf, 0x85, 0xd7, 0x72, 0x0d, 0x07,
+ 0xc2, 0x54, 0x61, 0x68, 0x3b, 0xc6, 0x48, 0xb4, 0x77, 0x8a, 0x9a, 0x14, 0xdd, 0x8a, 0x02, 0x4e,
+ 0x3b, 0xdd, 0x8c, 0x7d, 0xdd, 0x9a, 0xb2, 0xb5, 0x28, 0xbb, 0xc7, 0xaa, 0x1b, 0x51, 0xf1, 0x4e,
+ 0xbb, 0xbb, 0x0b, 0xd0, 0xce, 0x21, 0xbc, 0xc4, 0x1c, 0x6e, 0xb0, 0x00, 0x83, 0xcf, 0x33, 0x76,
+ 0xd1, 0x1f, 0xd4, 0x49, 0x49, 0xe0, 0xb2, 0x18, 0x3b, 0xfe};
+unsigned int ec_privkey_pk8_der_len = 138;
+
+struct EVP_PKEY_Delete {
+ void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
+};
+
+struct EVP_PKEY_CTX_Delete {
+ void operator()(EVP_PKEY_CTX* p) { EVP_PKEY_CTX_free(p); }
+};
+
+static bool test_import_rsa(TrustyKeymasterDevice* device) {
+ printf("===================\n");
+ printf("= RSA Import Test =\n");
+ printf("===================\n\n");
+
+ printf("=== Importing RSA keypair === \n");
+ uint8_t* key;
+ size_t size;
+ int error = device->import_keypair(rsa_privkey_pk8_der, rsa_privkey_pk8_der_len, &key, &size);
+ if (error != KM_ERROR_OK) {
+ printf("Error importing key pair: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> key_deleter(key);
+
+ printf("=== Signing with imported RSA key ===\n");
+ keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = 1024 / 8;
+ UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ uint8_t* signature;
+ size_t signature_len;
+ error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+ &signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error signing data with imported RSA key: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> signature_deleter(signature);
+
+ printf("=== Verifying with imported RSA key === \n");
+ error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+ signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error verifying data with imported RSA key: %d\n\n", error);
+ return false;
+ }
+
+ printf("\n");
+ return true;
+}
+
+static bool test_rsa(TrustyKeymasterDevice* device) {
+ printf("============\n");
+ printf("= RSA Test =\n");
+ printf("============\n\n");
+
+ printf("=== Generating RSA key pair ===\n");
+ keymaster_rsa_keygen_params_t params;
+ params.public_exponent = 65537;
+ params.modulus_size = 2048;
+
+ uint8_t* key;
+ size_t size;
+ int error = device->generate_keypair(TYPE_RSA, ¶ms, &key, &size);
+ if (error != KM_ERROR_OK) {
+ printf("Error generating RSA key pair: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> deleter(key);
+
+ printf("=== Signing with RSA key === \n");
+ keymaster_rsa_sign_params_t sign_params = {DIGEST_NONE, PADDING_NONE};
+ size_t message_len = params.modulus_size / 8;
+ UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ uint8_t* signature;
+ size_t signature_len;
+ error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+ &signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error signing data with RSA key: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> signature_deleter(signature);
+
+ printf("=== Verifying with RSA key === \n");
+ error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+ signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error verifying data with RSA key: %d\n\n", error);
+ return false;
+ }
+
+ printf("=== Exporting RSA public key ===\n");
+ uint8_t* exported_key;
+ size_t exported_size;
+ error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+ if (error != KM_ERROR_OK) {
+ printf("Error exporting RSA public key: %d\n\n", error);
+ return false;
+ }
+
+ printf("=== Verifying with exported key ===\n");
+ const uint8_t* tmp = exported_key;
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
+ UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+ printf("Error initializing openss EVP context\n");
+ return false;
+ }
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_RSA) {
+ printf("Exported key was the wrong type?!?\n");
+ return false;
+ }
+
+ EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_NO_PADDING);
+ if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
+ printf("Verification with exported pubkey failed.\n");
+ return false;
+ } else {
+ printf("Verification succeeded\n");
+ }
+
+ printf("\n");
+ return true;
+}
+
+static bool test_import_ecdsa(TrustyKeymasterDevice* device) {
+ printf("=====================\n");
+ printf("= ECDSA Import Test =\n");
+ printf("=====================\n\n");
+
+ printf("=== Importing ECDSA keypair === \n");
+ uint8_t* key;
+ size_t size;
+ int error = device->import_keypair(ec_privkey_pk8_der, ec_privkey_pk8_der_len, &key, &size);
+ if (error != KM_ERROR_OK) {
+ printf("Error importing key pair: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> deleter(key);
+
+ printf("=== Signing with imported ECDSA key ===\n");
+ keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
+ size_t message_len = 30 /* arbitrary */;
+ UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ uint8_t* signature;
+ size_t signature_len;
+ error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+ &signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error signing data with imported ECDSA key: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> signature_deleter(signature);
+
+ printf("=== Verifying with imported ECDSA key === \n");
+ error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+ signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error verifying data with imported ECDSA key: %d\n\n", error);
+ return false;
+ }
+
+ printf("\n");
+ return true;
+}
+
+static bool test_ecdsa(TrustyKeymasterDevice* device) {
+ printf("==============\n");
+ printf("= ECDSA Test =\n");
+ printf("==============\n\n");
+
+ printf("=== Generating ECDSA key pair ===\n");
+ keymaster_ec_keygen_params_t params;
+ params.field_size = 521;
+ uint8_t* key;
+ size_t size;
+ int error = device->generate_keypair(TYPE_EC, ¶ms, &key, &size);
+ if (error != 0) {
+ printf("Error generating ECDSA key pair: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> deleter(key);
+
+ printf("=== Signing with ECDSA key === \n");
+ keymaster_ec_sign_params_t sign_params = {DIGEST_NONE};
+ size_t message_len = 30 /* arbitrary */;
+ UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
+ memset(message.get(), 'a', message_len);
+ uint8_t* signature;
+ size_t signature_len;
+ error = device->sign_data(&sign_params, key, size, message.get(), message_len, &signature,
+ &signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error signing data with ECDSA key: %d\n\n", error);
+ return false;
+ }
+ UniquePtr<uint8_t[]> signature_deleter(signature);
+
+ printf("=== Verifying with ECDSA key === \n");
+ error = device->verify_data(&sign_params, key, size, message.get(), message_len, signature,
+ signature_len);
+ if (error != KM_ERROR_OK) {
+ printf("Error verifying data with ECDSA key: %d\n\n", error);
+ return false;
+ }
+
+ printf("=== Exporting ECDSA public key ===\n");
+ uint8_t* exported_key;
+ size_t exported_size;
+ error = device->get_keypair_public(key, size, &exported_key, &exported_size);
+ if (error != KM_ERROR_OK) {
+ printf("Error exporting ECDSA public key: %d\n\n", error);
+ return false;
+ }
+
+ printf("=== Verifying with exported key ===\n");
+ const uint8_t* tmp = exported_key;
+ UniquePtr<EVP_PKEY, EVP_PKEY_Delete> pkey(d2i_PUBKEY(NULL, &tmp, exported_size));
+ UniquePtr<EVP_PKEY_CTX, EVP_PKEY_CTX_Delete> ctx(EVP_PKEY_CTX_new(pkey.get(), NULL));
+ if (EVP_PKEY_verify_init(ctx.get()) != 1) {
+ printf("Error initializing openss EVP context\n");
+ return false;
+ }
+ if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) {
+ printf("Exported key was the wrong type?!?\n");
+ return false;
+ }
+
+ if (EVP_PKEY_verify(ctx.get(), signature, signature_len, message.get(), message_len) != 1) {
+ printf("Verification with exported pubkey failed.\n");
+ return false;
+ } else {
+ printf("Verification succeeded\n");
+ }
+
+ printf("\n");
+ return true;
+}
+
+int main(void) {
+
+ TrustyKeymasterDevice device(NULL);
+ if (device.session_error() != KM_ERROR_OK) {
+ printf("Failed to initialize Trusty session: %d\n", device.session_error());
+ return 1;
+ }
+ printf("Trusty session initialized\n");
+
+ bool success = true;
+ success &= test_rsa(&device);
+ success &= test_import_rsa(&device);
+ success &= test_ecdsa(&device);
+ success &= test_import_ecdsa(&device);
+
+ if (success) {
+ printf("\nTESTS PASSED!\n");
+ } else {
+ printf("\n!!!!TESTS FAILED!!!\n");
+ }
+
+ return success ? 0 : 1;
+}
diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c
index 55d5ee6..1fb34c9 100644
--- a/trusty/libtrusty/tipc-test/tipc_test.c
+++ b/trusty/libtrusty/tipc-test/tipc_test.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
+#include <sys/uio.h>
#include <trusty/tipc.h>
@@ -80,6 +81,8 @@
" ta2ta-ipc - execute TA to TA unittest\n"
" dev-uuid - print device uuid\n"
" ta-access - test ta-access flags\n"
+" writev - writev test\n"
+" readv - readv test\n"
"\n"
;
@@ -93,7 +96,7 @@
{
fprintf (stderr, usage, prog);
if (verbose)
- fprintf (stderr, usage_long);
+ fprintf (stderr, "%s", usage_long);
exit(code);
}
@@ -692,6 +695,171 @@
}
+static int writev_test(uint repeat, uint msgsz, bool var)
+{
+ uint i;
+ ssize_t rc;
+ size_t msg_len;
+ int echo_fd = -1;
+ char tx0_buf[msgsz];
+ char tx1_buf[msgsz];
+ char rx_buf [msgsz];
+ struct iovec iovs[2]= {{tx0_buf, 0}, {tx1_buf, 0}};
+
+ if (!opt_silent) {
+ printf("%s: repeat %u: msgsz %u: variable %s\n",
+ __func__, repeat, msgsz, var ? "true" : "false");
+ }
+
+ echo_fd = tipc_connect(dev_name, echo_name);
+ if (echo_fd < 0) {
+ fprintf(stderr, "Failed to connect to service\n");
+ return echo_fd;
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ msg_len = msgsz;
+ if (opt_variable && msgsz) {
+ msg_len = rand() % msgsz;
+ }
+
+ iovs[0].iov_len = msg_len / 3;
+ iovs[1].iov_len = msg_len - iovs[0].iov_len;
+
+ memset(tx0_buf, i + 1, iovs[0].iov_len);
+ memset(tx1_buf, i + 2, iovs[1].iov_len);
+ memset(rx_buf, i + 3, sizeof(rx_buf));
+
+ rc = writev(echo_fd, iovs, 2);
+ if (rc < 0) {
+ perror("writev_test: writev");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "writev", (size_t)rc, msg_len);
+ break;
+ }
+
+ rc = read(echo_fd, rx_buf, sizeof(rx_buf));
+ if (rc < 0) {
+ perror("writev_test: read");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "read", (size_t)rc, msg_len);
+ break;
+ }
+
+ if (memcmp(tx0_buf, rx_buf, iovs[0].iov_len)) {
+ fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
+ break;
+ }
+
+ if (memcmp(tx1_buf, rx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
+ fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
+ break;
+ }
+ }
+
+ tipc_close(echo_fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
+}
+
+static int readv_test(uint repeat, uint msgsz, bool var)
+{
+ uint i;
+ ssize_t rc;
+ size_t msg_len;
+ int echo_fd = -1;
+ char tx_buf [msgsz];
+ char rx0_buf[msgsz];
+ char rx1_buf[msgsz];
+ struct iovec iovs[2]= {{rx0_buf, 0}, {rx1_buf, 0}};
+
+ if (!opt_silent) {
+ printf("%s: repeat %u: msgsz %u: variable %s\n",
+ __func__, repeat, msgsz, var ? "true" : "false");
+ }
+
+ echo_fd = tipc_connect(dev_name, echo_name);
+ if (echo_fd < 0) {
+ fprintf(stderr, "Failed to connect to service\n");
+ return echo_fd;
+ }
+
+ for (i = 0; i < repeat; i++) {
+
+ msg_len = msgsz;
+ if (opt_variable && msgsz) {
+ msg_len = rand() % msgsz;
+ }
+
+ iovs[0].iov_len = msg_len / 3;
+ iovs[1].iov_len = msg_len - iovs[0].iov_len;
+
+ memset(tx_buf, i + 1, sizeof(tx_buf));
+ memset(rx0_buf, i + 2, iovs[0].iov_len);
+ memset(rx1_buf, i + 3, iovs[1].iov_len);
+
+ rc = write(echo_fd, tx_buf, msg_len);
+ if (rc < 0) {
+ perror("readv_test: write");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "write", (size_t)rc, msg_len);
+ break;
+ }
+
+ rc = readv(echo_fd, iovs, 2);
+ if (rc < 0) {
+ perror("readv_test: readv");
+ break;
+ }
+
+ if ((size_t)rc != msg_len) {
+ fprintf(stderr,
+ "%s: %s: data size mismatch (%zd vs. %zd)\n",
+ __func__, "write", (size_t)rc, msg_len);
+ break;
+ }
+
+ if (memcmp(rx0_buf, tx_buf, iovs[0].iov_len)) {
+ fprintf(stderr, "%s: data mismatch: buf 0\n", __func__);
+ break;
+ }
+
+ if (memcmp(rx1_buf, tx_buf + iovs[0].iov_len, iovs[1].iov_len)) {
+ fprintf(stderr, "%s: data mismatch, buf 1\n", __func__);
+ break;
+ }
+ }
+
+ tipc_close(echo_fd);
+
+ if (!opt_silent) {
+ printf("%s: done\n",__func__);
+ }
+
+ return 0;
+}
+
+
int main(int argc, char **argv)
{
int rc = 0;
@@ -735,6 +903,10 @@
rc = dev_uuid_test();
} else if (strcmp(test_name, "ta-access") == 0) {
rc = ta_access_test();
+ } else if (strcmp(test_name, "writev") == 0) {
+ rc = writev_test(opt_repeat, opt_msgsize, opt_variable);
+ } else if (strcmp(test_name, "readv") == 0) {
+ rc = readv_test(opt_repeat, opt_msgsize, opt_variable);
} else {
fprintf(stderr, "Unrecognized test name '%s'\n", test_name);
print_usage_and_exit(argv[0], EXIT_FAILURE, true);
diff --git a/trusty/nvram/Android.mk b/trusty/nvram/Android.mk
new file mode 100644
index 0000000..44e2212
--- /dev/null
+++ b/trusty/nvram/Android.mk
@@ -0,0 +1,43 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# nvram.trusty is the Trusty NVRAM HAL module.
+include $(CLEAR_VARS)
+LOCAL_MODULE := nvram.trusty
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+ module.c \
+ trusty_nvram_device.cpp \
+ trusty_nvram_implementation.cpp
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
+LOCAL_STATIC_LIBRARIES := libnvram-hal
+LOCAL_SHARED_LIBRARIES := libtrusty libnvram-messages liblog
+include $(BUILD_SHARED_LIBRARY)
+
+# nvram-wipe is a helper tool for clearing NVRAM state.
+include $(CLEAR_VARS)
+LOCAL_MODULE := nvram-wipe
+LOCAL_SRC_FILES := \
+ nvram_wipe.cpp \
+ trusty_nvram_implementation.cpp
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
+LOCAL_STATIC_LIBRARIES := libnvram-hal
+LOCAL_SHARED_LIBRARIES := libtrusty libnvram-messages liblog
+include $(BUILD_EXECUTABLE)
diff --git a/trusty/nvram/module.c b/trusty/nvram/module.c
new file mode 100644
index 0000000..a2e64d3
--- /dev/null
+++ b/trusty/nvram/module.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 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 <hardware/nvram.h>
+
+// This function is defined in trusty_nvram_device.cpp.
+int trusty_nvram_open(const hw_module_t* module,
+ const char* device_id,
+ hw_device_t** device_ptr);
+
+static struct hw_module_methods_t nvram_module_methods = {
+ .open = trusty_nvram_open,
+};
+
+struct nvram_module HAL_MODULE_INFO_SYM
+ __attribute__((visibility("default"))) = {
+ .common = {.tag = HARDWARE_MODULE_TAG,
+ .module_api_version = NVRAM_MODULE_API_VERSION_0_1,
+ .hal_api_version = HARDWARE_HAL_API_VERSION,
+ .id = NVRAM_HARDWARE_MODULE_ID,
+ .name = "Trusty NVRAM HAL",
+ .author = "The Android Open Source Project",
+ .methods = &nvram_module_methods,
+ .dso = 0,
+ .reserved = {}},
+};
diff --git a/trusty/nvram/nvram_wipe.cpp b/trusty/nvram/nvram_wipe.cpp
new file mode 100644
index 0000000..d0f4fad
--- /dev/null
+++ b/trusty/nvram/nvram_wipe.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2016 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 <nvram/messages/nvram_messages.h>
+
+#include "trusty_nvram_implementation.h"
+
+void usage(const char* program_name) {
+ fprintf(stderr, "Usage: %s [status|disable|wipe]\n", program_name);
+ exit(-1);
+}
+
+int main(int argc, char* argv[]) {
+ if (argc < 2) {
+ usage(argv[0]);
+ }
+
+ nvram::TrustyNvramImplementation nvram_proxy;
+ nvram::Request request;
+ nvram::Response response;
+
+ if (!strcmp(argv[1], "status")) {
+ request.payload.Activate<nvram::COMMAND_GET_INFO>();
+ nvram_proxy.Execute(request, &response);
+ const nvram::GetInfoResponse* get_info_response =
+ response.payload.get<nvram::COMMAND_GET_INFO>();
+ if (response.result == NV_RESULT_SUCCESS) {
+ int status = get_info_response && get_info_response->wipe_disabled;
+ printf("Wiping disabled: %d\n", status);
+ return status;
+ }
+ } else if (!strcmp(argv[1], "disable")) {
+ request.payload.Activate<nvram::COMMAND_DISABLE_WIPE>();
+ nvram_proxy.Execute(request, &response);
+ } else if (!strcmp(argv[1], "wipe")) {
+ request.payload.Activate<nvram::COMMAND_WIPE_STORAGE>();
+ nvram_proxy.Execute(request, &response);
+ } else {
+ usage(argv[0]);
+ }
+
+ if (response.result != NV_RESULT_SUCCESS) {
+ fprintf(stderr, "Command execution failure: %u\n", response.result);
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/trusty/nvram/trusty_nvram_device.cpp b/trusty/nvram/trusty_nvram_device.cpp
new file mode 100644
index 0000000..2c50915
--- /dev/null
+++ b/trusty/nvram/trusty_nvram_device.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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 <nvram/hal/nvram_device_adapter.h>
+
+#include "trusty_nvram_implementation.h"
+
+extern "C" int trusty_nvram_open(const hw_module_t* module,
+ const char* device_id,
+ hw_device_t** device_ptr) {
+ if (strcmp(NVRAM_HARDWARE_DEVICE_ID, device_id) != 0) {
+ return -EINVAL;
+ }
+
+ nvram::NvramDeviceAdapter* adapter = new nvram::NvramDeviceAdapter(
+ module, new nvram::TrustyNvramImplementation);
+ *device_ptr = adapter->as_device();
+ return 0;
+}
diff --git a/trusty/nvram/trusty_nvram_implementation.cpp b/trusty/nvram/trusty_nvram_implementation.cpp
new file mode 100644
index 0000000..041c1bd
--- /dev/null
+++ b/trusty/nvram/trusty_nvram_implementation.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 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 "trusty_nvram_implementation.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <hardware/nvram.h>
+#include <trusty/tipc.h>
+
+#define LOG_TAG "TrustyNVRAM"
+#include <log/log.h>
+
+#include <nvram/messages/blob.h>
+
+namespace nvram {
+namespace {
+
+// Character device to open for Trusty IPC connections.
+const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
+
+// App identifier of the NVRAM app.
+const char kTrustyNvramAppId[] = "com.android.trusty.nvram";
+
+} // namespace
+
+TrustyNvramImplementation::~TrustyNvramImplementation() {
+ if (tipc_nvram_fd_ != -1) {
+ tipc_close(tipc_nvram_fd_);
+ tipc_nvram_fd_ = -1;
+ }
+}
+
+void TrustyNvramImplementation::Execute(const nvram::Request& request,
+ nvram::Response* response) {
+ if (!SendRequest(request, response)) {
+ response->result = NV_RESULT_INTERNAL_ERROR;
+ }
+}
+
+bool TrustyNvramImplementation::Connect() {
+ if (tipc_nvram_fd_ != -1) {
+ return true;
+ }
+
+ int rc = tipc_connect(kTrustyDeviceName, kTrustyNvramAppId);
+ if (rc < 0) {
+ ALOGE("Failed to connect to Trusty NVRAM app: %s\n", strerror(-rc));
+ return false;
+ }
+
+ tipc_nvram_fd_ = rc;
+ return true;
+}
+
+bool TrustyNvramImplementation::SendRequest(const nvram::Request& request,
+ nvram::Response* response) {
+ if (!Connect()) {
+ return false;
+ }
+
+ nvram::Blob request_buffer;
+ if (!nvram::Encode(request, &request_buffer)) {
+ ALOGE("Failed to encode NVRAM request.\n");
+ return false;
+ }
+
+ ssize_t rc =
+ write(tipc_nvram_fd_, request_buffer.data(), request_buffer.size());
+ if (rc < 0) {
+ ALOGE("Failed to send NVRAM request: %s\n", strerror(-rc));
+ return false;
+ }
+ if (static_cast<size_t>(rc) != request_buffer.size()) {
+ ALOGE("Failed to send full request buffer: %zd\n", rc);
+ return false;
+ }
+
+ rc = read(tipc_nvram_fd_, response_buffer_, sizeof(response_buffer_));
+ if (rc < 0) {
+ ALOGE("Failed to read NVRAM response: %s\n", strerror(-rc));
+ return false;
+ }
+
+ if (static_cast<size_t>(rc) >= sizeof(response_buffer_)) {
+ ALOGE("NVRAM response exceeds response buffer size.\n");
+ return false;
+ }
+
+ if (!nvram::Decode(response_buffer_, static_cast<size_t>(rc), response)) {
+ ALOGE("Failed to decode NVRAM response.\n");
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace nvram
diff --git a/trusty/nvram/trusty_nvram_implementation.h b/trusty/nvram/trusty_nvram_implementation.h
new file mode 100644
index 0000000..60758f7
--- /dev/null
+++ b/trusty/nvram/trusty_nvram_implementation.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2016 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 TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
+#define TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
+
+#include <stdint.h>
+
+#include <nvram/hal/nvram_device_adapter.h>
+#include <nvram/messages/nvram_messages.h>
+
+namespace nvram {
+
+// |TrustyNvramImplementation| proxies requests to the Trusty NVRAM app. It
+// serializes the request objects, sends it to the Trusty app and finally reads
+// back the result and decodes it.
+class TrustyNvramImplementation : public nvram::NvramImplementation {
+ public:
+ ~TrustyNvramImplementation() override;
+
+ void Execute(const nvram::Request& request,
+ nvram::Response* response) override;
+
+ private:
+ // Connects the IPC channel to the Trusty app if it is not already open.
+ // Returns true if the channel is open, false on errors.
+ bool Connect();
+
+ // Dispatches a command to the trust app. Returns true if successful (note
+ // that the response may still indicate an error on the Trusty side), false if
+ // there are any I/O or encoding/decoding errors.
+ bool SendRequest(const nvram::Request& request,
+ nvram::Response* response);
+
+ // The file descriptor for the IPC connection to the Trusty app.
+ int tipc_nvram_fd_ = -1;
+
+ // Response buffer. This puts a hard size limit on the responses from the
+ // Trusty app. 4096 matches the maximum IPC message size currently supported
+ // by Trusty.
+ uint8_t response_buffer_[4096];
+};
+
+} // namespace nvram
+
+#endif // TRUSTY_NVRAM_TRUSTY_NVRAM_IMPLEMENTATION_H_
diff --git a/adf/libadf/Android.mk b/trusty/storage/interface/Android.mk
similarity index 76%
rename from adf/libadf/Android.mk
rename to trusty/storage/interface/Android.mk
index 7df354b..15cb6f3 100644
--- a/adf/libadf/Android.mk
+++ b/trusty/storage/interface/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2013 The Android Open Source Project
+#
+# Copyright (C) 2015 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.
@@ -11,14 +12,14 @@
# 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.
+#
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adf.c
-LOCAL_MODULE := libadf
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -Werror
+
+LOCAL_MODULE := libtrustystorageinterface
+
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
+
include $(BUILD_STATIC_LIBRARY)
diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h
new file mode 100644
index 0000000..b196d88
--- /dev/null
+++ b/trusty/storage/interface/include/trusty/interface/storage.h
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2015-2016 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+/*
+ * Storage port names
+ * @STORAGE_CLIENT_TD_PORT: Port used by clients that require tamper and
+ * rollback detection.
+ * @STORAGE_CLIENT_TDEA_PORT: Port used by clients that require storage before
+ * the non-secure os has booted.
+ * @STORAGE_CLIENT_TP_PORT: Port used by clients that require tamper proof
+ * storage. Note that non-secure code can prevent
+ read and write operations from succeeding, but
+ it cannot modify on-disk data.
+ * @STORAGE_DISK_PROXY_PORT: Port used by non-secure proxy server
+ */
+#define STORAGE_CLIENT_TD_PORT "com.android.trusty.storage.client.td"
+#define STORAGE_CLIENT_TDEA_PORT "com.android.trusty.storage.client.tdea"
+#define STORAGE_CLIENT_TP_PORT "com.android.trusty.storage.client.tp"
+#define STORAGE_DISK_PROXY_PORT "com.android.trusty.storage.proxy"
+
+enum storage_cmd {
+ STORAGE_REQ_SHIFT = 1,
+ STORAGE_RESP_BIT = 1,
+
+ STORAGE_RESP_MSG_ERR = STORAGE_RESP_BIT,
+
+ STORAGE_FILE_DELETE = 1 << STORAGE_REQ_SHIFT,
+ STORAGE_FILE_OPEN = 2 << STORAGE_REQ_SHIFT,
+ STORAGE_FILE_CLOSE = 3 << STORAGE_REQ_SHIFT,
+ STORAGE_FILE_READ = 4 << STORAGE_REQ_SHIFT,
+ STORAGE_FILE_WRITE = 5 << STORAGE_REQ_SHIFT,
+ STORAGE_FILE_GET_SIZE = 6 << STORAGE_REQ_SHIFT,
+ STORAGE_FILE_SET_SIZE = 7 << STORAGE_REQ_SHIFT,
+
+ STORAGE_RPMB_SEND = 8 << STORAGE_REQ_SHIFT,
+
+ /* transaction support */
+ STORAGE_END_TRANSACTION = 9 << STORAGE_REQ_SHIFT,
+};
+
+/**
+ * enum storage_err - error codes for storage protocol
+ * @STORAGE_NO_ERROR: all OK
+ * @STORAGE_ERR_GENERIC: unknown error. Can occur when there's an internal server
+ * error, e.g. the server runs out of memory or is in a bad state.
+ * @STORAGE_ERR_NOT_VALID: input not valid. May occur if the arguments passed
+ * into the command are not valid, for example if the file handle
+ * passed in is not a valid one.
+ * @STORAGE_ERR_UNIMPLEMENTED: the command passed in is not recognized
+ * @STORAGE_ERR_ACCESS: the file is not accessible in the requested mode
+ * @STORAGE_ERR_NOT_FOUND: the file was not found
+ * @STORAGE_ERR_EXIST the file exists when it shouldn't as in with OPEN_CREATE | OPEN_EXCLUSIVE.
+ * @STORAGE_ERR_TRANSACT returned by various operations to indicate that current transaction
+ * is in error state. Such state could be only cleared by sending
+ * STORAGE_END_TRANSACTION message.
+ */
+enum storage_err {
+ STORAGE_NO_ERROR = 0,
+ STORAGE_ERR_GENERIC = 1,
+ STORAGE_ERR_NOT_VALID = 2,
+ STORAGE_ERR_UNIMPLEMENTED = 3,
+ STORAGE_ERR_ACCESS = 4,
+ STORAGE_ERR_NOT_FOUND = 5,
+ STORAGE_ERR_EXIST = 6,
+ STORAGE_ERR_TRANSACT = 7,
+};
+
+/**
+ * storage_delete_flag - flags for controlling delete semantics
+ */
+enum storage_file_delete_flag {
+ STORAGE_FILE_DELETE_MASK = 0,
+};
+
+/**
+ * storage_file_flag - Flags to control 'open' semantics.
+ * @STORAGE_FILE_OPEN_CREATE: if this file does not exist, create it.
+ * @STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: causes STORAGE_FILE_OPEN_CREATE to fail if the file
+ * already exists. Only meaningful if used in combination
+ * with STORAGE_FILE_OPEN_CREATE.
+ * @STORAGE_FILE_OPEN_TRUNCATE: if this file already exists, discard existing content
+ * and open it as a new file. No change in semantics if the
+ * file does not exist.
+ * @STORAGE_FILE_OPEN_MASK: mask for all open flags supported in current protocol.
+ * All other bits must be set to 0.
+ */
+enum storage_file_open_flag {
+ STORAGE_FILE_OPEN_CREATE = (1 << 0),
+ STORAGE_FILE_OPEN_CREATE_EXCLUSIVE = (1 << 1),
+ STORAGE_FILE_OPEN_TRUNCATE = (1 << 2),
+ STORAGE_FILE_OPEN_MASK = STORAGE_FILE_OPEN_CREATE |
+ STORAGE_FILE_OPEN_TRUNCATE |
+ STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+};
+
+/**
+ * enum storage_msg_flag - protocol-level flags in struct storage_msg
+ * @STORAGE_MSG_FLAG_BATCH: if set, command belongs to a batch transaction.
+ * No response will be sent by the server until
+ * it receives a command with this flag unset, at
+ * which point a cummulative result for all messages
+ * sent with STORAGE_MSG_FLAG_BATCH will be sent.
+ * This is only supported by the non-secure disk proxy
+ * server.
+ * @STORAGE_MSG_FLAG_PRE_COMMIT: if set, indicates that server need to commit
+ * pending changes before processing this message.
+ * @STORAGE_MSG_FLAG_POST_COMMIT: if set, indicates that server need to commit
+ * pending changes after processing this message.
+ * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit
+ * current transaction after processing this message.
+ * It is an alias for STORAGE_MSG_FLAG_POST_COMMIT.
+ */
+enum storage_msg_flag {
+ STORAGE_MSG_FLAG_BATCH = 0x1,
+ STORAGE_MSG_FLAG_PRE_COMMIT = 0x2,
+ STORAGE_MSG_FLAG_POST_COMMIT = 0x4,
+ STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT,
+};
+
+/*
+ * The following declarations are the message-specific contents of
+ * the 'payload' element inside struct storage_msg.
+ */
+
+/**
+ * struct storage_file_delete_req - request format for STORAGE_FILE_DELETE
+ * @flags: currently unused, must be set to 0.
+ * @name: the name of the file
+ */
+struct storage_file_delete_req {
+ uint32_t flags;
+ char name[0];
+};
+
+/**
+ * struct storage_file_open_req - request format for STORAGE_FILE_OPEN
+ * @flags: any of enum storage_file_flag or'ed together
+ * @name: the name of the file
+ */
+struct storage_file_open_req {
+ uint32_t flags;
+ char name[0];
+};
+
+/**
+ * struct storage_file_open_resp - response format for STORAGE_FILE_OPEN
+ * @handle: opaque handle to the opened file. Only present on success.
+ */
+struct storage_file_open_resp {
+ uint32_t handle;
+};
+
+/**
+ * struct storage_file_close_req - request format for STORAGE_FILE_CLOSE
+ * @handle: the handle for the file to close
+ */
+struct storage_file_close_req {
+ uint32_t handle;
+};
+
+/**
+ * struct storage_file_read_req - request format for STORAGE_FILE_READ
+ * @handle: the handle for the file from which to read
+ * @size: the quantity of bytes to read from the file
+ * @offset: the offset in the file from whence to read
+ */
+struct storage_file_read_req {
+ uint32_t handle;
+ uint32_t size;
+ uint64_t offset;
+};
+
+/**
+ * struct storage_file_read_resp - response format for STORAGE_FILE_READ
+ * @data: beginning of data retrieved from file
+ */
+struct storage_file_read_resp {
+ uint8_t data[0];
+};
+
+/**
+ * struct storage_file_write_req - request format for STORAGE_FILE_WRITE
+ * @handle: the handle for the file to write to
+ * @offset: the offset in the file from whence to write
+ * @__reserved: unused, must be set to 0.
+ * @data: beginning of the data to be written
+ */
+struct storage_file_write_req {
+ uint64_t offset;
+ uint32_t handle;
+ uint32_t __reserved;
+ uint8_t data[0];
+};
+
+/**
+ * struct storage_file_get_size_req - request format for STORAGE_FILE_GET_SIZE
+ * @handle: handle for which the size is requested
+ */
+struct storage_file_get_size_req {
+ uint32_t handle;
+};
+
+/**
+ * struct storage_file_get_size_resp - response format for STORAGE_FILE_GET_SIZE
+ * @size: the size of the file
+ */
+struct storage_file_get_size_resp {
+ uint64_t size;
+};
+
+/**
+ * struct storage_file_set_size_req - request format for STORAGE_FILE_SET_SIZE
+ * @handle: the file handle
+ * @size: the desired size of the file
+ */
+struct storage_file_set_size_req {
+ uint64_t size;
+ uint32_t handle;
+};
+
+/**
+ * struct storage_rpmb_send_req - request format for STORAGE_RPMB_SEND
+ * @reliable_write_size: size in bytes of reliable write region
+ * @write_size: size in bytes of write region
+ * @read_size: number of bytes to read for a read request
+ * @__reserved: unused, must be set to 0
+ * @payload: start of reliable write region, followed by
+ * write region.
+ *
+ * Only used in proxy<->server interface.
+ */
+struct storage_rpmb_send_req {
+ uint32_t reliable_write_size;
+ uint32_t write_size;
+ uint32_t read_size;
+ uint32_t __reserved;
+ uint8_t payload[0];
+};
+
+/**
+ * struct storage_rpmb_send_resp: response type for STORAGE_RPMB_SEND
+ * @data: the data frames frames retrieved from the MMC.
+ */
+struct storage_rpmb_send_resp {
+ uint8_t data[0];
+};
+
+/**
+ * struct storage_msg - generic req/resp format for all storage commands
+ * @cmd: one of enum storage_cmd
+ * @op_id: client chosen operation identifier for an instance
+ * of a command or atomic grouping of commands (transaction).
+ * @flags: one or many of enum storage_msg_flag or'ed together.
+ * @size: total size of the message including this header
+ * @result: one of enum storage_err
+ * @__reserved: unused, must be set to 0.
+ * @payload: beginning of command specific message format
+ */
+struct storage_msg {
+ uint32_t cmd;
+ uint32_t op_id;
+ uint32_t flags;
+ uint32_t size;
+ int32_t result;
+ uint32_t __reserved;
+ uint8_t payload[0];
+};
+
diff --git a/adf/libadfhwc/Android.mk b/trusty/storage/lib/Android.mk
similarity index 69%
rename from adf/libadfhwc/Android.mk
rename to trusty/storage/lib/Android.mk
index 898f9c9..7e0fc9d 100644
--- a/adf/libadfhwc/Android.mk
+++ b/trusty/storage/lib/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2013 The Android Open Source Project
+#
+# Copyright (C) 2015 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.
@@ -11,15 +12,26 @@
# 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.
+#
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adfhwc.cpp
-LOCAL_MODULE := libadfhwc
-LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_LIBRARIES := libadf liblog libutils
-LOCAL_CFLAGS += -DLOG_TAG=\"adfhwc\" -Werror
+
+LOCAL_MODULE := libtrustystorage
+
+LOCAL_SRC_FILES := \
+ storage.c \
+
+LOCAL_CLFAGS = -fvisibility=hidden -Wall -Werror
+
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+
+LOCAL_STATIC_LIBRARIES := \
+ liblog \
+ libtrusty \
+ libtrustystorageinterface
+
include $(BUILD_STATIC_LIBRARY)
+
diff --git a/trusty/storage/lib/include/trusty/lib/storage.h b/trusty/storage/lib/include/trusty/lib/storage.h
new file mode 100644
index 0000000..b8ddf67
--- /dev/null
+++ b/trusty/storage/lib/include/trusty/lib/storage.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <trusty/interface/storage.h>
+
+#define STORAGE_MAX_NAME_LENGTH_BYTES 159
+
+__BEGIN_DECLS
+
+typedef uint32_t storage_session_t;
+typedef uint64_t file_handle_t;
+typedef uint64_t storage_off_t;
+
+#define STORAGE_INVALID_SESSION ((storage_session_t)-1)
+
+/**
+ * storage_ops_flags - storage related operation flags
+ * @STORAGE_OP_COMPLETE: forces to commit current transaction
+ */
+enum storage_ops_flags {
+ STORAGE_OP_COMPLETE = 0x1,
+};
+
+/**
+ * storage_open_session() - Opens a storage session.
+ * @device: device node for talking with Trusty
+ * @session_p: pointer to location in which to store session handle
+ * in case of success.
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_open_session(const char *device, storage_session_t *session_p, const char *port);
+
+/**
+ * storage_close_session() - Closes the session.
+ * @session: the session to close
+ */
+void storage_close_session(storage_session_t session);
+
+/**
+ * storage_open_file() - Opens a file
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @handle_p: pointer to location in which to store file handle in case of success
+ * @name: a null-terminated string identifier of the file to open.
+ * Cannot be more than STORAGE_MAX_NAME_LENGTH_BYTES in length.
+ * @flags: A bitmask consisting any storage_file_flag value or'ed together:
+ * - STORAGE_FILE_OPEN_CREATE: if this file does not exist, create it.
+ * - STORAGE_FILE_OPEN_CREATE_EXCLUSIVE: when specified, opening file with
+ * STORAGE_OPEN_FILE_CREATE flag will
+ * fail if the file already exists.
+ * Only meaningful if used in combination
+ * with STORAGE_FILE_OPEN_CREATE flag.
+ * - STORAGE_FILE_OPEN_TRUNCATE: if this file already exists, discard existing
+ * content and open it as a new file. No change
+ * in semantics if the file does not exist.
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_open_file(storage_session_t session, file_handle_t *handle_p,
+ const char *name, uint32_t flags, uint32_t opflags);
+
+/**
+ * storage_close_file() - Closes a file.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ */
+void storage_close_file(file_handle_t handle);
+
+/**
+ * storage_delete_file - Deletes a file.
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @name: the name of the file to delete
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, or an error code < 0 on failure.
+ */
+int storage_delete_file(storage_session_t session, const char *name,
+ uint32_t opflags);
+
+/**
+ * storage_read() - Reads a file at a given offset.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the start offset from whence to read in the file
+ * @buf: the buffer in which to write the data read
+ * @size: the size of buf and number of bytes to read
+ *
+ * Return: the number of bytes read on success, negative error code on failure
+ */
+ssize_t storage_read(file_handle_t handle,
+ storage_off_t off, void *buf, size_t size);
+
+/**
+ * storage_write() - Writes to a file at a given offset. Grows the file if necessary.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the start offset from whence to write in the file
+ * @buf: the buffer containing the data to write
+ * @size: the size of buf and number of bytes to write
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: the number of bytes written on success, negative error code on failure
+ */
+ssize_t storage_write(file_handle_t handle,
+ storage_off_t off, const void *buf, size_t size,
+ uint32_t opflags);
+
+/**
+ * storage_set_file_size() - Sets the size of the file.
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @off: the number of bytes to set as the new size of the file
+ * @opflags: a combination of @storage_op_flags
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_set_file_size(file_handle_t handle, storage_off_t file_size,
+ uint32_t opflags);
+
+/**
+ * storage_get_file_size() - Gets the size of the file.
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @handle: the file_handle_t retrieved from storage_open_file
+ * @size: pointer to storage_off_t in which to store the file size
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_get_file_size(file_handle_t handle, storage_off_t *size);
+
+
+/**
+ * storage_end_transaction: End current transaction
+ * @session: the storage_session_t returned from a call to storage_open_session
+ * @complete: if true, commit current transaction, discard it otherwise
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int storage_end_transaction(storage_session_t session, bool complete);
+
+
+__END_DECLS
diff --git a/trusty/storage/lib/storage.c b/trusty/storage/lib/storage.c
new file mode 100644
index 0000000..8130f76
--- /dev/null
+++ b/trusty/storage/lib/storage.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <trusty/tipc.h>
+#include <trusty/lib/storage.h>
+
+#define LOG_TAG "trusty_storage_client"
+#include <cutils/log.h>
+
+#define MAX_CHUNK_SIZE 4040
+
+static inline file_handle_t make_file_handle(storage_session_t s, uint32_t fid)
+{
+ return ((uint64_t)s << 32) | fid;
+}
+
+static inline storage_session_t _to_session(file_handle_t fh)
+{
+ return (storage_session_t)(fh >> 32);
+}
+
+static inline uint32_t _to_handle(file_handle_t fh)
+{
+ return (uint32_t) fh;
+}
+
+static inline uint32_t _to_msg_flags(uint32_t opflags)
+{
+ uint32_t msg_flags = 0;
+
+ if (opflags & STORAGE_OP_COMPLETE)
+ msg_flags |= STORAGE_MSG_FLAG_TRANSACT_COMPLETE;
+
+ return msg_flags;
+}
+
+static ssize_t check_response(struct storage_msg *msg, ssize_t res)
+{
+ if (res < 0)
+ return res;
+
+ if ((size_t)res < sizeof(*msg)) {
+ ALOGE("invalid msg length (%zd < %zd)\n", res, sizeof(*msg));
+ return -EIO;
+ }
+
+ ALOGV("cmd 0x%x: server returned %u\n", msg->cmd, msg->result);
+
+ switch(msg->result) {
+ case STORAGE_NO_ERROR:
+ return res - sizeof(*msg);
+
+ case STORAGE_ERR_NOT_FOUND:
+ return -ENOENT;
+
+ case STORAGE_ERR_EXIST:
+ return -EEXIST;
+
+ case STORAGE_ERR_NOT_VALID:
+ return -EINVAL;
+
+ case STORAGE_ERR_UNIMPLEMENTED:
+ ALOGE("cmd 0x%x: is unhandles command\n", msg->cmd);
+ return -EINVAL;
+
+ case STORAGE_ERR_ACCESS:
+ return -EACCES;
+
+ case STORAGE_ERR_TRANSACT:
+ return -EBUSY;
+
+ case STORAGE_ERR_GENERIC:
+ ALOGE("cmd 0x%x: internal server error\n", msg->cmd);
+ return -EIO;
+
+ default:
+ ALOGE("cmd 0x%x: unhandled server response %u\n",
+ msg->cmd, msg->result);
+ }
+
+ return -EIO;
+}
+
+static ssize_t send_reqv(storage_session_t session,
+ const struct iovec *tx_iovs, uint tx_iovcnt,
+ const struct iovec *rx_iovs, uint rx_iovcnt)
+{
+ ssize_t rc;
+
+ rc = writev(session, tx_iovs, tx_iovcnt);
+ if (rc < 0) {
+ rc = -errno;
+ ALOGE("failed to send request: %s\n", strerror(errno));
+ return rc;
+ }
+
+ rc = readv(session, rx_iovs, rx_iovcnt);
+ if (rc < 0) {
+ rc = -errno;
+ ALOGE("failed to recv response: %s\n", strerror(errno));
+ return rc;
+ }
+
+ return rc;
+}
+
+int storage_open_session(const char *device, storage_session_t *session_p,
+ const char *port)
+{
+ int rc = tipc_connect(device, port);
+ if (rc < 0)
+ return rc;
+ *session_p = (storage_session_t) rc;
+ return 0;
+}
+
+void storage_close_session(storage_session_t session)
+{
+ tipc_close(session);
+}
+
+
+int storage_open_file(storage_session_t session, file_handle_t *handle_p, const char *name,
+ uint32_t flags, uint32_t opflags)
+{
+ struct storage_msg msg = { .cmd = STORAGE_FILE_OPEN, .flags = _to_msg_flags(opflags)};
+ struct storage_file_open_req req = { .flags = flags };
+ struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
+ struct storage_file_open_resp rsp = { 0 };
+ struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};
+
+ ssize_t rc = send_reqv(session, tx, 3, rx, 2);
+ rc = check_response(&msg, rc);
+ if (rc < 0)
+ return rc;
+
+ if ((size_t)rc != sizeof(rsp)) {
+ ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
+ return -EIO;
+ }
+
+ *handle_p = make_file_handle(session, rsp.handle);
+ return 0;
+}
+
+void storage_close_file(file_handle_t fh)
+{
+ struct storage_msg msg = { .cmd = STORAGE_FILE_CLOSE };
+ struct storage_file_close_req req = { .handle = _to_handle(fh)};
+ struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+ struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+ ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
+ rc = check_response(&msg, rc);
+ if (rc < 0) {
+ ALOGE("close file failed (%d)\n", (int)rc);
+ }
+}
+
+int storage_delete_file(storage_session_t session, const char *name, uint32_t opflags)
+{
+ struct storage_msg msg = { .cmd = STORAGE_FILE_DELETE, .flags = _to_msg_flags(opflags)};
+ struct storage_file_delete_req req = { .flags = 0, };
+ struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)name, strlen(name)}};
+ struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+ ssize_t rc = send_reqv(session, tx, 3, rx, 1);
+ return check_response(&msg, rc);
+}
+
+static int _read_chunk(file_handle_t fh, storage_off_t off, void *buf, size_t size)
+{
+ struct storage_msg msg = { .cmd = STORAGE_FILE_READ };
+ struct storage_file_read_req req = { .handle = _to_handle(fh), .size = size, .offset = off };
+ struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+ struct iovec rx[2] = {{&msg, sizeof(msg)}, {buf, size}};
+
+ ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
+ return check_response(&msg, rc);
+}
+
+ssize_t storage_read(file_handle_t fh, storage_off_t off, void *buf, size_t size)
+{
+ int rc;
+ size_t bytes_read = 0;
+ size_t chunk = MAX_CHUNK_SIZE;
+ uint8_t *ptr = buf;
+
+ while (size) {
+ if (chunk > size)
+ chunk = size;
+ rc = _read_chunk(fh, off, ptr, chunk);
+ if (rc < 0)
+ return rc;
+ if (rc == 0)
+ break;
+ off += rc;
+ ptr += rc;
+ bytes_read += rc;
+ size -= rc;
+ }
+ return bytes_read;
+}
+
+static int _write_req(file_handle_t fh, storage_off_t off,
+ const void *buf, size_t size, uint32_t msg_flags)
+{
+ struct storage_msg msg = { .cmd = STORAGE_FILE_WRITE, .flags = msg_flags, };
+ struct storage_file_write_req req = { .handle = _to_handle(fh), .offset = off, };
+ struct iovec tx[3] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}, {(void *)buf, size}};
+ struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+ ssize_t rc = send_reqv(_to_session(fh), tx, 3, rx, 1);
+ rc = check_response(&msg, rc);
+ return rc < 0 ? rc : size;
+}
+
+ssize_t storage_write(file_handle_t fh, storage_off_t off,
+ const void *buf, size_t size, uint32_t opflags)
+{
+ int rc;
+ size_t bytes_written = 0;
+ size_t chunk = MAX_CHUNK_SIZE;
+ const uint8_t *ptr = buf;
+ uint32_t msg_flags = _to_msg_flags(opflags & ~STORAGE_OP_COMPLETE);
+
+ while (size) {
+ if (chunk >= size) {
+ /* last chunk in sequence */
+ chunk = size;
+ msg_flags = _to_msg_flags(opflags);
+ }
+ rc = _write_req(fh, off, ptr, chunk, msg_flags);
+ if (rc < 0)
+ return rc;
+ if ((size_t)rc != chunk) {
+ ALOGE("got partial write (%d)\n", (int)rc);
+ return -EIO;
+ }
+ off += chunk;
+ ptr += chunk;
+ bytes_written += chunk;
+ size -= chunk;
+ }
+ return bytes_written;
+}
+
+int storage_set_file_size(file_handle_t fh, storage_off_t file_size, uint32_t opflags)
+{
+ struct storage_msg msg = { .cmd = STORAGE_FILE_SET_SIZE, .flags = _to_msg_flags(opflags)};
+ struct storage_file_set_size_req req = { .handle = _to_handle(fh), .size = file_size, };
+ struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+ struct iovec rx[1] = {{&msg, sizeof(msg)}};
+
+ ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 1);
+ return check_response(&msg, rc);
+}
+
+int storage_get_file_size(file_handle_t fh, storage_off_t *size_p)
+{
+ struct storage_msg msg = { .cmd = STORAGE_FILE_GET_SIZE };
+ struct storage_file_get_size_req req = { .handle = _to_handle(fh), };
+ struct iovec tx[2] = {{&msg, sizeof(msg)}, {&req, sizeof(req)}};
+ struct storage_file_get_size_resp rsp;
+ struct iovec rx[2] = {{&msg, sizeof(msg)}, {&rsp, sizeof(rsp)}};
+
+ ssize_t rc = send_reqv(_to_session(fh), tx, 2, rx, 2);
+ rc = check_response(&msg, rc);
+ if (rc < 0)
+ return rc;
+
+ if ((size_t)rc != sizeof(rsp)) {
+ ALOGE("%s: invalid response length (%zd != %zd)\n", __func__, rc, sizeof(rsp));
+ return -EIO;
+ }
+
+ *size_p = rsp.size;
+ return 0;
+}
+
+int storage_end_transaction(storage_session_t session, bool complete)
+{
+ struct storage_msg msg = {
+ .cmd = STORAGE_END_TRANSACTION,
+ .flags = complete ? STORAGE_MSG_FLAG_TRANSACT_COMPLETE : 0,
+ };
+ struct iovec iov = {&msg, sizeof(msg)};
+
+ ssize_t rc = send_reqv(session, &iov, 1, &iov, 1);
+ return check_response(&msg, rc);
+}
diff --git a/adf/libadf/Android.mk b/trusty/storage/proxy/Android.mk
similarity index 62%
copy from adf/libadf/Android.mk
copy to trusty/storage/proxy/Android.mk
index 7df354b..745e302 100644
--- a/adf/libadf/Android.mk
+++ b/trusty/storage/proxy/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2013 The Android Open Source Project
+#
+# Copyright (C) 2016 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.
@@ -11,14 +12,30 @@
# 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.
+#
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := adf.c
-LOCAL_MODULE := libadf
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS += -Werror
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
-include $(BUILD_STATIC_LIBRARY)
+
+LOCAL_MODULE := storageproxyd
+
+LOCAL_C_INCLUDES += bionic/libc/kernel/uapi
+
+LOCAL_SRC_FILES := \
+ ipc.c \
+ rpmb.c \
+ storage.c \
+ proxy.c
+
+LOCAL_CLFAGS = -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+
+LOCAL_STATIC_LIBRARIES := \
+ libtrustystorageinterface \
+ libtrusty
+
+include $(BUILD_EXECUTABLE)
+
diff --git a/trusty/storage/proxy/ipc.c b/trusty/storage/proxy/ipc.c
new file mode 100644
index 0000000..b4748e2
--- /dev/null
+++ b/trusty/storage/proxy/ipc.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2016 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 <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+
+#include <trusty/tipc.h>
+
+#include "ipc.h"
+#include "log.h"
+
+#define MAX_RECONNECT_RETRY_COUNT 5
+#define TRUSTY_RECONNECT_TIMEOUT_SEC 5
+
+static int tipc_fd = -1;
+
+int ipc_connect(const char *device, const char *port)
+{
+ int rc;
+ uint retry_cnt = 0;
+
+ assert(tipc_fd == -1);
+
+ while(true) {
+ rc = tipc_connect(device, port);
+ if (rc >= 0)
+ break;
+
+ ALOGE("failed (%d) to connect to storage server\n", rc);
+ if (++retry_cnt > MAX_RECONNECT_RETRY_COUNT) {
+ ALOGE("max number of reconnect retries (%d) has been reached\n",
+ retry_cnt);
+ return -1;
+ }
+ sleep(TRUSTY_RECONNECT_TIMEOUT_SEC);
+ }
+ tipc_fd = rc;
+ return 0;
+}
+
+void ipc_disconnect(void)
+{
+ assert(tipc_fd >= 0);
+
+ tipc_close(tipc_fd);
+ tipc_fd = -1;
+}
+
+ssize_t ipc_get_msg(struct storage_msg *msg, void *req_buf, size_t req_buf_len)
+{
+ ssize_t rc;
+ struct iovec iovs[2] = {{msg, sizeof(*msg)}, {req_buf, req_buf_len}};
+
+ assert(tipc_fd >= 0);
+
+ rc = readv(tipc_fd, iovs, 2);
+ if (rc < 0) {
+ ALOGE("failed to read request: %s\n", strerror(errno));
+ return rc;
+ }
+
+ /* check for minimum size */
+ if ((size_t)rc < sizeof(*msg)) {
+ ALOGE("message is too short (%zu bytes received)\n", rc);
+ return -1;
+ }
+
+ /* check for message completeness */
+ if (msg->size != (uint32_t)rc) {
+ ALOGE("inconsistent message size [cmd=%d] (%u != %u)\n",
+ msg->cmd, msg->size, (uint32_t)rc);
+ return -1;
+ }
+
+ return rc - sizeof(*msg);
+}
+
+int ipc_respond(struct storage_msg *msg, void *out, size_t out_size)
+{
+ ssize_t rc;
+ struct iovec iovs[2] = {{msg, sizeof(*msg)}, {out, out_size}};
+
+ assert(tipc_fd >= 0);
+
+ msg->cmd |= STORAGE_RESP_BIT;
+
+ rc = writev(tipc_fd, iovs, out ? 2 : 1);
+ if (rc < 0) {
+ ALOGE("error sending response 0x%x: %s\n",
+ msg->cmd, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+
diff --git a/libcutils/atomic.c b/trusty/storage/proxy/ipc.h
similarity index 60%
copy from libcutils/atomic.c
copy to trusty/storage/proxy/ipc.h
index d34aa00..2e366bb 100644
--- a/libcutils/atomic.c
+++ b/trusty/storage/proxy/ipc.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -13,14 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+#include <stdint.h>
+#include <trusty/interface/storage.h>
-#define ANDROID_ATOMIC_INLINE
-
-#include <cutils/atomic.h>
+int ipc_connect(const char *device, const char *service_name);
+void ipc_disconnect(void);
+ssize_t ipc_get_msg(struct storage_msg *msg, void *req_buf, size_t req_buf_len);
+int ipc_respond(struct storage_msg *msg, void *out, size_t out_size);
diff --git a/libcutils/atomic.c b/trusty/storage/proxy/log.h
similarity index 62%
copy from libcutils/atomic.c
copy to trusty/storage/proxy/log.h
index d34aa00..471cb50 100644
--- a/libcutils/atomic.c
+++ b/trusty/storage/proxy/log.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,13 +14,6 @@
* limitations under the License.
*/
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+#define LOG_TAG "storageproxyd"
+#include <cutils/log.h>
-#define ANDROID_ATOMIC_INLINE
-
-#include <cutils/atomic.h>
diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c
new file mode 100644
index 0000000..d645ac0
--- /dev/null
+++ b/trusty/storage/proxy/proxy.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <private/android_filesystem_config.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "rpmb.h"
+#include "storage.h"
+
+#define REQ_BUFFER_SIZE 4096
+static uint8_t req_buffer[REQ_BUFFER_SIZE + 1];
+
+static const char *ss_data_root;
+static const char *trusty_devname;
+static const char *rpmb_devname;
+static const char *ss_srv_name = STORAGE_DISK_PROXY_PORT;
+
+static const char *_sopts = "hp:d:r:";
+static const struct option _lopts[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"trusty_dev", required_argument, NULL, 'd'},
+ {"data_path", required_argument, NULL, 'p'},
+ {"rpmb_dev", required_argument, NULL, 'r'},
+ {0, 0, 0, 0}
+};
+
+static void show_usage_and_exit(int code)
+{
+ ALOGE("usage: storageproxyd -d <trusty_dev> -p <data_path> -r <rpmb_dev>\n");
+ exit(code);
+}
+
+static int drop_privs(void)
+{
+ struct __user_cap_header_struct capheader;
+ struct __user_cap_data_struct capdata[2];
+
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0) {
+ return -1;
+ }
+
+ /*
+ * ensure we're running as the system user
+ */
+ if (setgid(AID_SYSTEM) != 0) {
+ return -1;
+ }
+
+ if (setuid(AID_SYSTEM) != 0) {
+ return -1;
+ }
+
+ /*
+ * drop all capabilities except SYS_RAWIO
+ */
+ memset(&capheader, 0, sizeof(capheader));
+ memset(&capdata, 0, sizeof(capdata));
+ capheader.version = _LINUX_CAPABILITY_VERSION_3;
+ capheader.pid = 0;
+
+ capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].permitted = CAP_TO_MASK(CAP_SYS_RAWIO);
+ capdata[CAP_TO_INDEX(CAP_SYS_RAWIO)].effective = CAP_TO_MASK(CAP_SYS_RAWIO);
+
+ if (capset(&capheader, &capdata[0]) < 0) {
+ return -1;
+ }
+
+ /* no-execute for user, no access for group and other */
+ umask(S_IXUSR | S_IRWXG | S_IRWXO);
+
+ return 0;
+}
+
+static int handle_req(struct storage_msg *msg, const void *req, size_t req_len)
+{
+ int rc;
+
+ if ((msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) &&
+ (msg->cmd != STORAGE_RPMB_SEND)) {
+ /*
+ * handling post commit messages on non rpmb commands are not
+ * implemented as there is no use case for this yet.
+ */
+ ALOGE("cmd 0x%x: post commit option is not implemented\n", msg->cmd);
+ msg->result = STORAGE_ERR_UNIMPLEMENTED;
+ return ipc_respond(msg, NULL, 0);
+ }
+
+ if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT) {
+ rc = storage_sync_checkpoint();
+ if (rc < 0) {
+ msg->result = STORAGE_ERR_GENERIC;
+ return ipc_respond(msg, NULL, 0);
+ }
+ }
+
+ switch (msg->cmd) {
+ case STORAGE_FILE_DELETE:
+ rc = storage_file_delete(msg, req, req_len);
+ break;
+
+ case STORAGE_FILE_OPEN:
+ rc = storage_file_open(msg, req, req_len);
+ break;
+
+ case STORAGE_FILE_CLOSE:
+ rc = storage_file_close(msg, req, req_len);
+ break;
+
+ case STORAGE_FILE_WRITE:
+ rc = storage_file_write(msg, req, req_len);
+ break;
+
+ case STORAGE_FILE_READ:
+ rc = storage_file_read(msg, req, req_len);
+ break;
+
+ case STORAGE_FILE_GET_SIZE:
+ rc = storage_file_get_size(msg, req, req_len);
+ break;
+
+ case STORAGE_FILE_SET_SIZE:
+ rc = storage_file_set_size(msg, req, req_len);
+ break;
+
+ case STORAGE_RPMB_SEND:
+ rc = rpmb_send(msg, req, req_len);
+ break;
+
+ default:
+ ALOGE("unhandled command 0x%x\n", msg->cmd);
+ msg->result = STORAGE_ERR_UNIMPLEMENTED;
+ rc = 1;
+ }
+
+ if (rc > 0) {
+ /* still need to send response */
+ rc = ipc_respond(msg, NULL, 0);
+ }
+ return rc;
+}
+
+static int proxy_loop(void)
+{
+ ssize_t rc;
+ struct storage_msg msg;
+
+ /* enter main message handling loop */
+ while (true) {
+
+ /* get incoming message */
+ rc = ipc_get_msg(&msg, req_buffer, REQ_BUFFER_SIZE);
+ if (rc < 0)
+ return rc;
+
+ /* handle request */
+ req_buffer[rc] = 0; /* force zero termination */
+ rc = handle_req(&msg, req_buffer, rc);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+static void parse_args(int argc, char *argv[])
+{
+ int opt;
+ int oidx = 0;
+
+ while ((opt = getopt_long(argc, argv, _sopts, _lopts, &oidx)) != -1) {
+ switch (opt) {
+
+ case 'd':
+ trusty_devname = strdup(optarg);
+ break;
+
+ case 'p':
+ ss_data_root = strdup(optarg);
+ break;
+
+ case 'r':
+ rpmb_devname = strdup(optarg);
+ break;
+
+ default:
+ ALOGE("unrecognized option (%c):\n", opt);
+ show_usage_and_exit(EXIT_FAILURE);
+ }
+ }
+
+ if (ss_data_root == NULL ||
+ trusty_devname == NULL ||
+ rpmb_devname == NULL) {
+ ALOGE("missing required argument(s)\n");
+ show_usage_and_exit(EXIT_FAILURE);
+ }
+
+ ALOGI("starting storageproxyd\n");
+ ALOGI("storage data root: %s\n", ss_data_root);
+ ALOGI("trusty dev: %s\n", trusty_devname);
+ ALOGI("rpmb dev: %s\n", rpmb_devname);
+}
+
+int main(int argc, char *argv[])
+{
+ int rc;
+ uint retry_cnt;
+
+ /* drop privileges */
+ if (drop_privs() < 0)
+ return EXIT_FAILURE;
+
+ /* parse arguments */
+ parse_args(argc, argv);
+
+ /* initialize secure storage directory */
+ rc = storage_init(ss_data_root);
+ if (rc < 0)
+ return EXIT_FAILURE;
+
+ /* open rpmb device */
+ rc = rpmb_open(rpmb_devname);
+ if (rc < 0)
+ return EXIT_FAILURE;
+
+ /* connect to Trusty secure storage server */
+ rc = ipc_connect(trusty_devname, ss_srv_name);
+ if (rc < 0)
+ return EXIT_FAILURE;
+
+ /* enter main loop */
+ rc = proxy_loop();
+ ALOGE("exiting proxy loop with status (%d)\n", rc);
+
+ ipc_disconnect();
+ rpmb_close();
+
+ return (rc < 0) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/trusty/storage/proxy/rpmb.c b/trusty/storage/proxy/rpmb.c
new file mode 100644
index 0000000..9130458
--- /dev/null
+++ b/trusty/storage/proxy/rpmb.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include <linux/major.h>
+#include <linux/mmc/ioctl.h>
+
+#include "ipc.h"
+#include "log.h"
+#include "rpmb.h"
+#include "storage.h"
+
+#define MMC_READ_MULTIPLE_BLOCK 18
+#define MMC_WRITE_MULTIPLE_BLOCK 25
+#define MMC_RELIABLE_WRITE_FLAG (1 << 31)
+
+#define MMC_RSP_PRESENT (1 << 0)
+#define MMC_RSP_CRC (1 << 2)
+#define MMC_RSP_OPCODE (1 << 4)
+#define MMC_CMD_ADTC (1 << 5)
+#define MMC_RSP_SPI_S1 (1 << 7)
+#define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE)
+#define MMC_RSP_SPI_R1 (MMC_RSP_SPI_S1)
+
+#define MMC_WRITE_FLAG_R 0
+#define MMC_WRITE_FLAG_W 1
+#define MMC_WRITE_FLAG_RELW (MMC_WRITE_FLAG_W | MMC_RELIABLE_WRITE_FLAG)
+
+#define MMC_BLOCK_SIZE 512
+
+static int rpmb_fd = -1;
+static uint8_t read_buf[4096];
+
+#ifdef RPMB_DEBUG
+
+static void print_buf(const char *prefix, const uint8_t *buf, size_t size)
+{
+ size_t i;
+
+ printf("%s @%p [%zu]", prefix, buf, size);
+ for (i = 0; i < size; i++) {
+ if (i && i % 32 == 0)
+ printf("\n%*s", (int) strlen(prefix), "");
+ printf(" %02x", buf[i]);
+ }
+ printf("\n");
+ fflush(stdout);
+}
+
+#endif
+
+
+int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len)
+{
+ int rc;
+ struct {
+ struct mmc_ioc_multi_cmd multi;
+ struct mmc_ioc_cmd cmd_buf[3];
+ } mmc = {};
+ struct mmc_ioc_cmd *cmd = mmc.multi.cmds;
+ const struct storage_rpmb_send_req *req = r;
+
+ if (req_len < sizeof(*req)) {
+ ALOGW("malformed rpmb request: invalid length (%zu < %zu)\n",
+ req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ size_t expected_len =
+ sizeof(*req) + req->reliable_write_size + req->write_size;
+ if (req_len != expected_len) {
+ ALOGW("malformed rpmb request: invalid length (%zu != %zu)\n",
+ req_len, expected_len);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ const uint8_t *write_buf = req->payload;
+ if (req->reliable_write_size) {
+ if ((req->reliable_write_size % MMC_BLOCK_SIZE) != 0) {
+ ALOGW("invalid reliable write size %u\n", req->reliable_write_size);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ cmd->write_flag = MMC_WRITE_FLAG_RELW;
+ cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd->blksz = MMC_BLOCK_SIZE;
+ cmd->blocks = req->reliable_write_size / MMC_BLOCK_SIZE;
+ mmc_ioc_cmd_set_data((*cmd), write_buf);
+#ifdef RPMB_DEBUG
+ ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+ print_buf("request: ", write_buf, req->reliable_write_size);
+#endif
+ write_buf += req->reliable_write_size;
+ mmc.multi.num_of_cmds++;
+ cmd++;
+ }
+
+ if (req->write_size) {
+ if ((req->write_size % MMC_BLOCK_SIZE) != 0) {
+ ALOGW("invalid write size %u\n", req->write_size);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ cmd->write_flag = MMC_WRITE_FLAG_W;
+ cmd->opcode = MMC_WRITE_MULTIPLE_BLOCK;
+ cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC;
+ cmd->blksz = MMC_BLOCK_SIZE;
+ cmd->blocks = req->write_size / MMC_BLOCK_SIZE;
+ mmc_ioc_cmd_set_data((*cmd), write_buf);
+#ifdef RPMB_DEBUG
+ ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+ print_buf("request: ", write_buf, req->write_size);
+#endif
+ write_buf += req->write_size;
+ mmc.multi.num_of_cmds++;
+ cmd++;
+ }
+
+ if (req->read_size) {
+ if (req->read_size % MMC_BLOCK_SIZE != 0 ||
+ req->read_size > sizeof(read_buf)) {
+ ALOGE("%s: invalid read size %u\n", __func__, req->read_size);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ cmd->write_flag = MMC_WRITE_FLAG_R;
+ cmd->opcode = MMC_READ_MULTIPLE_BLOCK;
+ cmd->flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC,
+ cmd->blksz = MMC_BLOCK_SIZE;
+ cmd->blocks = req->read_size / MMC_BLOCK_SIZE;
+ mmc_ioc_cmd_set_data((*cmd), read_buf);
+#ifdef RPMB_DEBUG
+ ALOGI("opcode: 0x%x, write_flag: 0x%x\n", cmd->opcode, cmd->write_flag);
+#endif
+ mmc.multi.num_of_cmds++;
+ cmd++;
+ }
+
+ rc = ioctl(rpmb_fd, MMC_IOC_MULTI_CMD, &mmc.multi);
+ if (rc < 0) {
+ ALOGE("%s: mmc ioctl failed: %d, %s\n", __func__, rc, strerror(errno));
+ msg->result = STORAGE_ERR_GENERIC;
+ goto err_response;
+ }
+#ifdef RPMB_DEBUG
+ if (req->read_size)
+ print_buf("response: ", read_buf, req->read_size);
+#endif
+
+ if (msg->flags & STORAGE_MSG_FLAG_POST_COMMIT) {
+ /*
+ * Nothing todo for post msg commit request as MMC_IOC_MULTI_CMD
+ * is fully synchronous in this implementation.
+ */
+ }
+
+ msg->result = STORAGE_NO_ERROR;
+ return ipc_respond(msg, read_buf, req->read_size);
+
+err_response:
+ return ipc_respond(msg, NULL, 0);
+}
+
+
+int rpmb_open(const char *rpmb_devname)
+{
+ int rc;
+
+ rc = open(rpmb_devname, O_RDWR, 0);
+ if (rc < 0) {
+ ALOGE("unable (%d) to open rpmb device '%s': %s\n",
+ errno, rpmb_devname, strerror(errno));
+ return rc;
+ }
+ rpmb_fd = rc;
+ return 0;
+}
+
+void rpmb_close(void)
+{
+ close(rpmb_fd);
+ rpmb_fd = -1;
+}
+
diff --git a/libcutils/atomic.c b/trusty/storage/proxy/rpmb.h
similarity index 62%
rename from libcutils/atomic.c
rename to trusty/storage/proxy/rpmb.h
index d34aa00..85cff44 100644
--- a/libcutils/atomic.c
+++ b/trusty/storage/proxy/rpmb.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -13,14 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
-/*
- * Generate non-inlined versions of android_atomic functions.
- * Nobody should be using these, but some binary blobs currently (late 2014)
- * are.
- * If you read this in 2015 or later, please try to delete this file.
- */
+#include <stdint.h>
+#include <trusty/interface/storage.h>
-#define ANDROID_ATOMIC_INLINE
-
-#include <cutils/atomic.h>
+int rpmb_open(const char *rpmb_devname);
+int rpmb_send(struct storage_msg *msg, const void *r, size_t req_len);
+void rpmb_close(void);
diff --git a/trusty/storage/proxy/storage.c b/trusty/storage/proxy/storage.c
new file mode 100644
index 0000000..c61e89d
--- /dev/null
+++ b/trusty/storage/proxy/storage.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "ipc.h"
+#include "storage.h"
+
+#define FD_TBL_SIZE 64
+#define MAX_READ_SIZE 4096
+
+enum sync_state {
+ SS_UNUSED = -1,
+ SS_CLEAN = 0,
+ SS_DIRTY = 1,
+};
+
+static int ssdir_fd = -1;
+static const char *ssdir_name;
+
+static enum sync_state fs_state;
+static enum sync_state dir_state;
+static enum sync_state fd_state[FD_TBL_SIZE];
+
+static struct {
+ struct storage_file_read_resp hdr;
+ uint8_t data[MAX_READ_SIZE];
+} read_rsp;
+
+static uint32_t insert_fd(int open_flags, int fd)
+{
+ uint32_t handle = fd;
+
+ if (open_flags & O_CREAT) {
+ dir_state = SS_DIRTY;
+ }
+
+ if (handle < FD_TBL_SIZE) {
+ fd_state[fd] = SS_CLEAN; /* fd clean */
+ if (open_flags & O_TRUNC) {
+ fd_state[fd] = SS_DIRTY; /* set fd dirty */
+ }
+ } else {
+ ALOGW("%s: untracked fd %u\n", __func__, fd);
+ if (open_flags & (O_TRUNC | O_CREAT)) {
+ fs_state = SS_DIRTY;
+ }
+ }
+ return handle;
+}
+
+static int lookup_fd(uint32_t handle, bool dirty)
+{
+ if (dirty) {
+ if (handle < FD_TBL_SIZE) {
+ fd_state[handle] = SS_DIRTY;
+ } else {
+ fs_state = SS_DIRTY;
+ }
+ }
+ return handle;
+}
+
+static int remove_fd(uint32_t handle)
+{
+ if (handle < FD_TBL_SIZE) {
+ fd_state[handle] = SS_UNUSED; /* set to uninstalled */
+ }
+ return handle;
+}
+
+static enum storage_err translate_errno(int error)
+{
+ enum storage_err result;
+ switch (error) {
+ case 0:
+ result = STORAGE_NO_ERROR;
+ break;
+ case EBADF:
+ case EINVAL:
+ case ENOTDIR:
+ case EISDIR:
+ case ENAMETOOLONG:
+ result = STORAGE_ERR_NOT_VALID;
+ break;
+ case ENOENT:
+ result = STORAGE_ERR_NOT_FOUND;
+ break;
+ case EEXIST:
+ result = STORAGE_ERR_EXIST;
+ break;
+ case EPERM:
+ case EACCES:
+ result = STORAGE_ERR_ACCESS;
+ break;
+ default:
+ result = STORAGE_ERR_GENERIC;
+ break;
+ }
+
+ return result;
+}
+
+static ssize_t write_with_retry(int fd, const void *buf_, size_t size, off_t offset)
+{
+ ssize_t rc;
+ const uint8_t *buf = buf_;
+
+ while (size > 0) {
+ rc = TEMP_FAILURE_RETRY(pwrite(fd, buf, size, offset));
+ if (rc < 0)
+ return rc;
+ size -= rc;
+ buf += rc;
+ offset += rc;
+ }
+ return 0;
+}
+
+static ssize_t read_with_retry(int fd, void *buf_, size_t size, off_t offset)
+{
+ ssize_t rc;
+ size_t rcnt = 0;
+ uint8_t *buf = buf_;
+
+ while (size > 0) {
+ rc = TEMP_FAILURE_RETRY(pread(fd, buf, size, offset));
+ if (rc < 0)
+ return rc;
+ if (rc == 0)
+ break;
+ size -= rc;
+ buf += rc;
+ offset += rc;
+ rcnt += rc;
+ }
+ return rcnt;
+}
+
+int storage_file_delete(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ char *path = NULL;
+ const struct storage_file_delete_req *req = r;
+
+ if (req_len < sizeof(*req)) {
+ ALOGE("%s: invalid request length (%zd < %zd)\n",
+ __func__, req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ size_t fname_len = strlen(req->name);
+ if (fname_len != req_len - sizeof(*req)) {
+ ALOGE("%s: invalid filename length (%zd != %zd)\n",
+ __func__, fname_len, req_len - sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
+ if (rc < 0) {
+ ALOGE("%s: asprintf failed\n", __func__);
+ msg->result = STORAGE_ERR_GENERIC;
+ goto err_response;
+ }
+
+ dir_state = SS_DIRTY;
+ rc = unlink(path);
+ if (rc < 0) {
+ rc = errno;
+ if (errno == ENOENT) {
+ ALOGV("%s: error (%d) unlinking file '%s'\n",
+ __func__, rc, path);
+ } else {
+ ALOGE("%s: error (%d) unlinking file '%s'\n",
+ __func__, rc, path);
+ }
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+
+ ALOGV("%s: \"%s\"\n", __func__, path);
+ msg->result = STORAGE_NO_ERROR;
+
+err_response:
+ if (path)
+ free(path);
+ return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_open(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ char *path = NULL;
+ const struct storage_file_open_req *req = r;
+ struct storage_file_open_resp resp = {0};
+
+ if (req_len < sizeof(*req)) {
+ ALOGE("%s: invalid request length (%zd < %zd)\n",
+ __func__, req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ size_t fname_len = strlen(req->name);
+ if (fname_len != req_len - sizeof(*req)) {
+ ALOGE("%s: invalid filename length (%zd != %zd)\n",
+ __func__, fname_len, req_len - sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ int rc = asprintf(&path, "%s/%s", ssdir_name, req->name);
+ if (rc < 0) {
+ ALOGE("%s: asprintf failed\n", __func__);
+ msg->result = STORAGE_ERR_GENERIC;
+ goto err_response;
+ }
+
+ int open_flags = O_RDWR;
+
+ if (req->flags & STORAGE_FILE_OPEN_TRUNCATE)
+ open_flags |= O_TRUNC;
+
+ if (req->flags & STORAGE_FILE_OPEN_CREATE) {
+ /* open or create */
+ if (req->flags & STORAGE_FILE_OPEN_CREATE_EXCLUSIVE) {
+ /* create exclusive */
+ open_flags |= O_CREAT | O_EXCL;
+ rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+ } else {
+ /* try open first */
+ rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+ if (rc == -1 && errno == ENOENT) {
+ /* then try open with O_CREATE */
+ open_flags |= O_CREAT;
+ rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+ }
+
+ }
+ } else {
+ /* open an existing file */
+ rc = TEMP_FAILURE_RETRY(open(path, open_flags, S_IRUSR | S_IWUSR));
+ }
+
+ if (rc < 0) {
+ rc = errno;
+ if (errno == EEXIST || errno == ENOENT) {
+ ALOGV("%s: failed to open file \"%s\": %s\n",
+ __func__, path, strerror(errno));
+ } else {
+ ALOGE("%s: failed to open file \"%s\": %s\n",
+ __func__, path, strerror(errno));
+ }
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+ free(path);
+
+ /* at this point rc contains storage file fd */
+ msg->result = STORAGE_NO_ERROR;
+ resp.handle = insert_fd(open_flags, rc);
+ ALOGV("%s: \"%s\": fd = %u: handle = %d\n",
+ __func__, path, rc, resp.handle);
+
+ return ipc_respond(msg, &resp, sizeof(resp));
+
+err_response:
+ if (path)
+ free(path);
+ return ipc_respond(msg, NULL, 0);
+}
+
+int storage_file_close(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ const struct storage_file_close_req *req = r;
+
+ if (req_len != sizeof(*req)) {
+ ALOGE("%s: invalid request length (%zd != %zd)\n",
+ __func__, req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ int fd = remove_fd(req->handle);
+ ALOGV("%s: handle = %u: fd = %u\n", __func__, req->handle, fd);
+
+ int rc = fsync(fd);
+ if (rc < 0) {
+ rc = errno;
+ ALOGE("%s: fsync failed for fd=%u: %s\n",
+ __func__, fd, strerror(errno));
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+
+ rc = close(fd);
+ if (rc < 0) {
+ rc = errno;
+ ALOGE("%s: close failed for fd=%u: %s\n",
+ __func__, fd, strerror(errno));
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+
+ msg->result = STORAGE_NO_ERROR;
+
+err_response:
+ return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_write(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ int rc;
+ const struct storage_file_write_req *req = r;
+
+ if (req_len < sizeof(*req)) {
+ ALOGE("%s: invalid request length (%zd < %zd)\n",
+ __func__, req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ int fd = lookup_fd(req->handle, true);
+ if (write_with_retry(fd, &req->data[0], req_len - sizeof(*req),
+ req->offset) < 0) {
+ rc = errno;
+ ALOGW("%s: error writing file (fd=%d): %s\n",
+ __func__, fd, strerror(errno));
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+
+ msg->result = STORAGE_NO_ERROR;
+
+err_response:
+ return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_read(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ int rc;
+ const struct storage_file_read_req *req = r;
+
+ if (req_len != sizeof(*req)) {
+ ALOGE("%s: invalid request length (%zd != %zd)\n",
+ __func__, req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ if (req->size > MAX_READ_SIZE) {
+ ALOGW("%s: request is too large (%zd > %zd) - refusing\n",
+ __func__, req->size, MAX_READ_SIZE);
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ int fd = lookup_fd(req->handle, false);
+ ssize_t read_res = read_with_retry(fd, read_rsp.hdr.data, req->size,
+ (off_t)req->offset);
+ if (read_res < 0) {
+ rc = errno;
+ ALOGW("%s: error reading file (fd=%d): %s\n",
+ __func__, fd, strerror(errno));
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+
+ msg->result = STORAGE_NO_ERROR;
+ return ipc_respond(msg, &read_rsp, read_res + sizeof(read_rsp.hdr));
+
+err_response:
+ return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_get_size(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ const struct storage_file_get_size_req *req = r;
+ struct storage_file_get_size_resp resp = {0};
+
+ if (req_len != sizeof(*req)) {
+ ALOGE("%s: invalid request length (%zd != %zd)\n",
+ __func__, req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ struct stat stat;
+ int fd = lookup_fd(req->handle, false);
+ int rc = fstat(fd, &stat);
+ if (rc < 0) {
+ rc = errno;
+ ALOGE("%s: error stat'ing file (fd=%d): %s\n",
+ __func__, fd, strerror(errno));
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+
+ resp.size = stat.st_size;
+ msg->result = STORAGE_NO_ERROR;
+ return ipc_respond(msg, &resp, sizeof(resp));
+
+err_response:
+ return ipc_respond(msg, NULL, 0);
+}
+
+
+int storage_file_set_size(struct storage_msg *msg,
+ const void *r, size_t req_len)
+{
+ const struct storage_file_set_size_req *req = r;
+
+ if (req_len != sizeof(*req)) {
+ ALOGE("%s: invalid request length (%zd != %zd)\n",
+ __func__, req_len, sizeof(*req));
+ msg->result = STORAGE_ERR_NOT_VALID;
+ goto err_response;
+ }
+
+ int fd = lookup_fd(req->handle, true);
+ int rc = TEMP_FAILURE_RETRY(ftruncate(fd, req->size));
+ if (rc < 0) {
+ rc = errno;
+ ALOGE("%s: error truncating file (fd=%d): %s\n",
+ __func__, fd, strerror(errno));
+ msg->result = translate_errno(rc);
+ goto err_response;
+ }
+
+ msg->result = STORAGE_NO_ERROR;
+
+err_response:
+ return ipc_respond(msg, NULL, 0);
+}
+
+int storage_init(const char *dirname)
+{
+ fs_state = SS_CLEAN;
+ dir_state = SS_CLEAN;
+ for (uint i = 0; i < FD_TBL_SIZE; i++) {
+ fd_state[i] = SS_UNUSED; /* uninstalled */
+ }
+
+ ssdir_fd = open(dirname, O_RDONLY);
+ if (ssdir_fd < 0) {
+ ALOGE("failed to open ss root dir \"%s\": %s\n",
+ dirname, strerror(errno));
+ return -1;
+ }
+ ssdir_name = dirname;
+ return 0;
+}
+
+int storage_sync_checkpoint(void)
+{
+ int rc;
+
+ /* sync fd table and reset it to clean state first */
+ for (uint fd = 0; fd < FD_TBL_SIZE; fd++) {
+ if (fd_state[fd] == SS_DIRTY) {
+ if (fs_state == SS_CLEAN) {
+ /* need to sync individual fd */
+ rc = fsync(fd);
+ if (rc < 0) {
+ ALOGE("fsync for fd=%d failed: %s\n", fd, strerror(errno));
+ return rc;
+ }
+ }
+ fd_state[fd] = SS_CLEAN; /* set to clean */
+ }
+ }
+
+ /* check if we need to sync the directory */
+ if (dir_state == SS_DIRTY) {
+ if (fs_state == SS_CLEAN) {
+ rc = fsync(ssdir_fd);
+ if (rc < 0) {
+ ALOGE("fsync for ssdir failed: %s\n", strerror(errno));
+ return rc;
+ }
+ }
+ dir_state = SS_CLEAN; /* set to clean */
+ }
+
+ /* check if we need to sync the whole fs */
+ if (fs_state == SS_DIRTY) {
+ rc = syscall(SYS_syncfs, ssdir_fd);
+ if (rc < 0) {
+ ALOGE("syncfs failed: %s\n", strerror(errno));
+ return rc;
+ }
+ fs_state = SS_CLEAN;
+ }
+
+ return 0;
+}
+
diff --git a/trusty/storage/proxy/storage.h b/trusty/storage/proxy/storage.h
new file mode 100644
index 0000000..5a670d4
--- /dev/null
+++ b/trusty/storage/proxy/storage.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+#pragma once
+
+#include <stdint.h>
+#include <trusty/interface/storage.h>
+
+int storage_file_delete(struct storage_msg *msg,
+ const void *req, size_t req_len);
+
+int storage_file_open(struct storage_msg *msg,
+ const void *req, size_t req_len);
+
+int storage_file_close(struct storage_msg *msg,
+ const void *req, size_t req_len);
+
+int storage_file_write(struct storage_msg *msg,
+ const void *req, size_t req_len);
+
+int storage_file_read(struct storage_msg *msg,
+ const void *req, size_t req_len);
+
+int storage_file_get_size(struct storage_msg *msg,
+ const void *req, size_t req_len);
+
+int storage_file_set_size(struct storage_msg *msg,
+ const void *req, size_t req_len);
+
+int storage_init(const char *dirname);
+
+int storage_sync_checkpoint(void);
+
diff --git a/libion/tests/Android.mk b/trusty/storage/tests/Android.mk
similarity index 67%
rename from libion/tests/Android.mk
rename to trusty/storage/tests/Android.mk
index 894f90e..71c904d 100644
--- a/libion/tests/Android.mk
+++ b/trusty/storage/tests/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2013 The Android Open Source Project
+# Copyright (C) 2016 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.
@@ -17,16 +17,13 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := ion-unit-tests
+LOCAL_MODULE := secure-storage-unit-test
LOCAL_CFLAGS += -g -Wall -Werror -std=gnu++11 -Wno-missing-field-initializers
-LOCAL_SHARED_LIBRARIES += libion
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../kernel-headers
-LOCAL_SRC_FILES := \
- ion_test_fixture.cpp \
- allocate_test.cpp \
- formerly_valid_handle_test.cpp \
- invalid_values_test.cpp \
- map_test.cpp \
- device_test.cpp \
- exit_test.cpp
+LOCAL_STATIC_LIBRARIES := \
+ libtrustystorageinterface \
+ libtrustystorage \
+ libtrusty \
+ liblog
+LOCAL_SRC_FILES := main.cpp
include $(BUILD_NATIVE_TEST)
+
diff --git a/trusty/storage/tests/main.cpp b/trusty/storage/tests/main.cpp
new file mode 100644
index 0000000..1fd6f8d
--- /dev/null
+++ b/trusty/storage/tests/main.cpp
@@ -0,0 +1,3040 @@
+/*
+ * Copyright (C) 2016 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 <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <gtest/gtest.h>
+
+#include <trusty/lib/storage.h>
+
+#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
+static inline bool is_32bit_aligned(size_t sz)
+{
+ return ((sz & 0x3) == 0);
+}
+
+static inline bool is_valid_size(size_t sz) {
+ return (sz > 0) && is_32bit_aligned(sz);
+}
+
+static bool is_valid_offset(storage_off_t off)
+{
+ return (off & 0x3) == 0ULL;
+}
+
+static void fill_pattern32(uint32_t *buf, size_t len, storage_off_t off)
+{
+ size_t cnt = len / sizeof(uint32_t);
+ uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
+ while (cnt--) {
+ *buf++ = pattern++;
+ }
+}
+
+static bool check_pattern32(const uint32_t *buf, size_t len, storage_off_t off)
+{
+ size_t cnt = len / sizeof(uint32_t);
+ uint32_t pattern = (uint32_t)(off / sizeof(uint32_t));
+ while (cnt--) {
+ if (*buf != pattern)
+ return false;
+ buf++;
+ pattern++;
+ }
+ return true;
+}
+
+static bool check_value32(const uint32_t *buf, size_t len, uint32_t val)
+{
+ size_t cnt = len / sizeof(uint32_t);
+ while (cnt--) {
+ if (*buf != val)
+ return false;
+ buf++;
+ }
+ return true;
+}
+
+using testing::TestWithParam;
+
+class StorageServiceTest : public virtual TestWithParam<const char *> {
+public:
+ StorageServiceTest() {}
+ virtual ~StorageServiceTest() {}
+
+ virtual void SetUp() {
+ port_ = GetParam();
+ test_buf_ = NULL;
+ aux_session_ = STORAGE_INVALID_SESSION;
+ int rc = storage_open_session(TRUSTY_DEVICE_NAME, &session_, port_);
+ ASSERT_EQ(0, rc);
+ }
+
+ virtual void TearDown() {
+ if (test_buf_) {
+ delete[] test_buf_;
+ test_buf_ = NULL;
+ }
+ storage_close_session(session_);
+
+ if (aux_session_ != STORAGE_INVALID_SESSION) {
+ storage_close_session(aux_session_);
+ aux_session_ = STORAGE_INVALID_SESSION;
+ }
+ }
+
+ void WriteReadAtOffsetHelper(file_handle_t handle, size_t blk, size_t cnt, bool complete);
+
+ void WriteZeroChunk(file_handle_t handle, storage_off_t off, size_t chunk_len, bool complete );
+ void WritePatternChunk(file_handle_t handle, storage_off_t off, size_t chunk_len, bool complete);
+ void WritePattern(file_handle_t handle, storage_off_t off, size_t data_len, size_t chunk_len, bool complete);
+
+ void ReadChunk(file_handle_t handle, storage_off_t off, size_t chunk_len,
+ size_t head_len, size_t pattern_len, size_t tail_len);
+ void ReadPattern(file_handle_t handle, storage_off_t off, size_t data_len, size_t chunk_len);
+ void ReadPatternEOF(file_handle_t handle, storage_off_t off, size_t chunk_len, size_t exp_len);
+
+protected:
+ const char *port_;
+ uint32_t *test_buf_;
+ storage_session_t session_;
+ storage_session_t aux_session_;
+};
+
+INSTANTIATE_TEST_CASE_P(SS_TD_Tests, StorageServiceTest, ::testing::Values(STORAGE_CLIENT_TD_PORT));
+INSTANTIATE_TEST_CASE_P(SS_TDEA_Tests, StorageServiceTest, ::testing::Values(STORAGE_CLIENT_TDEA_PORT));
+INSTANTIATE_TEST_CASE_P(SS_TP_Tests, StorageServiceTest, ::testing::Values(STORAGE_CLIENT_TP_PORT));
+
+
+void StorageServiceTest::WriteZeroChunk(file_handle_t handle, storage_off_t off,
+ size_t chunk_len, bool complete)
+{
+ int rc;
+ uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+ ASSERT_PRED1(is_valid_size, chunk_len);
+ ASSERT_PRED1(is_valid_offset, off);
+
+ memset(data_buf, 0, chunk_len);
+
+ rc = storage_write(handle, off, data_buf, sizeof(data_buf),
+ complete ? STORAGE_OP_COMPLETE : 0);
+ ASSERT_EQ((int)chunk_len, rc);
+}
+
+void StorageServiceTest::WritePatternChunk(file_handle_t handle, storage_off_t off,
+ size_t chunk_len, bool complete)
+{
+ int rc;
+ uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+ ASSERT_PRED1(is_valid_size, chunk_len);
+ ASSERT_PRED1(is_valid_offset, off);
+
+ fill_pattern32(data_buf, chunk_len, off);
+
+ rc = storage_write(handle, off, data_buf, sizeof(data_buf),
+ complete ? STORAGE_OP_COMPLETE : 0);
+ ASSERT_EQ((int)chunk_len, rc);
+}
+
+void StorageServiceTest::WritePattern(file_handle_t handle, storage_off_t off,
+ size_t data_len, size_t chunk_len, bool complete)
+{
+ ASSERT_PRED1(is_valid_size, data_len);
+ ASSERT_PRED1(is_valid_size, chunk_len);
+
+ while (data_len) {
+ if (data_len < chunk_len)
+ chunk_len = data_len;
+ WritePatternChunk(handle, off, chunk_len, (chunk_len == data_len) && complete);
+ ASSERT_FALSE(HasFatalFailure());
+ off += chunk_len;
+ data_len -= chunk_len;
+ }
+}
+
+void StorageServiceTest::ReadChunk(file_handle_t handle,
+ storage_off_t off, size_t chunk_len,
+ size_t head_len, size_t pattern_len,
+ size_t tail_len)
+{
+ int rc;
+ uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+ uint8_t *data_ptr = (uint8_t *)data_buf;
+
+ ASSERT_PRED1(is_valid_size, chunk_len);
+ ASSERT_PRED1(is_valid_offset, off);
+ ASSERT_EQ(head_len + pattern_len + tail_len, chunk_len);
+
+ rc = storage_read(handle, off, data_buf, chunk_len);
+ ASSERT_EQ((int)chunk_len, rc);
+
+ if (head_len) {
+ ASSERT_TRUE(check_value32((const uint32_t *)data_ptr, head_len, 0));
+ data_ptr += head_len;
+ off += head_len;
+ }
+
+ if (pattern_len) {
+ ASSERT_TRUE(check_pattern32((const uint32_t *)data_ptr, pattern_len, off));
+ data_ptr += pattern_len;
+ }
+
+ if (tail_len) {
+ ASSERT_TRUE(check_value32((const uint32_t *)data_ptr, tail_len, 0));
+ }
+}
+
+void StorageServiceTest::ReadPattern(file_handle_t handle, storage_off_t off,
+ size_t data_len, size_t chunk_len)
+{
+ int rc;
+ uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+ ASSERT_PRED1(is_valid_size, chunk_len);
+ ASSERT_PRED1(is_valid_size, data_len);
+ ASSERT_PRED1(is_valid_offset, off);
+
+ while (data_len) {
+ if (chunk_len > data_len)
+ chunk_len = data_len;
+ rc = storage_read(handle, off, data_buf, sizeof(data_buf));
+ ASSERT_EQ((int)chunk_len, rc);
+ ASSERT_TRUE(check_pattern32(data_buf, chunk_len, off));
+ off += chunk_len;
+ data_len -= chunk_len;
+ }
+}
+
+void StorageServiceTest::ReadPatternEOF(file_handle_t handle, storage_off_t off,
+ size_t chunk_len, size_t exp_len)
+{
+ int rc;
+ size_t bytes_read = 0;
+ uint32_t data_buf[chunk_len/sizeof(uint32_t)];
+
+ ASSERT_PRED1(is_valid_size, chunk_len);
+ ASSERT_PRED1(is_32bit_aligned, exp_len);
+
+ while (true) {
+ rc = storage_read(handle, off, data_buf, sizeof(data_buf));
+ ASSERT_GE(rc, 0);
+ if (rc == 0)
+ break; // end of file reached
+ ASSERT_PRED1(is_valid_size, (size_t)rc);
+ ASSERT_TRUE(check_pattern32(data_buf, rc, off));
+ off += rc;
+ bytes_read += rc;
+ }
+ ASSERT_EQ(bytes_read, exp_len);
+}
+
+TEST_P(StorageServiceTest, CreateDelete) {
+ int rc;
+ file_handle_t handle;
+ const char *fname = "test_create_delete_file";
+
+ // make sure test file does not exist (expect success or -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+
+ // one more time (expect -ENOENT only)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // create file (expect 0)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // try to create it again while it is still opened (expect -EEXIST)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EEXIST, rc);
+
+ // close it
+ storage_close_file(handle);
+
+ // try to create it again while it is closed (expect -EEXIST)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EEXIST, rc);
+
+ // delete file (expect 0)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // one more time (expect -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, DeleteOpened) {
+ int rc;
+ file_handle_t handle;
+ const char *fname = "delete_opened_test_file";
+
+ // make sure test file does not exist (expect success or -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+
+ // one more time (expect -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // open/create file (expect 0)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // delete opened file (expect 0)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // one more time (expect -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // close file
+ storage_close_file(handle);
+
+ // one more time (expect -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenNoCreate) {
+ int rc;
+ file_handle_t handle;
+ const char *fname = "test_open_no_create_file";
+
+ // make sure test file does not exist (expect success or -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+
+ // open non-existing file (expect -ENOENT)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // create file (expect 0)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle);
+
+ // open existing file (expect 0)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // close it
+ storage_close_file(handle);
+
+ // delete file (expect 0)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenOrCreate) {
+ int rc;
+ file_handle_t handle;
+ const char *fname = "test_open_create_file";
+
+ // make sure test file does not exist (expect success or -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+
+ // open/create a non-existing file (expect 0)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle);
+
+ // open/create an existing file (expect 0)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle);
+
+ // delete file (expect 0)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenCreateDeleteCharset) {
+ int rc;
+ file_handle_t handle;
+ const char *fname = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz_01234.56789";
+
+ // open/create file (expect 0)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle);
+
+ // open/create an existing file (expect 0)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle);
+
+ // delete file (expect 0)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open again
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, WriteReadSequential) {
+ int rc;
+ size_t blk = 2048;
+ file_handle_t handle;
+ const char *fname = "test_write_read_sequential";
+
+ // make sure test file does not exist (expect success or -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+
+ // create file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write a bunch of blocks (sequentially)
+ WritePattern(handle, 0, 32 * blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPattern(handle, 0, 32 * blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close file
+ storage_close_file(handle);
+
+ // open the same file again
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // read data back (sequentially) and check pattern again
+ ReadPattern(handle, 0, 32 * blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, OpenTruncate) {
+ int rc;
+ uint32_t val;
+ size_t blk = 2048;
+ file_handle_t handle;
+ const char *fname = "test_open_truncate";
+
+ // make sure test file does not exist (expect success or -ENOENT)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+
+ // create file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write some data and read it back
+ WritePatternChunk(handle, 0, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPattern(handle, 0, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close file
+ storage_close_file(handle);
+
+ // reopen with truncate
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_TRUNCATE, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ /* try to read data back (expect no data) */
+ rc = storage_read(handle, 0LL, &val, sizeof(val));
+ ASSERT_EQ(0, rc);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, OpenSame) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ file_handle_t handle3;
+ const char *fname = "test_open_same_file";
+
+ // open/create file (expect 0)
+ rc = storage_open_file(session_, &handle1, fname, STORAGE_FILE_OPEN_CREATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle1);
+
+ // open an existing file first time (expect 0)
+ rc = storage_open_file(session_, &handle1, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // open the same file second time (expect error)
+ rc = storage_open_file(session_, &handle2, fname, 0, 0);
+ ASSERT_NE(0, rc);
+
+ storage_close_file(handle1);
+
+ // delete file (expect 0)
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open deleted file (expect -ENOENT)
+ rc = storage_open_file(session_, &handle3, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, OpenMany) {
+ int rc;
+ file_handle_t handles[10];
+ char filename[10];
+ const char *fname_fmt = "mf%d";
+
+ // open or create a bunch of files (expect 0)
+ for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+ snprintf(filename, sizeof(filename), fname_fmt, i);
+ rc = storage_open_file(session_, &handles[i], filename,
+ STORAGE_FILE_OPEN_CREATE, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+ }
+
+ // check that all handles are different
+ for (uint i = 0; i < ARRAY_SIZE(handles)-1; i++) {
+ for (uint j = i+1; j < ARRAY_SIZE(handles); j++) {
+ ASSERT_NE(handles[i], handles[j]);
+ }
+ }
+
+ // close them all
+ for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+ storage_close_file(handles[i]);
+ }
+
+ // open all files without CREATE flags (expect 0)
+ for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+ snprintf(filename, sizeof(filename), fname_fmt, i);
+ rc = storage_open_file(session_, &handles[i], filename, 0, 0);
+ ASSERT_EQ(0, rc);
+ }
+
+ // check that all handles are different
+ for (uint i = 0; i < ARRAY_SIZE(handles)-1; i++) {
+ for (uint j = i+1; j < ARRAY_SIZE(handles); j++) {
+ ASSERT_NE(handles[i], handles[j]);
+ }
+ }
+
+ // close and remove all test files
+ for (uint i = 0; i < ARRAY_SIZE(handles); ++i) {
+ storage_close_file(handles[i]);
+ snprintf(filename, sizeof(filename), fname_fmt, i);
+ rc = storage_delete_file(session_, filename, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+ }
+}
+
+
+TEST_P(StorageServiceTest, ReadAtEOF) {
+ int rc;
+ uint32_t val;
+ size_t blk = 2048;
+ file_handle_t handle;
+ const char *fname = "test_read_eof";
+
+ // open/create/truncate file
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write block at offset 0
+ WritePatternChunk(handle, 0, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close file
+ storage_close_file(handle);
+
+ // open same file again
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // read the whole block back and check pattern again
+ ReadPattern(handle, 0, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read at end of file (expected 0 bytes)
+ rc = storage_read(handle, blk, &val, sizeof(val));
+ ASSERT_EQ(0, rc);
+
+ // partial read at end of the file (expected partial data)
+ ReadPatternEOF(handle, blk/2, blk, blk/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read past end of file
+ rc = storage_read(handle, blk + 2, &val, sizeof(val));
+ ASSERT_EQ(-EINVAL, rc);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, GetFileSize) {
+ int rc;
+ size_t blk = 2048;
+ storage_off_t size;
+ file_handle_t handle;
+ const char *fname = "test_get_file_size";
+
+ // open/create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // check file size (expect success and size == 0)
+ size = 1;
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, size);
+
+ // write block
+ WritePatternChunk(handle, 0, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check size
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ(blk, size);
+
+ // write another block
+ WritePatternChunk(handle, blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check size again
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ(blk*2, size);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, SetFileSize) {
+ int rc;
+ size_t blk = 2048;
+ storage_off_t size;
+ file_handle_t handle;
+ const char *fname = "test_set_file_size";
+
+ // open/create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // check file size (expect success and size == 0)
+ size = 1;
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, size);
+
+ // write block
+ WritePatternChunk(handle, 0, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check size
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ(blk, size);
+
+ storage_close_file(handle);
+
+ // reopen normally
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // check size again
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ(blk, size);
+
+ // set file size to half
+ rc = storage_set_file_size(handle, blk/2, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // check size again (should be half of original size)
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ(blk/2, size);
+
+ // read data back
+ ReadPatternEOF(handle, 0, blk, blk/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // set file size to 0
+ rc = storage_set_file_size(handle, 0, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // check size again (should be 0)
+ rc = storage_get_file_size(handle, &size);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0LL, size);
+
+ // try to read again
+ ReadPatternEOF(handle, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+void StorageServiceTest::WriteReadAtOffsetHelper(file_handle_t handle, size_t blk, size_t cnt, bool complete)
+{
+ storage_off_t off1 = blk;
+ storage_off_t off2 = blk * (cnt-1);
+
+ // write known pattern data at non-zero offset1
+ WritePatternChunk(handle, off1, blk, complete);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // write known pattern data at non-zero offset2
+ WritePatternChunk(handle, off2, blk, complete);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read data back at offset1
+ ReadPattern(handle, off1, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read data back at offset2
+ ReadPattern(handle, off2, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read partially written data at end of file(expect to get data only, no padding)
+ ReadPatternEOF(handle, off2 + blk/2, blk, blk/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read data at offset 0 (expect success and zero data)
+ ReadChunk(handle, 0, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read data from gap (expect success and zero data)
+ ReadChunk(handle, off1 + blk, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read partially written data (start pointing within written data)
+ // (expect to get written data back and zeroes at the end)
+ ReadChunk(handle, off1 + blk/2, blk, 0, blk/2, blk/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read partially written data (start pointing withing unwritten data)
+ // expect to get zeroes at the beginning and proper data at the end
+ ReadChunk(handle, off1 - blk/2, blk, blk/2, blk/2, 0);
+ ASSERT_FALSE(HasFatalFailure());
+}
+
+
+TEST_P(StorageServiceTest, WriteReadAtOffset) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t blk_cnt = 32;
+ const char *fname = "test_write_at_offset";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write a bunch of blocks filled with zeroes
+ for (uint i = 0; i < blk_cnt; i++) {
+ WriteZeroChunk(handle, i * blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+ }
+
+ WriteReadAtOffsetHelper(handle, blk, blk_cnt, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, WriteSparse) {
+ int rc;
+ file_handle_t handle;
+ const char *fname = "test_write_sparse";
+
+ // open/create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write value past en of file
+ uint32_t val = 0xDEADBEEF;
+ rc = storage_write(handle, 1, &val, sizeof(val), STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+// Persistent 32k
+
+TEST_P(StorageServiceTest, CreatePersistent32K) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t file_size = 32768;
+ const char *fname = "test_persistent_32K_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write a bunch of blocks filled with pattern
+ WritePattern(handle, 0, file_size, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent32k) {
+ int rc;
+ file_handle_t handle;
+ size_t exp_len = 32 * 1024;
+ const char *fname = "test_persistent_32K_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ ReadPatternEOF(handle, 0, 2048, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPatternEOF(handle, 0, 1024, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPatternEOF(handle, 0, 332, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CleanUpPersistent32K) {
+ int rc;
+ const char *fname = "test_persistent_32K_file";
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+}
+
+// Persistent 1M
+TEST_P(StorageServiceTest, CreatePersistent1M_4040) {
+ int rc;
+ file_handle_t handle;
+ size_t file_size = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write a bunch of blocks filled with pattern
+ WritePattern(handle, 0, file_size, 4040, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CreatePersistent1M_2032) {
+ int rc;
+ file_handle_t handle;
+ size_t file_size = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write a bunch of blocks filled with pattern
+ WritePattern(handle, 0, file_size, 2032, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+
+TEST_P(StorageServiceTest, CreatePersistent1M_496) {
+ int rc;
+ file_handle_t handle;
+ size_t file_size = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write a bunch of blocks filled with pattern
+ WritePattern(handle, 0, file_size, 496, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CreatePersistent1M_240) {
+ int rc;
+ file_handle_t handle;
+ size_t file_size = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write a bunch of blocks filled with pattern
+ WritePattern(handle, 0, file_size, 240, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_4040) {
+ int rc;
+ file_handle_t handle;
+ size_t exp_len = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ ReadPatternEOF(handle, 0, 4040, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_2032) {
+ int rc;
+ file_handle_t handle;
+ size_t exp_len = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ ReadPatternEOF(handle, 0, 2032, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_496) {
+ int rc;
+ file_handle_t handle;
+ size_t exp_len = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ ReadPatternEOF(handle, 0, 496, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, ReadPersistent1M_240) {
+ int rc;
+ file_handle_t handle;
+ size_t exp_len = 1024 * 1024;
+ const char *fname = "test_persistent_1M_file";
+
+ // create/truncate file.
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ ReadPatternEOF(handle, 0, 240, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close but do not delete file
+ storage_close_file(handle);
+}
+
+TEST_P(StorageServiceTest, CleanUpPersistent1M) {
+ int rc;
+ const char *fname = "test_persistent_1M_file";
+ rc = storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+ rc = (rc == -ENOENT) ? 0 : rc;
+ ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, WriteReadLong) {
+ int rc;
+ file_handle_t handle;
+ size_t wc = 10000;
+ const char *fname = "test_write_read_long";
+
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ test_buf_ = new uint32_t[wc];
+ fill_pattern32(test_buf_, wc * sizeof(uint32_t), 0);
+ rc = storage_write(handle, 0, test_buf_, wc * sizeof(uint32_t), STORAGE_OP_COMPLETE);
+ ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
+
+ rc = storage_read(handle, 0, test_buf_, wc * sizeof(uint32_t));
+ ASSERT_EQ((int)(wc * sizeof(uint32_t)), rc);
+ ASSERT_TRUE(check_pattern32(test_buf_, wc * sizeof(uint32_t), 0));
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+// Negative tests
+
+TEST_P(StorageServiceTest, OpenInvalidFileName) {
+ int rc;
+ file_handle_t handle;
+ const char *fname1 = "";
+ const char *fname2 = "ffff$ffff";
+ const char *fname3 = "ffff\\ffff";
+ char max_name[STORAGE_MAX_NAME_LENGTH_BYTES+1];
+
+ rc = storage_open_file(session_, &handle, fname1,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ rc = storage_open_file(session_, &handle, fname2,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ rc = storage_open_file(session_, &handle, fname3,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ /* max name */
+ memset(max_name, 'a', sizeof(max_name));
+ max_name[sizeof(max_name)-1] = 0;
+
+ rc = storage_open_file(session_, &handle, max_name,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ max_name[sizeof(max_name)-2] = 0;
+ rc = storage_open_file(session_, &handle, max_name,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ storage_close_file(handle);
+ storage_delete_file(session_, max_name, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, BadFileHnadle) {
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle1;
+ const char *fname = "test_invalid_file_handle";
+
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ handle1 = handle + 1;
+
+ // write to invalid file handle
+ uint32_t val = 0xDEDBEEF;
+ rc = storage_write(handle1, 0, &val, sizeof(val), STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // read from invalid handle
+ rc = storage_read(handle1, 0, &val, sizeof(val));
+ ASSERT_EQ(-EINVAL, rc);
+
+ // set size
+ rc = storage_set_file_size(handle1, 0, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // get size
+ storage_off_t fsize = (storage_off_t)(-1);
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // close (there is no way to check errors here)
+ storage_close_file(handle1);
+
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, ClosedFileHnadle) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ const char *fname1 = "test_invalid_file_handle1";
+ const char *fname2 = "test_invalid_file_handle2";
+
+ rc = storage_open_file(session_, &handle1, fname1,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(session_, &handle2, fname2,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // close first file handle
+ storage_close_file(handle1);
+
+ // write to invalid file handle
+ uint32_t val = 0xDEDBEEF;
+ rc = storage_write(handle1, 0, &val, sizeof(val), STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // read from invalid handle
+ rc = storage_read(handle1, 0, &val, sizeof(val));
+ ASSERT_EQ(-EINVAL, rc);
+
+ // set size
+ rc = storage_set_file_size(handle1, 0, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // get size
+ storage_off_t fsize = (storage_off_t)(-1);
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // close (there is no way to check errors here)
+ storage_close_file(handle1);
+
+ // clean up
+ storage_close_file(handle2);
+ storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+ storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+// Transactions
+
+TEST_P(StorageServiceTest, TransactDiscardInactive) {
+ int rc;
+
+ // discard current transaction (there should not be any)
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // try it again
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, TransactCommitInactive) {
+ int rc;
+
+ // try to commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // try it again
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWrite) {
+
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_discard_write";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // write (without commit)
+ WritePattern(handle, 0, exp_len, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // abort current transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // cleanup
+ storage_close_file( handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactDiscardWriteAppend) {
+
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_write_append";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data with commit
+ WritePattern(handle, 0, exp_len/2, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // write data without commit
+ WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size (should be exp_len)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // discard transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check file size, it should be exp_len/2
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+ // check file data
+ ReadPatternEOF(handle, 0, blk, exp_len/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWriteRead) {
+
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_discard_write_read";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // Fill with zeroes (with commit)
+ for (uint i = 0; i < 32; i++) {
+ WriteZeroChunk(handle, i * blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+ }
+
+ // check that test chunk is filled with zeroes
+ ReadChunk(handle, blk, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // write test pattern (without commit)
+ WritePattern(handle, blk, blk, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read it back an check pattern
+ ReadChunk(handle, blk, blk, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // abort current transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // read same chunk back (should be filled with zeros)
+ ReadChunk(handle, blk, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardWriteMany) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ size_t blk = 2048;
+ size_t exp_len1 = 32 * 1024;
+ size_t exp_len2 = 31 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname1 = "test_transact_discard_write_file1";
+ const char *fname2 = "test_transact_discard_write_file2";
+
+ // open create truncate (with commit)
+ rc = storage_open_file(session_, &handle1, fname1,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate (with commit)
+ rc = storage_open_file(session_, &handle2, fname2,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // file1: fill file with pattern (without commit)
+ WritePattern(handle1, 0, exp_len1, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // file2: fill file with pattern (without commit)
+ WritePattern(handle2, 0, exp_len2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size, it should be exp_len1
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+ // check file size, it should be exp_len2
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+ // commit transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check file size, it should be exp_len1
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // check file size, it should be exp_len2
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // check data
+ ReadPatternEOF(handle1, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPatternEOF(handle2, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+ storage_close_file(handle2);
+ storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardTruncate) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_discard_truncate";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // close file
+ storage_close_file(handle);
+
+ // open truncate file (without commit)
+ rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // abort current transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check file size (should be an oruginal size)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardSetSize) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_discard_set_size";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // set file size to half of original (no commit)
+ rc = storage_set_file_size(handle, (storage_off_t)exp_len/2, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+ // set file size to 1/3 of original (no commit)
+ rc = storage_set_file_size(handle, (storage_off_t)exp_len/3, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+ // abort current transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check file size (should be an original size)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardDelete) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_discard_delete";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close it
+ storage_close_file(handle);
+
+ // delete file (without commit)
+ rc = storage_delete_file(session_, fname, 0);
+ ASSERT_EQ(0, rc);
+
+ // try to open it (should fail)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // abort current transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // try to open it
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size (should be an original size)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactDiscardDelete2) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_discard_delete";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // delete file (without commit)
+ rc = storage_delete_file(session_, fname, 0);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle);
+
+ // try to open it (should fail)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // abort current transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // try to open it
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size (should be an original size)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactDiscardCreate) {
+ int rc;
+ file_handle_t handle;
+ const char *fname = "test_transact_discard_create_excl";
+
+ // delete test file just in case
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+
+ // create file (without commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ 0);
+ ASSERT_EQ(0, rc);
+
+ // abort current transaction
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitWrites) {
+
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle_aux;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_commit_writes";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open the same file in aux session
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size, it should be 0
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // write data in primary session (without commit)
+ WritePattern(handle, 0, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // write more data in primary session (without commit)
+ WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size in aux session, it should still be 0
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // check file size of aux session, should fail
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // abort transaction in aux session to recover
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check file size in aux session, it should be exp_len
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // check file size in primary session, it should be exp_len
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // check data in primary session
+ ReadPatternEOF(handle, 0, blk, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check data in aux session
+ ReadPatternEOF(handle_aux, 0, blk, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_close_file(handle_aux);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitWrites2) {
+
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle_aux;
+ size_t blk = 2048;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_commit_writes2";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open the same file in separate session
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // discard transaction in aux_session
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // Fill with zeroes (with commit)
+ for (uint i = 0; i < 8; i++) {
+ WriteZeroChunk(handle, i * blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+ }
+
+ // check that test chunks are filled with zeroes
+ ReadChunk(handle, blk, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadChunk(handle, 2 * blk, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // write test pattern (without commit)
+ WritePattern(handle, blk, blk, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // write test pattern (without commit)
+ WritePattern(handle, 2 * blk, blk, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read it back and check pattern
+ ReadChunk(handle, blk, blk, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // In aux session it still should be empty
+ ReadChunk(handle_aux, blk, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadChunk(handle_aux, 2 * blk, blk, blk, 0, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // read same chunks back in primary session
+ ReadChunk(handle, blk, blk, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadChunk(handle, 2 * blk, blk, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read same chunks back in aux session (should fail)
+ uint32_t val;
+ rc = storage_read(handle_aux, blk, &val, sizeof(val));
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_read(handle_aux, 2 * blk, &val, sizeof(val));
+ ASSERT_EQ(-EBUSY, rc);
+
+ // abort transaction in aux session
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // read same chunk again in aux session
+ ReadChunk(handle_aux, blk, blk, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadChunk(handle_aux, 2 * blk, blk, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+
+ // cleanup
+ storage_close_file(handle);
+ storage_close_file(handle_aux);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitSetSize) {
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle_aux;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_commit_set_size";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open the same file in separate session
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // same in aux session
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // set file size to half of original (no commit)
+ rc = storage_set_file_size(handle, (storage_off_t)exp_len/2, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // set file size to 1/3 of original (no commit)
+ rc = storage_set_file_size(handle, (storage_off_t)exp_len/3, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // check file size (should be 1/3 of an original size)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+ // check file size from aux session
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // abort transaction in aux_session
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check again
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/3, fsize);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_close_file(handle_aux);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitDelete) {
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle_aux;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ const char *fname = "test_transact_commit_delete";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close it
+ storage_close_file(handle);
+
+ // open the same file in separate session
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle_aux);
+
+ // delete file (without commit)
+ rc = storage_delete_file(session_, fname, 0);
+ ASSERT_EQ(0, rc);
+
+ // try to open it (should fail)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // open the same file in separate session (should be fine)
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+ storage_close_file(handle_aux);
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // try to open it in primary session (still fails)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // open the same file in aux session (should also fail)
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitTruncate) {
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle_aux;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_commit_truncate";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // close file
+ storage_close_file(handle);
+
+ // check from different session
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // open truncate file (without commit)
+ rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // check file size (should be 0)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // check file size in aux session (should be -EBUSY)
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // abort transaction in aux session
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // check again
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_close_file(handle_aux);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitCreate) {
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle_aux;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_commit_create";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // delete test file just in case
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+
+ // check from aux session
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // create file (without commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ 0);
+ ASSERT_EQ(0, rc);
+
+ // check file size
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // close file
+ storage_close_file(handle);
+
+ // check from aux session (should fail)
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // check open from normal session
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // check open from aux session (should succeed)
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // cleanup
+ storage_close_file(handle);
+ storage_close_file(handle_aux);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactCommitCreateMany) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ file_handle_t handle1_aux;
+ file_handle_t handle2_aux;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname1 = "test_transact_commit_create1";
+ const char *fname2 = "test_transact_commit_create2";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // delete test file just in case
+ storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+ storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+
+ // create file (without commit)
+ rc = storage_open_file(session_, &handle1, fname1,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ 0);
+ ASSERT_EQ(0, rc);
+
+ // create file (without commit)
+ rc = storage_open_file(session_, &handle2, fname2,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ 0);
+ ASSERT_EQ(0, rc);
+
+ // check file sizes
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // close files
+ storage_close_file(handle1);
+ storage_close_file(handle2);
+
+ // open files from aux session
+ rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // open from primary session
+ rc = storage_open_file(session_, &handle1, fname1, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(session_, &handle2, fname2, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // open from aux session
+ rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle1_aux);
+ storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+ storage_close_file(handle2);
+ storage_close_file(handle2_aux);
+ storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitWriteMany) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ file_handle_t handle1_aux;
+ file_handle_t handle2_aux;
+ size_t blk = 2048;
+ size_t exp_len1 = 32 * 1024;
+ size_t exp_len2 = 31 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname1 = "test_transact_commit_write_file1";
+ const char *fname2 = "test_transact_commit_write_file2";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate (with commit)
+ rc = storage_open_file(session_, &handle1, fname1,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate (with commit)
+ rc = storage_open_file(session_, &handle2, fname2,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // open same files from aux session
+ rc = storage_open_file(aux_session_, &handle1_aux, fname1, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(aux_session_, &handle2_aux, fname2, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // file1: fill file with pattern (without commit)
+ WritePattern(handle1, 0, exp_len1, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // file2: fill file with pattern (without commit)
+ WritePattern(handle2, 0, exp_len2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size, it should be exp_len1
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+ // check file size, it should be exp_len2
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+ // check file sizes from aux session (should be 0)
+ rc = storage_get_file_size(handle1_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ rc = storage_get_file_size(handle2_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // commit transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // check file size, it should be exp_len1
+ rc = storage_get_file_size(handle1, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+ // check file size, it should be exp_len2
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+ // check from aux session (should be -EBUSY)
+ rc = storage_get_file_size(handle1_aux, &fsize);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // abort transaction in aux session
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // and check again
+ rc = storage_get_file_size(handle1_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len1, fsize);
+
+ rc = storage_get_file_size(handle2_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len2, fsize);
+
+ // check data
+ ReadPatternEOF(handle1, 0, blk, exp_len1);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPatternEOF(handle2, 0, blk, exp_len2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPatternEOF(handle1_aux, 0, blk, exp_len1);
+ ASSERT_FALSE(HasFatalFailure());
+
+ ReadPatternEOF(handle2_aux, 0, blk, exp_len2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle1_aux);
+ storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+ storage_close_file(handle2);
+ storage_close_file(handle2_aux);
+ storage_delete_file(session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactCommitDeleteCreate) {
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle_aux;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_delete_create";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, exp_len, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close it
+ storage_close_file(handle);
+
+ // delete file (without commit)
+ rc = storage_delete_file(session_, fname, 0);
+ ASSERT_EQ(0, rc);
+
+ // try to open it (should fail)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // try to open it in aux session (should succeed)
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // create file with the same name (no commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_CREATE_EXCLUSIVE,
+ 0);
+ ASSERT_EQ(0, rc);
+
+ // write half of data (with commit)
+ WritePattern(handle, 0, exp_len/2, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check file size (should be half)
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+ // commit transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // check data from primary session
+ ReadPatternEOF(handle, 0, blk, exp_len/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // check from aux session (should fail)
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // abort trunsaction in aux session
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // and try again (should still fail)
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // close file and reopen it again
+ storage_close_file(handle_aux);
+ rc = storage_open_file(aux_session_, &handle_aux, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // try it again (should succeed)
+ rc = storage_get_file_size(handle_aux, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+ // check data
+ ReadPatternEOF(handle_aux, 0, blk, exp_len/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_close_file(handle_aux);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, TransactRewriteExistingTruncate) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ const char *fname = "test_transact_rewrite_existing_truncate";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // close it
+ storage_close_file(handle);
+
+ // up
+ for (uint i = 1; i < 32; i++) {
+ // open truncate (no commit)
+ rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, i * blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close
+ storage_close_file(handle);
+ }
+
+ // down
+ for (uint i = 1; i < 32; i++) {
+ // open truncate (no commit)
+ rc = storage_open_file(session_, &handle, fname, STORAGE_FILE_OPEN_TRUNCATE, 0);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, (32 - i) * blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close
+ storage_close_file(handle);
+ }
+
+ // cleanup
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactRewriteExistingSetSize) {
+ int rc;
+ file_handle_t handle;
+ size_t blk = 2048;
+ const char *fname = "test_transact_rewrite_existing_set_size";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // close it
+ storage_close_file(handle);
+
+ // up
+ for (uint i = 1; i < 32; i++) {
+ // open truncate (no commit)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, i * blk, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // update size (with commit)
+ rc = storage_set_file_size(handle, i * blk, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // close
+ storage_close_file(handle);
+ }
+
+ // down
+ for (uint i = 1; i < 32; i++) {
+ // open trancate (no commit)
+ rc = storage_open_file(session_, &handle, fname, 0, 0);
+ ASSERT_EQ(0, rc);
+
+ // write data (with commit)
+ WritePattern(handle, 0, (32 - i) * blk, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // update size (with commit)
+ rc = storage_set_file_size(handle, (32 - i) * blk, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // close
+ storage_close_file(handle);
+ }
+
+ // cleanup
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, TransactResumeAfterNonFatalError) {
+
+ int rc;
+ file_handle_t handle;
+ file_handle_t handle1;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_resume_writes";
+
+ // open create truncate file (with commit)
+ rc = storage_open_file(session_, &handle, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // write (without commit)
+ WritePattern(handle, 0, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // issue some commands that should fail with non-fatal errors
+
+ // write past end of file
+ uint32_t val = 0xDEDBEEF;
+ rc = storage_write(handle, exp_len/2 + 1, &val, sizeof(val), 0);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // read past end of file
+ rc = storage_read(handle, exp_len/2 + 1, &val, sizeof(val));
+ ASSERT_EQ(-EINVAL, rc);
+
+ // try to extend file past end of file
+ rc = storage_set_file_size(handle, exp_len/2 + 1, 0);
+ ASSERT_EQ(-EINVAL, rc);
+
+ // open non existing file
+ rc = storage_open_file(session_, &handle1, "foo",
+ STORAGE_FILE_OPEN_TRUNCATE, STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // delete non-existing file
+ rc = storage_delete_file(session_, "foo", STORAGE_OP_COMPLETE);
+ ASSERT_EQ(-ENOENT, rc);
+
+ // then resume writinga (without commit)
+ WritePattern(handle, exp_len/2, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // commit current transaction
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // check file size, it should be exp_len
+ rc = storage_get_file_size(handle, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // check data
+ ReadPatternEOF(handle, 0, blk, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle);
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+// Transaction Collisions
+
+TEST_P(StorageServiceTest, Transact2_WriteNC) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ size_t blk = 2048;
+ const char *fname1 = "test_transact_f1";
+ const char *fname2 = "test_transact_f2";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(session_, &handle1, fname1,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(aux_session_, &handle2, fname2,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // session 1
+ WritePattern(handle1, 0, blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read it back
+ ReadPatternEOF(handle1, 0, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // session 2
+ WritePattern(handle2, 0, blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read it back
+ ReadPatternEOF(handle2, 0, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle2);
+
+ storage_delete_file(session_, fname1, STORAGE_OP_COMPLETE);
+ storage_delete_file(aux_session_, fname2, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_DeleteNC) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ size_t blk = 2048;
+ const char *fname1 = "test_transact_delete_f1";
+ const char *fname2 = "test_transact_delete_f2";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(session_, &handle1, fname1,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_open_file(aux_session_, &handle2, fname2,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // session 1
+ WritePattern(handle1, 0, blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read it back
+ ReadPatternEOF(handle1, 0, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // session 2
+ WritePattern(handle2, 0, blk, blk, true);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // read it back
+ ReadPatternEOF(handle2, 0, blk, blk);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // close files and delete them
+ storage_close_file(handle1);
+ storage_delete_file(session_, fname1, 0);
+
+ storage_close_file(handle2);
+ storage_delete_file(aux_session_, fname2, 0);
+
+ // commit
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ rc = storage_end_transaction(aux_session_, true);
+ ASSERT_EQ(0, rc);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Read) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_writeRead";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // S1: open create truncate file
+ rc = storage_open_file(session_, &handle1, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S2: open the same file
+ rc = storage_open_file(aux_session_, &handle2, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S1: write (no commit)
+ WritePattern(handle1, 0, exp_len, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S1: read it back
+ ReadPatternEOF(handle1, 0, blk, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S2: check file size, it should be 0
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // S2: read it back (should no data)
+ ReadPatternEOF(handle2, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S1: commit
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // S2: check file size, it should fail
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // S2: abort transaction
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // S2: check file size again, it should be exp_len
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // S2: read it again (should be exp_len)
+ ReadPatternEOF(handle2, 0, blk, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle2);
+
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Commit_Commit) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ file_handle_t handle3;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_write_write_commit_commit";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // S1: open create truncate file
+ rc = storage_open_file(session_, &handle1, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S2: open the same file
+ rc = storage_open_file(aux_session_, &handle2, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S1: write (no commit)
+ WritePattern(handle1, 0, exp_len, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S2: write (no commit)
+ WritePattern(handle2, 0, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S1: commit
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // S2: read/write/get/set size/delete (all should fail)
+ uint32_t val = 0;
+ rc = storage_read(handle2, 0, &val, sizeof(val));
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_write(handle2, 0, &val, sizeof(val), 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_set_file_size(handle2, fsize, 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_delete_file(aux_session_, fname, 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_open_file(aux_session_, &handle3, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // S2: commit (should fail, and failed state should be cleared)
+ rc = storage_end_transaction(aux_session_, true);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // S2: check file size, it should be exp_len
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // S2: read it again (should be exp_len)
+ ReadPatternEOF(handle2, 0, blk, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle2);
+
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Commit_Discard) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ file_handle_t handle3;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_write_write_commit_discard";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // S1: open create truncate file
+ rc = storage_open_file(session_, &handle1, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S2: open the same file
+ rc = storage_open_file(aux_session_, &handle2, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S1: write (no commit)
+ WritePattern(handle1, 0, exp_len, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S2: write (no commit)
+ WritePattern(handle2, 0, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S1: commit
+ rc = storage_end_transaction(session_, true);
+ ASSERT_EQ(0, rc);
+
+ // S2: read/write/get/set size/delete (all should fail)
+ uint32_t val = 0;
+ rc = storage_read(handle2, 0, &val, sizeof(val));
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_write(handle2, 0, &val, sizeof(val), 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_set_file_size(handle2, fsize, 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_delete_file(aux_session_, fname, 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ rc = storage_open_file(aux_session_, &handle3, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE, 0);
+ ASSERT_EQ(-EBUSY, rc);
+
+ // S2: discard (should fail, and failed state should be cleared)
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // S2: check file size, it should be exp_len
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len, fsize);
+
+ // S2: read it again (should be exp_len)
+ ReadPatternEOF(handle2, 0, blk, exp_len);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle2);
+
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Discard_Commit) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_write_write_discard_commit";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // S1: open create truncate file
+ rc = storage_open_file(session_, &handle1, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S2: open the same file
+ rc = storage_open_file(aux_session_, &handle2, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S1: write (no commit)
+ WritePattern(handle1, 0, exp_len, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S2: write (no commit)
+ WritePattern(handle2, 0, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S1: discard
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // S2: commit (should succeed)
+ rc = storage_end_transaction(aux_session_, true);
+ ASSERT_EQ(0, rc);
+
+ // S2: check file size, it should be exp_len
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)exp_len/2, fsize);
+
+ // S2: read it again (should be exp_len)
+ ReadPatternEOF(handle2, 0, blk, exp_len/2);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle2);
+
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
+
+TEST_P(StorageServiceTest, Transact2_Write_Write_Discard_Discard) {
+ int rc;
+ file_handle_t handle1;
+ file_handle_t handle2;
+ size_t blk = 2048;
+ size_t exp_len = 32 * 1024;
+ storage_off_t fsize = (storage_off_t)(-1);
+ const char *fname = "test_transact_write_write_discard_Discard";
+
+ // open second session
+ rc = storage_open_session(TRUSTY_DEVICE_NAME, &aux_session_, port_);
+ ASSERT_EQ(0, rc);
+
+ // S1: open create truncate file
+ rc = storage_open_file(session_, &handle1, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S2: open the same file
+ rc = storage_open_file(aux_session_, &handle2, fname,
+ STORAGE_FILE_OPEN_CREATE | STORAGE_FILE_OPEN_TRUNCATE,
+ STORAGE_OP_COMPLETE);
+ ASSERT_EQ(0, rc);
+
+ // S1: write (no commit)
+ WritePattern(handle1, 0, exp_len, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S2: write (no commit)
+ WritePattern(handle2, 0, exp_len/2, blk, false);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // S1: discard
+ rc = storage_end_transaction(session_, false);
+ ASSERT_EQ(0, rc);
+
+ // S2: discard
+ rc = storage_end_transaction(aux_session_, false);
+ ASSERT_EQ(0, rc);
+
+ // S2: check file size, it should be 0
+ rc = storage_get_file_size(handle2, &fsize);
+ ASSERT_EQ(0, rc);
+ ASSERT_EQ((storage_off_t)0, fsize);
+
+ // S2: read it again (should be 0)
+ ReadPatternEOF(handle2, 0, blk, 0);
+ ASSERT_FALSE(HasFatalFailure());
+
+ // cleanup
+ storage_close_file(handle1);
+ storage_close_file(handle2);
+
+ storage_delete_file(session_, fname, STORAGE_OP_COMPLETE);
+}
+
diff --git a/libmincrypt/tools/Android.mk b/trusty/trusty-base.mk
similarity index 61%
copy from libmincrypt/tools/Android.mk
copy to trusty/trusty-base.mk
index 3154914..9c3a7df 100644
--- a/libmincrypt/tools/Android.mk
+++ b/trusty/trusty-base.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2008 The Android Open Source Project
+#
+# Copyright (C) 2016 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.
@@ -11,12 +12,17 @@
# 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.
+#
-LOCAL_PATH := $(call my-dir)
+#
+# This makefile should be included by devices that use Trusty TEE
+# to pull in the baseline set of Trusty specific modules.
+#
-include $(CLEAR_VARS)
-LOCAL_MODULE := dumpkey
-LOCAL_SRC_FILES := DumpPublicKey.java
-LOCAL_JAR_MANIFEST := DumpPublicKey.mf
-LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-host
-include $(BUILD_HOST_JAVA_LIBRARY)
+PRODUCT_PACKAGES += \
+ keystore.trusty \
+ gatekeeper.trusty
+
+PRODUCT_PROPERTY_OVERRIDES += \
+ ro.hardware.keystore=trusty \
+ ro.hardware.gatekeeper=trusty
diff --git a/adf/Android.mk b/trusty/trusty-storage.mk
similarity index 80%
rename from adf/Android.mk
rename to trusty/trusty-storage.mk
index 64d486e..3f26316 100644
--- a/adf/Android.mk
+++ b/trusty/trusty-storage.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2013 The Android Open Source Project
+# Copyright (C) 2015 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.
@@ -13,6 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-LOCAL_PATH := $(my-dir)
-include $(call first-makefiles-under,$(LOCAL_PATH))
+PRODUCT_PACKAGES += \
+ storageproxyd \
diff --git a/tzdatacheck/Android.bp b/tzdatacheck/Android.bp
new file mode 100644
index 0000000..00ad141
--- /dev/null
+++ b/tzdatacheck/Android.bp
@@ -0,0 +1,14 @@
+// ========================================================
+// Executable
+// ========================================================
+cc_binary {
+ name: "tzdatacheck",
+ host_supported: true,
+ srcs: ["tzdatacheck.cpp"],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ ],
+ cflags: ["-Werror"],
+}
diff --git a/tzdatacheck/Android.mk b/tzdatacheck/Android.mk
deleted file mode 100644
index 0e25f7d..0000000
--- a/tzdatacheck/Android.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-# ========================================================
-# Executable
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= tzdatacheck.cpp
-LOCAL_MODULE := tzdatacheck
-LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
-LOCAL_CFLAGS := -Werror
-include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= tzdatacheck.cpp
-LOCAL_MODULE := tzdatacheck
-LOCAL_SHARED_LIBRARIES := libbase libcutils liblog
-LOCAL_CFLAGS := -Werror
-include $(BUILD_HOST_EXECUTABLE)
-