resolve merge conflicts of 557749e55b to klp-modular-dev DO NOT MERGE am: bdfb431467 -s ours am: 1eb6ec56c2
am: 9cde309103 -s ours
* commit '9cde3091033bc367690aa65b814650cdc0e284fe':
Don't create tombstone directory. DO NOT MERGE
diff --git a/adb/Android.mk b/adb/Android.mk
index af7d7e5..b70c153 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -111,6 +111,7 @@
jdwp_service.c \
framebuffer_service.c \
remount_service.c \
+ disable_verity_service.c \
usb_linux_client.c
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror
@@ -120,13 +121,25 @@
LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
endif
+ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
+endif
+
LOCAL_MODULE := adbd
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include
-LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux
+LOCAL_STATIC_LIBRARIES := liblog \
+ libfs_mgr \
+ libcutils \
+ libc \
+ libmincrypt \
+ libselinux \
+ libext4_utils_static
+
include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.h b/adb/adb.h
index 4f06800..44e5981 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -329,6 +329,7 @@
#if !ADB_HOST
void framebuffer_service(int fd, void *cookie);
void remount_service(int fd, void *cookie);
+void disable_verity_service(int fd, void* cookie);
#endif
/* packet allocator */
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index b24c674..54dd537 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -18,6 +18,7 @@
#define __ADB_AUTH_H
void adb_auth_init(void);
+int adb_auth_keygen(const char* filename);
void adb_auth_verified(atransport *t);
void send_auth_request(atransport *t);
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c
index 783774a..dd83900 100644
--- a/adb/adb_auth_host.c
+++ b/adb/adb_auth_host.c
@@ -15,9 +15,12 @@
*/
#include <stdio.h>
+#include <stdlib.h>
#ifdef _WIN32
-# define WIN32_LEAN_AND_MEAN
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
# include "windows.h"
# include "shlobj.h"
#else
@@ -110,18 +113,34 @@
static void get_user_info(char *buf, size_t len)
{
char hostname[1024], username[1024];
- int ret;
+ int ret = -1;
+
+ if (getenv("HOSTNAME") != NULL) {
+ strncpy(hostname, getenv("HOSTNAME"), sizeof(hostname));
+ hostname[sizeof(hostname)-1] = '\0';
+ ret = 0;
+ }
#ifndef _WIN32
- ret = gethostname(hostname, sizeof(hostname));
if (ret < 0)
+ ret = gethostname(hostname, sizeof(hostname));
#endif
+ if (ret < 0)
strcpy(hostname, "unknown");
+ ret = -1;
+
+ if (getenv("LOGNAME") != NULL) {
+ strncpy(username, getenv("LOGNAME"), sizeof(username));
+ username[sizeof(username)-1] = '\0';
+ ret = 0;
+ }
+
#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
- ret = getlogin_r(username, sizeof(username));
if (ret < 0)
+ ret = getlogin_r(username, sizeof(username));
#endif
+ if (ret < 0)
strcpy(username, "unknown");
ret = snprintf(buf, len, " %s@%s", username, hostname);
@@ -408,6 +427,11 @@
return ret + 1;
}
+int adb_auth_keygen(const char* filename) {
+ adb_trace_mask |= (1 << TRACE_AUTH);
+ return (generate_key(filename) == 0);
+}
+
void adb_auth_init(void)
{
int ret;
diff --git a/adb/commandline.c b/adb/commandline.c
index 05b4ef6..7704878 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -36,6 +36,7 @@
#define TRACE_TAG TRACE_ADB
#include "adb.h"
#include "adb_client.h"
+#include "adb_auth.h"
#include "file_sync_service.h"
static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
@@ -189,6 +190,10 @@
"\n"
" adb restore <file> - restore device contents from the <file> backup archive\n"
"\n"
+ " adb disable-verity - disable dm-verity checking on USERDEBUG builds\n"
+ " adb keygen <file> - generate adb public/private key. The private key is stored in <file>,\n"
+ " and the public key is stored in <file>.pub. Any existing files\n"
+ " are overwritten.\n"
" adb help - show this help message\n"
" adb version - show version num\n"
"\n"
@@ -205,8 +210,7 @@
" adb reboot-bootloader - reboots the device into the bootloader\n"
" adb root - restarts the adbd daemon with root permissions\n"
" adb usb - restarts the adbd daemon listening on USB\n"
- " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port"
- "\n"
+ " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port\n"
"networking:\n"
" adb ppp <tty> [parameters] - Run PPP over USB.\n"
" Note: you should not automatically start a PPP connection.\n"
@@ -1437,7 +1441,7 @@
if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
|| !strcmp(argv[0], "reboot-bootloader")
|| !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
- || !strcmp(argv[0], "root")) {
+ || !strcmp(argv[0], "root") || !strcmp(argv[0], "disable-verity")) {
char command[100];
if (!strcmp(argv[0], "reboot-bootloader"))
snprintf(command, sizeof(command), "reboot:bootloader");
@@ -1720,6 +1724,11 @@
return restore(argc, argv);
}
+ if (!strcmp(argv[0], "keygen")) {
+ if (argc < 2) return usage();
+ return adb_auth_keygen(argv[1]);
+ }
+
if (!strcmp(argv[0], "jdwp")) {
int fd = adb_connect("jdwp");
if (fd >= 0) {
diff --git a/adb/disable_verity_service.c b/adb/disable_verity_service.c
new file mode 100644
index 0000000..ed3da52
--- /dev/null
+++ b/adb/disable_verity_service.c
@@ -0,0 +1,199 @@
+/*
+ * 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 "sysdeps.h"
+
+#define TRACE_TAG TRACE_ADB
+#include "adb.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "cutils/properties.h"
+#include "ext4_sb.h"
+#include <fs_mgr.h>
+
+#define FSTAB_PREFIX "/fstab."
+struct fstab *fstab;
+
+__attribute__((__format__(printf, 2, 3))) __nonnull((2))
+static void write_console(int fd, const char* format, ...)
+{
+ char buffer[256];
+ va_list args;
+ va_start (args, format);
+ vsnprintf (buffer, sizeof(buffer), format, args);
+ va_end (args);
+
+ adb_write(fd, buffer, strnlen(buffer, sizeof(buffer)));
+}
+
+static int get_target_device_size(int fd, const char *blk_device,
+ uint64_t *device_size)
+{
+ int data_device;
+ struct ext4_super_block sb;
+ struct fs_info info;
+
+ info.len = 0; /* Only len is set to 0 to ask the device for real size. */
+
+ data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC);
+ if (data_device < 0) {
+ write_console(fd, "Error opening block device (%s)\n", strerror(errno));
+ return -1;
+ }
+
+ if (lseek64(data_device, 1024, SEEK_SET) < 0) {
+ write_console(fd, "Error seeking to superblock\n");
+ adb_close(data_device);
+ return -1;
+ }
+
+ if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
+ write_console(fd, "Error reading superblock\n");
+ adb_close(data_device);
+ return -1;
+ }
+
+ ext4_parse_sb(&sb, &info);
+ *device_size = info.len;
+
+ adb_close(data_device);
+ return 0;
+}
+
+static int disable_verity(int fd, const char *block_device,
+ const char* mount_point)
+{
+ uint32_t magic_number;
+ const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE;
+ uint64_t device_length;
+ int device;
+ int retval = -1;
+
+ device = adb_open(block_device, O_RDWR | O_CLOEXEC);
+ if (device == -1) {
+ write_console(fd, "Could not open block device %s (%s).\n",
+ block_device, strerror(errno));
+ write_console(fd, "Maybe run adb remount?\n");
+ goto errout;
+ }
+
+ // find the start of the verity metadata
+ if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) {
+ write_console(fd, "Could not get target device size.\n");
+ goto errout;
+ }
+
+ if (lseek64(device, device_length, SEEK_SET) < 0) {
+ write_console(fd,
+ "Could not seek to start of verity metadata block.\n");
+ goto errout;
+ }
+
+ // check the magic number
+ if (adb_read(device, &magic_number, sizeof(magic_number))
+ != sizeof(magic_number)) {
+ write_console(fd, "Couldn't read magic number!\n");
+ goto errout;
+ }
+
+ if (magic_number == VERITY_METADATA_MAGIC_DISABLE) {
+ write_console(fd, "Verity already disabled on %s\n", mount_point);
+ goto errout;
+ }
+
+ if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
+ write_console(fd,
+ "Couldn't find verity metadata at offset %"PRIu64"!\n",
+ device_length);
+ goto errout;
+ }
+
+ if (lseek64(device, device_length, SEEK_SET) < 0) {
+ write_console(fd,
+ "Could not seek to start of verity metadata block.\n");
+ goto errout;
+ }
+
+ if (adb_write(device, &voff, sizeof(voff)) != sizeof(voff)) {
+ write_console(fd, "Could not set verity disabled flag on device %s\n",
+ block_device);
+ goto errout;
+ }
+
+ write_console(fd, "Verity disabled on %s\n", mount_point);
+ retval = 0;
+errout:
+ if (device != -1)
+ adb_close(device);
+ return retval;
+}
+
+void disable_verity_service(int fd, void* cookie)
+{
+#ifdef ALLOW_ADBD_DISABLE_VERITY
+ char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+ char propbuf[PROPERTY_VALUE_MAX];
+ int i;
+ bool any_disabled = false;
+
+ property_get("ro.secure", propbuf, "0");
+ if (strcmp(propbuf, "1")) {
+ write_console(fd, "verity not enabled - ENG build\n");
+ goto errout;
+ }
+
+ property_get("ro.debuggable", propbuf, "0");
+ if (strcmp(propbuf, "1")) {
+ write_console(fd, "verity cannot be disabled - USER build\n");
+ goto errout;
+ }
+
+ property_get("ro.hardware", propbuf, "");
+ snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
+
+ fstab = fs_mgr_read_fstab(fstab_filename);
+ if (!fstab) {
+ write_console(fd, "Failed to open %s\nMaybe run adb root?\n",
+ fstab_filename);
+ goto errout;
+ }
+
+ /* Loop through entries looking for ones that vold manages */
+ for (i = 0; i < fstab->num_entries; i++) {
+ if(fs_mgr_is_verified(&fstab->recs[i])) {
+ if (!disable_verity(fd, fstab->recs[i].blk_device,
+ fstab->recs[i].mount_point)) {
+ any_disabled = true;
+ }
+ }
+ }
+
+ if (any_disabled) {
+ write_console(fd,
+ "Now reboot your device for settings to take effect\n");
+ }
+#else
+ write_console(fd, "disable-verity only works for userdebug builds\n");
+#endif
+
+errout:
+ adb_close(fd);
+}
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c
index 5b95d15..ff1396c 100644
--- a/adb/get_my_path_darwin.c
+++ b/adb/get_my_path_darwin.c
@@ -19,12 +19,12 @@
void get_my_path(char *s, size_t maxLen)
{
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, maxLen, kCFStringEncodingUTF8);
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+ CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
+ CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
+ CFRelease(executableURL);
+
+ CFStringGetFileSystemRepresentation(executablePathString, s, maxLen);
+ CFRelease(executablePathString);
}
diff --git a/adb/remount_service.c b/adb/remount_service.c
index 72d15a1..36367a7 100644
--- a/adb/remount_service.c
+++ b/adb/remount_service.c
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "sysdeps.h"
+
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -22,7 +24,7 @@
#include <sys/mount.h>
#include <unistd.h>
-#include "sysdeps.h"
+#include "cutils/properties.h"
#define TRACE_TAG TRACE_ADB
#include "adb.h"
@@ -115,6 +117,36 @@
void remount_service(int fd, void *cookie)
{
char buffer[200];
+ char prop_buf[PROPERTY_VALUE_MAX];
+
+ bool system_verified = false, vendor_verified = false;
+ property_get("partition.system.verified", prop_buf, "0");
+ if (!strcmp(prop_buf, "1")) {
+ system_verified = true;
+ }
+
+ property_get("partition.vendor.verified", prop_buf, "0");
+ if (!strcmp(prop_buf, "1")) {
+ vendor_verified = true;
+ }
+
+ if (system_verified || vendor_verified) {
+ // Allow remount but warn of likely bad effects
+ bool both = system_verified && vendor_verified;
+ snprintf(buffer, sizeof(buffer),
+ "dm_verity is enabled on the %s%s%s partition%s.\n",
+ system_verified ? "system" : "",
+ both ? " and " : "",
+ vendor_verified ? "vendor" : "",
+ both ? "s" : "");
+ write_string(fd, buffer);
+ snprintf(buffer, sizeof(buffer),
+ "Use \"adb disable-verity\" to disable verity.\n"
+ "If you do not, remount may succeed, however, you will still "
+ "not be able to write to these volumes.\n");
+ write_string(fd, buffer);
+ }
+
if (remount("/system", &system_ro)) {
snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
write_string(fd, buffer);
diff --git a/adb/services.c b/adb/services.c
index e61371a..21b08dc 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -469,6 +469,8 @@
free(cookie);
}
}
+ } else if(!strncmp(name, "disable-verity:", 15)) {
+ ret = create_service_thread(disable_verity_service, NULL);
#endif
}
if (ret >= 0) {
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c
index b082c6d..e69ec2b 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.c
@@ -2,6 +2,7 @@
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
+#include <stdlib.h>
#include <errno.h>
#define TRACE_TAG TRACE_SYSDEPS
#include "adb.h"
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 957e5db..19bcae4 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -17,9 +17,12 @@
#include "usb_vendors.h"
#include <stdio.h>
+#include <stdlib.h>
#ifdef _WIN32
-# define WIN32_LEAN_AND_MEAN
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
# include "windows.h"
# include "shlobj.h"
#else
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index b7ad913..a2d7226 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -21,6 +21,7 @@
#include <usb100.h>
#include <adb_api.h>
#include <stdio.h>
+#include <stdlib.h>
#include "sysdeps.h"
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index e49ef9b..c2a1dbc 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -88,7 +88,9 @@
return;
}
- wait_for_stop(tid, total_sleep_time_usec);
+ if (!attached && wait_for_sigstop(tid, total_sleep_time_usec, detach_failed) == -1) {
+ return;
+ }
UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
if (backtrace->Unwind(0)) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index 61805c9..06c16f8 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -77,7 +77,7 @@
"*\n"
"* Wait for gdb to start, then press the VOLUME DOWN key\n"
"* to let the process continue crashing.\n"
- "********************************************************\n",
+ "********************************************************",
request.pid, exe, request.tid);
// Wait for VOLUME DOWN.
@@ -129,11 +129,11 @@
socklen_t len = sizeof(cr);
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (status != 0) {
- ALOGE("cannot get credentials\n");
+ ALOGE("cannot get credentials");
return -1;
}
- ALOGV("reading tid\n");
+ ALOGV("reading tid");
fcntl(fd, F_SETFL, O_NONBLOCK);
pollfd pollfds[1];
@@ -227,6 +227,7 @@
ALOGE("ptrace attach failed: %s\n", strerror(errno));
} else {
bool detach_failed = false;
+ bool tid_unresponsive = false;
bool attach_gdb = should_attach_gdb(&request);
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
ALOGE("failed responding to client: %s\n", strerror(errno));
@@ -240,8 +241,9 @@
int total_sleep_time_usec = 0;
for (;;) {
- int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
- if (signal < 0) {
+ int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed);
+ if (signal == -1) {
+ tid_unresponsive = true;
break;
}
@@ -308,27 +310,21 @@
free(tombstone_path);
}
- ALOGV("detaching\n");
- if (attach_gdb) {
- // stop the process so we can debug
- kill(request.pid, SIGSTOP);
-
- // detach so we can attach gdbserver
- if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
- detach_failed = true;
+ if (!tid_unresponsive) {
+ ALOGV("detaching");
+ if (attach_gdb) {
+ // stop the process so we can debug
+ kill(request.pid, SIGSTOP);
}
-
- // if debug.db.uid is set, its value indicates if we should wait
- // for user action for the crashing process.
- // in this case, we log a message and turn the debug LED on
- // waiting for a gdb connection (for instance)
- wait_for_user_action(request);
- } else {
- // just detach
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno));
+ ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno));
detach_failed = true;
+ } else if (attach_gdb) {
+ // if debug.db.uid is set, its value indicates if we should wait
+ // for user action for the crashing process.
+ // in this case, we log a message and turn the debug LED on
+ // waiting for a gdb connection (for instance)
+ wait_for_user_action(request);
}
}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 8bf3a50..46f453b 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -374,11 +374,7 @@
}
}
-static void dump_thread(
- Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) {
-
- wait_for_stop(backtrace->Tid(), total_sleep_time_usec);
-
+static void dump_thread(Backtrace* backtrace, log_t* log) {
dump_registers(log, backtrace->Tid());
dump_backtrace_and_stack(backtrace, log);
@@ -421,13 +417,17 @@
continue;
}
+ if (wait_for_sigstop(new_tid, total_sleep_time_usec, &detach_failed) == -1) {
+ continue;
+ }
+
log->current_tid = new_tid;
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
dump_thread_info(log, pid, new_tid);
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
if (backtrace->Unwind(0)) {
- dump_thread(backtrace.get(), log, total_sleep_time_usec);
+ dump_thread(backtrace.get(), log);
}
log->current_tid = log->crashed_tid;
@@ -628,7 +628,7 @@
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
if (backtrace->Unwind(0)) {
dump_abort_message(backtrace.get(), log, abort_msg_address);
- dump_thread(backtrace.get(), log, total_sleep_time_usec);
+ dump_thread(backtrace.get(), log);
}
if (want_logs) {
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index 9a30fe3..2baf9de 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -28,8 +28,8 @@
#include <backtrace/Backtrace.h>
#include <log/log.h>
-const int sleep_time_usec = 50000; // 0.05 seconds
-const int max_total_sleep_usec = 10000000; // 10 seconds
+const int SLEEP_TIME_USEC = 50000; // 0.05 seconds
+const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
static int write_to_am(int fd, const char* buf, int len) {
int to_write = len;
@@ -91,48 +91,44 @@
}
}
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
+int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed) {
+ bool allow_dead_tid = false;
for (;;) {
int status;
- pid_t n = waitpid(tid, &status, __WALL | WNOHANG);
- if (n < 0) {
- if (errno == EAGAIN)
- continue;
- ALOGE("waitpid failed: %s\n", strerror(errno));
- return -1;
- } else if (n > 0) {
- ALOGV("waitpid: n=%d status=%08x\n", n, status);
+ pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
+ if (n == -1) {
+ ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
+ break;
+ } else if (n == tid) {
if (WIFSTOPPED(status)) {
return WSTOPSIG(status);
} else {
ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
- return -1;
+ // This is the only circumstance under which we can allow a detach
+ // to fail with ESRCH, which indicates the tid has exited.
+ allow_dead_tid = true;
+ break;
}
}
- if (*total_sleep_time_usec > max_total_sleep_usec) {
- ALOGE("timed out waiting for tid=%d to die\n", tid);
- return -1;
- }
-
- // not ready yet
- ALOGV("not ready yet\n");
- usleep(sleep_time_usec);
- *total_sleep_time_usec += sleep_time_usec;
- }
-}
-
-void wait_for_stop(pid_t tid, int* total_sleep_time_usec) {
- siginfo_t si;
- while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) {
- if (*total_sleep_time_usec > max_total_sleep_usec) {
- ALOGE("timed out waiting for tid=%d to stop\n", tid);
+ if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
+ ALOGE("timed out waiting for stop signal: tid=%d", tid);
break;
}
- usleep(sleep_time_usec);
- *total_sleep_time_usec += sleep_time_usec;
+ usleep(SLEEP_TIME_USEC);
+ *total_sleep_time_usec += SLEEP_TIME_USEC;
}
+
+ if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
+ if (allow_dead_tid && errno == ESRCH) {
+ ALOGE("tid exited before attach completed: tid %d", tid);
+ } else {
+ *detach_failed = true;
+ ALOGE("detach failed: tid %d, %s", tid, strerror(errno));
+ }
+ }
+ return -1;
}
#if defined (__mips__)
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index 82413b8..58a882c 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -67,12 +67,11 @@
LOGS
};
-/* Log information onto the tombstone. */
+// Log information onto the tombstone.
void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
-int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
-void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
+int wait_for_sigstop(pid_t, int*, bool*);
void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c
index 0d13863..a09610f 100644
--- a/fastboot/usb_windows.c
+++ b/fastboot/usb_windows.c
@@ -32,6 +32,7 @@
#include <usb100.h>
#include <adb_api.h>
#include <stdio.h>
+#include <stdlib.h>
#include "usb.h"
diff --git a/fastboot/util_osx.c b/fastboot/util_osx.c
index 26b832a..e718562 100644
--- a/fastboot/util_osx.c
+++ b/fastboot/util_osx.c
@@ -31,14 +31,15 @@
void get_my_path(char s[PATH_MAX])
{
- char *x;
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- CFDictionaryRef dict;
- dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
- CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict,
- CFSTR("CFBundleExecutable"));
- CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8);
+ CFBundleRef mainBundle = CFBundleGetMainBundle();
+ CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle);
+ CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle);
+ CFRelease(executableURL);
+
+ CFStringGetFileSystemRepresentation(executablePathString, s, PATH_MAX-1);
+ CFRelease(executablePathString);
+
+ char *x;
x = strrchr(s, '/');
if(x) x[1] = 0;
}
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk
index 7cffc37..0ec6c4b 100644
--- a/fs_mgr/Android.mk
+++ b/fs_mgr/Android.mk
@@ -4,8 +4,12 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c
+LOCAL_SRC_FILES += fs_mgr_format.c
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \
+ system/vold \
+ system/extras/ext4_utils \
+ external/openssl/include
LOCAL_MODULE:= libfs_mgr
LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static
@@ -13,6 +17,10 @@
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Werror
+ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT)))
+LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
+endif
+
include $(BUILD_STATIC_LIBRARY)
@@ -31,6 +39,7 @@
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static
+LOCAL_STATIC_LIBRARIES += libsparse_static libz libselinux
LOCAL_CFLAGS := -Werror
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 91e6c33..8533ff6 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -40,6 +40,9 @@
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"
+#include "ext4_utils.h"
+#include "wipe.h"
+
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_verity.h"
@@ -141,9 +144,10 @@
} else if (!strcmp(fs_type, "f2fs")) {
char *f2fs_fsck_argv[] = {
F2FS_FSCK_BIN,
+ "-f",
blk_device
};
- INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
+ INFO("Running %s -f %s\n", F2FS_FSCK_BIN, blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
&status, true, LOG_KLOG | LOG_FILE,
@@ -245,6 +249,25 @@
return strcmp(value, "1") ? 0 : 1;
}
+static int device_is_secure() {
+ int ret = -1;
+ char value[PROP_VALUE_MAX];
+ ret = __system_property_get("ro.secure", value);
+ /* If error, we want to fail secure */
+ if (ret < 0)
+ return 1;
+ return strcmp(value, "0") ? 1 : 0;
+}
+
+static int device_is_force_encrypted() {
+ int ret = -1;
+ char value[PROP_VALUE_MAX];
+ ret = __system_property_get("ro.vold.forceencryption", value);
+ if (ret < 0)
+ return 0;
+ return strcmp(value, "1") ? 0 : 1;
+}
+
/*
* Tries to mount any of the consecutive fstab entries that match
* the mountpoint of the one given by fstab->recs[start_idx].
@@ -350,14 +373,18 @@
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
}
- if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
- !device_is_debuggable()) {
- if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
+ if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ int rc = fs_mgr_setup_verity(&fstab->recs[i]);
+ if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+ INFO("Verity disabled");
+ } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
ERROR("Could not set up verified partition, skipping!\n");
continue;
}
}
int last_idx_inspected;
+ int top_idx = i;
+
mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
i = last_idx_inspected;
mount_errno = errno;
@@ -365,7 +392,9 @@
/* Deal with encryptability. */
if (!mret) {
/* If this is encryptable, need to trigger encryption */
- if ((fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)) {
+ if ( (fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)
+ || (device_is_force_encrypted()
+ && fs_mgr_is_encryptable(&fstab->recs[attempted_idx]))) {
if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
@@ -385,10 +414,38 @@
continue;
}
- /* mount(2) returned an error, check if it's encryptable and deal with it */
+ /* mount(2) returned an error, handle the encryptable/formattable case */
+ bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
+ 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
+ * at two different lines in the fstab. Use the top one for formatting
+ * as that is the preferred one.
+ */
+ ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__,
+ fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point,
+ 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);
+ if (fd >= 0) {
+ INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc);
+ wipe_block_device(fd, get_file_size(fd));
+ close(fd);
+ } else {
+ ERROR("%s(): %s wouldn't open (%s)\n", __func__,
+ fstab->recs[top_idx].key_loc, strerror(errno));
+ }
+ }
+ if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) {
+ /* Let's replay the mount actions. */
+ i = top_idx - 1;
+ continue;
+ }
+ }
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
- if(partition_wiped(fstab->recs[attempted_idx].blk_device)) {
+ if (wiped) {
ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
fstab->recs[attempted_idx].fs_type);
@@ -467,9 +524,11 @@
fstab->recs[i].mount_point);
}
- if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
- !device_is_debuggable()) {
- if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
+ if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {
+ int rc = fs_mgr_setup_verity(&fstab->recs[i]);
+ if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
+ INFO("Verity disabled");
+ } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
ERROR("Could not set up verified partition, skipping!\n");
continue;
}
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
new file mode 100644
index 0000000..b5b92b5
--- /dev/null
+++ b/fs_mgr/fs_mgr_format.c
@@ -0,0 +1,119 @@
+/*
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <cutils/partition_utils.h>
+#include <sys/mount.h>
+#include "ext4_utils.h"
+#include "ext4.h"
+#include "make_ext4fs.h"
+#include "fs_mgr_priv.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)
+{
+ unsigned int nr_sec;
+ int fd, rc = 0;
+
+ if ((fd = open(fs_blkdev, O_WRONLY, 0644)) < 0) {
+ ERROR("Cannot open block device. %s\n", strerror(errno));
+ return -1;
+ }
+
+ if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) {
+ ERROR("Cannot get block device size. %s\n", strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ /* Format the partition using the calculated length */
+ reset_ext4fs_info();
+ info.len = ((off64_t)nr_sec * 512);
+
+ /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
+ rc = make_ext4fs_internal(fd, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
+ if (rc) {
+ ERROR("make_ext4fs returned %d.\n", rc);
+ }
+ close(fd);
+
+ return rc;
+}
+
+static int format_f2fs(char *fs_blkdev)
+{
+ char * args[3];
+ int pid;
+ int rc = 0;
+
+ args[0] = (char *)"/sbin/mkfs.f2fs";
+ args[1] = fs_blkdev;
+ args[2] = (char *)0;
+
+ pid = fork();
+ if (pid < 0) {
+ return pid;
+ }
+ if (!pid) {
+ /* This doesn't return */
+ execv("/sbin/mkfs.f2fs", args);
+ exit(1);
+ }
+ for(;;) {
+ pid_t p = waitpid(pid, &rc, 0);
+ if (p != pid) {
+ ERROR("Error waiting for child process - %d\n", p);
+ rc = -1;
+ break;
+ }
+ if (WIFEXITED(rc)) {
+ rc = WEXITSTATUS(rc);
+ INFO("%s done, status %d\n", args[0], rc);
+ if (rc) {
+ rc = -1;
+ }
+ break;
+ }
+ ERROR("Still waiting for %s...\n", args[0]);
+ }
+
+ return rc;
+}
+
+int fs_mgr_do_format(struct fstab_rec *fstab)
+{
+ int rc = -EINVAL;
+
+ ERROR("%s: Format %s as '%s'.\n", __func__, fstab->blk_device, fstab->fs_type);
+
+ 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);
+ } else {
+ ERROR("File system type '%s' is not supported\n", fstab->fs_type);
+ }
+
+ return rc;
+}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 3f84179..c2da28a 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -15,10 +15,12 @@
*/
#include <ctype.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
+#include <unistd.h>
#include "fs_mgr_priv.h"
@@ -68,10 +70,24 @@
{ "zramsize=", MF_ZRAMSIZE },
{ "verify", MF_VERIFY },
{ "noemulatedsd", MF_NOEMULATEDSD },
+ { "formattable", MF_FORMATTABLE },
{ "defaults", 0 },
{ 0, 0 },
};
+static uint64_t calculate_zram_size(unsigned int percentage)
+{
+ uint64_t total;
+
+ total = sysconf(_SC_PHYS_PAGES);
+ total *= percentage;
+ total /= 100;
+
+ total *= sysconf(_SC_PAGESIZE);
+
+ return total;
+}
+
static int parse_flags(char *flags, struct flag_list *fl,
struct fs_mgr_flag_values *flag_vals,
char *fs_options, int fs_options_len)
@@ -145,7 +161,12 @@
} else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
} else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
- flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0);
+ int is_percent = !!strrchr(p, '%');
+ unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
+ if (is_percent)
+ flag_vals->zram_size = calculate_zram_size(val);
+ else
+ flag_vals->zram_size = val;
}
break;
}
@@ -418,6 +439,11 @@
return fstab->fs_mgr_flags & MF_NONREMOVABLE;
}
+int fs_mgr_is_verified(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_VERIFY;
+}
+
int fs_mgr_is_encryptable(struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
@@ -427,3 +453,8 @@
{
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
}
+
+int fs_mgr_is_formattable(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & (MF_FORMATTABLE);
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index 34938fa..fd58306 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -75,6 +75,7 @@
#define MF_FORCECRYPT 0x400
#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
external storage */
+#define MF_FORMATTABLE 0x1000
#define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h
index 6193784..f90e596 100644
--- a/fs_mgr/fs_mgr_priv_verity.h
+++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -14,4 +14,7 @@
* limitations under the License.
*/
-int fs_mgr_setup_verity(struct fstab_rec *fstab);
\ No newline at end of file
+#define FS_MGR_SETUP_VERITY_DISABLED -2
+#define FS_MGR_SETUP_VERITY_FAIL -1
+#define FS_MGR_SETUP_VERITY_SUCCESS 0
+int fs_mgr_setup_verity(struct fstab_rec *fstab);
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index b79a4a8..a82db4e 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -43,7 +43,6 @@
#include "fs_mgr_priv_verity.h"
#define VERITY_METADATA_SIZE 32768
-#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
#define VERITY_TABLE_RSA_KEY "/verity_key"
extern struct fs_info info;
@@ -87,11 +86,11 @@
static int verify_table(char *signature, char *table, int table_length)
{
RSAPublicKey *key;
- uint8_t hash_buf[SHA_DIGEST_SIZE];
+ uint8_t hash_buf[SHA256_DIGEST_SIZE];
int retval = -1;
// Hash the table
- SHA_hash((uint8_t*)table, table_length, hash_buf);
+ SHA256_hash((uint8_t*)table, table_length, hash_buf);
// Now get the public key from the keyfile
key = load_key(VERITY_TABLE_RSA_KEY);
@@ -105,7 +104,7 @@
(uint8_t*) signature,
RSANUMBYTES,
(uint8_t*) hash_buf,
- SHA_DIGEST_SIZE)) {
+ SHA256_DIGEST_SIZE)) {
ERROR("Couldn't verify table.");
goto out;
}
@@ -123,28 +122,28 @@
struct ext4_super_block sb;
struct fs_info info = {0};
- data_device = open(blk_device, O_RDONLY);
- if (data_device < 0) {
+ data_device = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
+ if (data_device == -1) {
ERROR("Error opening block device (%s)", strerror(errno));
return -1;
}
- if (lseek64(data_device, 1024, SEEK_SET) < 0) {
+ if (TEMP_FAILURE_RETRY(lseek64(data_device, 1024, SEEK_SET)) < 0) {
ERROR("Error seeking to superblock");
- close(data_device);
+ TEMP_FAILURE_RETRY(close(data_device));
return -1;
}
- if (read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
+ if (TEMP_FAILURE_RETRY(read(data_device, &sb, sizeof(sb))) != sizeof(sb)) {
ERROR("Error reading superblock");
- close(data_device);
+ TEMP_FAILURE_RETRY(close(data_device));
return -1;
}
ext4_parse_sb(&sb, &info);
*device_size = info.len;
- close(data_device);
+ TEMP_FAILURE_RETRY(close(data_device));
return 0;
}
@@ -154,11 +153,13 @@
unsigned table_length;
uint64_t device_length;
int protocol_version;
- FILE *device;
- int retval = -1;
+ int device;
+ int retval = FS_MGR_SETUP_VERITY_FAIL;
+ *signature = 0;
+ *table = 0;
- device = fopen(block_device, "r");
- if (!device) {
+ device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC));
+ if (device == -1) {
ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno));
goto out;
}
@@ -168,23 +169,35 @@
ERROR("Could not get target device size.\n");
goto out;
}
- if (fseek(device, device_length, SEEK_SET) < 0) {
+ if (TEMP_FAILURE_RETRY(lseek64(device, device_length, SEEK_SET)) < 0) {
ERROR("Could not seek to start of verity metadata block.\n");
goto out;
}
// check the magic number
- if (!fread(&magic_number, sizeof(int), 1, device)) {
+ if (TEMP_FAILURE_RETRY(read(device, &magic_number, sizeof(magic_number))) !=
+ sizeof(magic_number)) {
ERROR("Couldn't read magic number!\n");
goto out;
}
+
+#ifdef ALLOW_ADBD_DISABLE_VERITY
+ if (magic_number == VERITY_METADATA_MAGIC_DISABLE) {
+ retval = FS_MGR_SETUP_VERITY_DISABLED;
+ INFO("Attempt to cleanly disable verity - only works in USERDEBUG");
+ goto out;
+ }
+#endif
+
if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
- ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_length);
+ ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n",
+ device_length);
goto out;
}
// check the protocol version
- if (!fread(&protocol_version, sizeof(int), 1, device)) {
+ if (TEMP_FAILURE_RETRY(read(device, &protocol_version,
+ sizeof(protocol_version))) != sizeof(protocol_version)) {
ERROR("Couldn't read verity metadata protocol version!\n");
goto out;
}
@@ -194,43 +207,49 @@
}
// get the signature
- *signature = (char*) malloc(RSANUMBYTES * sizeof(char));
+ *signature = (char*) malloc(RSANUMBYTES);
if (!*signature) {
ERROR("Couldn't allocate memory for signature!\n");
goto out;
}
- if (!fread(*signature, RSANUMBYTES, 1, device)) {
+ if (TEMP_FAILURE_RETRY(read(device, *signature, RSANUMBYTES)) != RSANUMBYTES) {
ERROR("Couldn't read signature from verity metadata!\n");
- free(*signature);
goto out;
}
// get the size of the table
- if (!fread(&table_length, sizeof(int), 1, device)) {
+ if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) !=
+ sizeof(table_length)) {
ERROR("Couldn't get the size of the verity table from metadata!\n");
- free(*signature);
goto out;
}
// get the table + null terminator
- table_length += 1;
- *table = malloc(table_length);
- if(!*table) {
+ *table = malloc(table_length + 1);
+ if (!*table) {
ERROR("Couldn't allocate memory for verity table!\n");
goto out;
}
- if (!fgets(*table, table_length, device)) {
+ if (TEMP_FAILURE_RETRY(read(device, *table, table_length)) !=
+ (ssize_t)table_length) {
ERROR("Couldn't read the verity table from metadata!\n");
- free(*table);
- free(*signature);
goto out;
}
- retval = 0;
+ (*table)[table_length] = 0;
+ retval = FS_MGR_SETUP_VERITY_SUCCESS;
out:
- if (device)
- fclose(device);
+ if (device != -1)
+ TEMP_FAILURE_RETRY(close(device));
+
+ if (retval != FS_MGR_SETUP_VERITY_SUCCESS) {
+ free(*table);
+ free(*signature);
+ *table = 0;
+ *signature = 0;
+ }
+
return retval;
}
@@ -357,11 +376,12 @@
int fs_mgr_setup_verity(struct fstab_rec *fstab) {
- int retval = -1;
+ int retval = FS_MGR_SETUP_VERITY_FAIL;
+ int fd = -1;
- char *verity_blk_name;
- char *verity_table;
- char *verity_table_signature;
+ char *verity_blk_name = 0;
+ char *verity_table = 0;
+ char *verity_table_signature = 0;
char buffer[DM_BUF_SIZE];
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
@@ -378,11 +398,21 @@
return retval;
}
+ // read the verity block at the end of the block device
+ // send error code up the chain so we can detect attempts to disable verity
+ retval = read_verity_metadata(fstab->blk_device,
+ &verity_table_signature,
+ &verity_table);
+ if (retval < 0) {
+ goto out;
+ }
+
+ retval = FS_MGR_SETUP_VERITY_FAIL;
+
// get the device mapper fd
- int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
ERROR("Error opening device mapper (%s)", strerror(errno));
- return retval;
+ goto out;
}
// create the device
@@ -397,13 +427,6 @@
goto out;
}
- // read the verity block at the end of the block device
- if (read_verity_metadata(fstab->blk_device,
- &verity_table_signature,
- &verity_table) < 0) {
- goto out;
- }
-
// verify the signature on the table
if (verify_table(verity_table_signature,
verity_table,
@@ -424,6 +447,7 @@
// assign the new verity block device as the block device
free(fstab->blk_device);
fstab->blk_device = verity_blk_name;
+ verity_blk_name = 0;
// make sure we've set everything up properly
if (test_access(fstab->blk_device) < 0) {
@@ -434,6 +458,13 @@
retval = set_verified_property(mount_point);
out:
- close(fd);
+ if (fd != -1) {
+ close(fd);
+ }
+
+ free(verity_table);
+ free(verity_table_signature);
+ free(verity_blk_name);
+
return retval;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 0c7eb20..5a6ad2d 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -20,6 +20,13 @@
#include <stdint.h>
#include <linux/dm-ioctl.h>
+// Magic number at start of verity metadata
+#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001
+
+// Replacement magic number at start of verity metadata to cleanly
+// turn verity off in userdebug builds.
+#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF"
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -74,9 +81,14 @@
struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path);
int fs_mgr_is_voldmanaged(struct fstab_rec *fstab);
int fs_mgr_is_nonremovable(struct fstab_rec *fstab);
+int fs_mgr_is_verified(struct fstab_rec *fstab);
int fs_mgr_is_encryptable(struct fstab_rec *fstab);
int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab);
+int fs_mgr_is_formattable(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
+
+int fs_mgr_do_format(struct fstab_rec *fstab);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 4bcc8e6..bae687d 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -64,11 +64,26 @@
*/
int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen);
+/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
+ * Stores the tombstone path in the provided buffer.
+ * If reading debugger data from debuggerd ever takes longer than timeout_secs
+ * seconds, then stop and return an error.
+ * Returns 0 on success, -1 on error.
+ */
+int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs);
+
/* Dumps a process backtrace only to the specified file (requires root).
* Returns 0 on success, -1 on error.
*/
int dump_backtrace_to_file(pid_t tid, int fd);
+/* Dumps a process backtrace only to the specified file (requires root).
+ * If reading debugger data from debuggerd ever takes longer than timeout_secs
+ * seconds, then stop and return an error.
+ * Returns 0 on success, -1 on error.
+ */
+int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs);
+
#ifdef __cplusplus
}
#endif
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h
index ac254e9..523dc49 100644
--- a/include/nativebridge/native_bridge.h
+++ b/include/nativebridge/native_bridge.h
@@ -37,7 +37,7 @@
// Do the early initialization part of the native bridge, if necessary. This should be done under
// high privileges.
-void PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set);
+bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set);
// Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv*
// will be used to modify the app environment for the bridge.
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 5d9c3ea..2f528b9 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -248,7 +248,6 @@
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" },
{ 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" },
- { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/tcpdump" },
{ 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" },
/* the following files have enhanced capabilities and ARE included in user builds. */
diff --git a/include/system/audio.h b/include/system/audio.h
index df454ff..181a171 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -57,10 +57,14 @@
* and must be routed to speaker
*/
AUDIO_STREAM_DTMF = 8,
- AUDIO_STREAM_TTS = 9,
-
- AUDIO_STREAM_CNT,
- AUDIO_STREAM_MAX = AUDIO_STREAM_CNT - 1,
+ AUDIO_STREAM_TTS = 9, /* Transmitted Through Speaker.
+ * Plays over speaker only, silent on other devices.
+ */
+ AUDIO_STREAM_ACCESSIBILITY = 10, /* For accessibility talk back prompts */
+ AUDIO_STREAM_REROUTING = 11, /* For dynamic policy output mixes */
+ AUDIO_STREAM_PATCH = 12, /* For internal audio flinger tracks. Fixed volume */
+ AUDIO_STREAM_PUBLIC_CNT = AUDIO_STREAM_TTS + 1,
+ AUDIO_STREAM_CNT = AUDIO_STREAM_PATCH + 1,
} audio_stream_type_t;
/* Do not change these values without updating their counterparts
@@ -96,6 +100,7 @@
AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12,
AUDIO_USAGE_ASSISTANCE_SONIFICATION = 13,
AUDIO_USAGE_GAME = 14,
+ AUDIO_USAGE_VIRTUAL_SOURCE = 15,
AUDIO_USAGE_CNT,
AUDIO_USAGE_MAX = AUDIO_USAGE_CNT - 1,
diff --git a/init/Android.mk b/init/Android.mk
index 489dc93..228e645 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -45,7 +45,9 @@
libc \
libselinux \
libmincrypt \
- libext4_utils_static
+ libext4_utils_static \
+ libsparse_static \
+ libz
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
diff --git a/init/devices.c b/init/devices.c
index 1012fee..73fe223 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -564,7 +564,7 @@
make_device(devpath, path, block, major, minor, (const char **)links);
if (links) {
for (i = 0; links[i]; i++)
- make_link(devpath, links[i]);
+ make_link_init(devpath, links[i]);
}
}
diff --git a/init/property_service.c b/init/property_service.c
index 1902b77..91ef251 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -540,6 +540,7 @@
{
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL);
+ load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
load_override_properties();
diff --git a/init/util.c b/init/util.c
index 0f69e1c..12cb11d 100644
--- a/init/util.c
+++ b/init/util.c
@@ -329,13 +329,13 @@
if (!s)
return;
- for (; *s; s++) {
+ while (*s) {
s += strspn(s, accept);
- if (*s) *s = '_';
+ if (*s) *s++ = '_';
}
}
-void make_link(const char *oldpath, const char *newpath)
+void make_link_init(const char *oldpath, const char *newpath)
{
int ret;
char buf[256];
diff --git a/init/util.h b/init/util.h
index 04b8129..a7e7c8b 100644
--- a/init/util.h
+++ b/init/util.h
@@ -33,7 +33,7 @@
int mkdir_recursive(const char *pathname, mode_t mode);
void sanitize(char *p);
-void make_link(const char *oldpath, const char *newpath);
+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);
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index c321369..9588dd6 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -64,6 +64,10 @@
libbacktrace_static_libraries_host := \
libcutils \
+libbacktrace_ldlibs_host := \
+ -lpthread \
+ -lrt \
+
module := libbacktrace
module_tag := optional
build_type := target
@@ -105,6 +109,10 @@
libbacktrace_libc++_static_libraries_host := \
libcutils \
+libbacktrace_libc++_ldlibs_host := \
+ -lpthread \
+ -lrt \
+
libbacktrace_libc++_libc++ := true
module := libbacktrace_libc++
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp
index b47cd2a..439cc3b 100644
--- a/libbacktrace/BacktraceThread.cpp
+++ b/libbacktrace/BacktraceThread.cpp
@@ -17,14 +17,15 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
-#include <linux/futex.h>
#include <pthread.h>
#include <signal.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <ucontext.h>
+#include <unistd.h>
#include <cutils/atomic.h>
@@ -32,10 +33,6 @@
#include "BacktraceThread.h"
#include "thread_utils.h"
-static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) {
- return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3);
-}
-
//-------------------------------------------------------------------------
// ThreadEntry implementation.
//-------------------------------------------------------------------------
@@ -45,7 +42,14 @@
// Assumes that ThreadEntry::list_mutex_ has already been locked before
// creating a ThreadEntry object.
ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
- : pid_(pid), tid_(tid), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) {
+ : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER),
+ wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0),
+ next_(ThreadEntry::list_), prev_(NULL) {
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ pthread_cond_init(&wait_cond_, &attr);
+
// Add ourselves to the list.
if (ThreadEntry::list_) {
ThreadEntry::list_->prev_ = this;
@@ -99,22 +103,35 @@
next_ = NULL;
prev_ = NULL;
+
+ pthread_cond_destroy(&wait_cond_);
}
void ThreadEntry::Wait(int value) {
timespec ts;
- ts.tv_sec = 10;
- ts.tv_nsec = 0;
- errno = 0;
- futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0);
- if (errno != 0 && errno != EWOULDBLOCK) {
- BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno));
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) {
+ BACK_LOGW("clock_gettime failed: %s", strerror(errno));
+ abort();
}
+ ts.tv_sec += 10;
+
+ pthread_mutex_lock(&wait_mutex_);
+ while (wait_value_ != value) {
+ int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
+ if (ret != 0) {
+ BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret));
+ break;
+ }
+ }
+ pthread_mutex_unlock(&wait_mutex_);
}
void ThreadEntry::Wake() {
- futex_++;
- futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
+ pthread_mutex_lock(&wait_mutex_);
+ wait_value_++;
+ pthread_mutex_unlock(&wait_mutex_);
+
+ pthread_cond_signal(&wait_cond_);
}
void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
@@ -142,7 +159,7 @@
// Pause the thread until the unwind is complete. This avoids having
// the thread run ahead causing problems.
- entry->Wait(1);
+ entry->Wait(2);
ThreadEntry::Remove(entry);
}
@@ -194,7 +211,7 @@
}
// Wait for the thread to get the ucontext.
- entry->Wait(0);
+ entry->Wait(1);
// After the thread has received the signal, allow other unwinders to
// continue.
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h
index ff3e9f3..99a8638 100644
--- a/libbacktrace/BacktraceThread.h
+++ b/libbacktrace/BacktraceThread.h
@@ -48,8 +48,10 @@
inline void Lock() {
pthread_mutex_lock(&mutex_);
- // Reset the futex value in case of multiple unwinds of the same thread.
- futex_ = 0;
+
+ // Always reset the wait value since this could be the first or nth
+ // time this entry is locked.
+ wait_value_ = 0;
}
inline void Unlock() {
@@ -66,9 +68,11 @@
pid_t pid_;
pid_t tid_;
- int futex_;
int ref_count_;
pthread_mutex_t mutex_;
+ pthread_mutex_t wait_mutex_;
+ pthread_cond_t wait_cond_;
+ int wait_value_;
ThreadEntry* next_;
ThreadEntry* prev_;
ucontext_t ucontext_;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index ed6b211..8002ed6 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -51,7 +51,7 @@
#define NS_PER_SEC 1000000000ULL
// Number of simultaneous dumping operations to perform.
-#define NUM_THREADS 20
+#define NUM_THREADS 40
// Number of simultaneous threads running in our forked process.
#define NUM_PTRACE_THREADS 5
@@ -486,6 +486,13 @@
struct sigaction new_action;
ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0);
EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
+ // The SA_RESTORER flag gets set behind our back, so a direct comparison
+ // doesn't work unless we mask the value off. Mips doesn't have this
+ // flag, so skip this on that platform.
+#ifdef SA_RESTORER
+ cur_action.sa_flags &= ~SA_RESTORER;
+ new_action.sa_flags &= ~SA_RESTORER;
+#endif
EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
}
@@ -583,7 +590,7 @@
// Wait for tids to be set.
for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) {
- ASSERT_TRUE(WaitForNonZero(&it->state, 10));
+ ASSERT_TRUE(WaitForNonZero(&it->state, 30));
}
// Start all of the dumpers at once, they will spin until they are signalled
@@ -602,7 +609,7 @@
android_atomic_acquire_store(1, &dump_now);
for (size_t i = 0; i < NUM_THREADS; i++) {
- ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 10));
+ ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
// Tell the runner thread to exit its infinite loop.
android_atomic_acquire_store(0, &runners[i].state);
@@ -625,7 +632,7 @@
ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0);
// Wait for tids to be set.
- ASSERT_TRUE(WaitForNonZero(&runner.state, 10));
+ ASSERT_TRUE(WaitForNonZero(&runner.state, 30));
// Start all of the dumpers at once, they will spin until they are signalled
// to begin their dump run.
@@ -645,7 +652,7 @@
android_atomic_acquire_store(1, &dump_now);
for (size_t i = 0; i < NUM_THREADS; i++) {
- ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 100));
+ ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
ASSERT_TRUE(dumpers[i].backtrace != NULL);
VerifyMaxDump(dumpers[i].backtrace);
diff --git a/libcutils/debugger.c b/libcutils/debugger.c
index 4035ee1..b8a2efc 100644
--- a/libcutils/debugger.c
+++ b/libcutils/debugger.c
@@ -19,11 +19,16 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#include <unistd.h>
#include <cutils/debugger.h>
#include <cutils/sockets.h>
+#define LOG_TAG "DEBUG"
+#include <log/log.h>
+
#if defined(__LP64__)
#include <elf.h>
@@ -64,7 +69,7 @@
return result;
}
-static int make_dump_request(debugger_action_t action, pid_t tid) {
+static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_secs) {
const char* socket_name;
debugger_msg_t msg;
size_t msg_len;
@@ -98,6 +103,19 @@
return -1;
}
+ if (timeout_secs > 0) {
+ struct timeval tm;
+ tm.tv_sec = timeout_secs;
+ tm.tv_usec = 0;
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)) == -1) {
+ ALOGE("WARNING: Cannot set receive timeout value on socket: %s", strerror(errno));
+ }
+
+ if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm)) == -1) {
+ ALOGE("WARNING: Cannot set send timeout value on socket: %s", strerror(errno));
+ }
+ }
+
if (send_request(sock_fd, msg_ptr, msg_len) < 0) {
TEMP_FAILURE_RETRY(close(sock_fd));
return -1;
@@ -107,7 +125,11 @@
}
int dump_backtrace_to_file(pid_t tid, int fd) {
- int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid);
+ return dump_backtrace_to_file_timeout(tid, fd, 0);
+}
+
+int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) {
+ int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid, timeout_secs);
if (sock_fd < 0) {
return -1;
}
@@ -127,7 +149,11 @@
}
int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) {
- int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid);
+ return dump_tombstone_timeout(tid, pathbuf, pathlen, 0);
+}
+
+int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs) {
+ int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid, timeout_secs);
if (sock_fd < 0) {
return -1;
}
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c
index 2acc3c3..493511e 100644
--- a/libcutils/sched_policy.c
+++ b/libcutils/sched_policy.c
@@ -45,8 +45,6 @@
#define POLICY_DEBUG 0
-#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
-
// This prctl is only available in Android kernels.
#define PR_SET_TIMERSLACK_PID 41
@@ -60,9 +58,6 @@
// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
static int bg_cgroup_fd = -1;
static int fg_cgroup_fd = -1;
-#if CAN_SET_SP_SYSTEM
-static int system_cgroup_fd = -1;
-#endif
/* Add tid to the scheduling group defined by the policy */
static int add_tid_to_cgroup(int tid, SchedPolicy policy)
@@ -78,11 +73,6 @@
case SP_AUDIO_SYS:
fd = fg_cgroup_fd;
break;
-#if CAN_SET_SP_SYSTEM
- case SP_SYSTEM:
- fd = system_cgroup_fd;
- break;
-#endif
default:
fd = -1;
break;
@@ -123,21 +113,13 @@
if (!access("/dev/cpuctl/tasks", F_OK)) {
__sys_supports_schedgroups = 1;
-#if CAN_SET_SP_SYSTEM
filename = "/dev/cpuctl/tasks";
- system_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
- if (system_cgroup_fd < 0) {
- SLOGV("open of %s failed: %s\n", filename, strerror(errno));
- }
-#endif
-
- filename = "/dev/cpuctl/apps/tasks";
fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
if (fg_cgroup_fd < 0) {
SLOGE("open of %s failed: %s\n", filename, strerror(errno));
}
- filename = "/dev/cpuctl/apps/bg_non_interactive/tasks";
+ filename = "/dev/cpuctl/bg_non_interactive/tasks";
bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
if (bg_cgroup_fd < 0) {
SLOGE("open of %s failed: %s\n", filename, strerror(errno));
@@ -233,11 +215,9 @@
if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
return -1;
if (grpBuf[0] == '\0') {
- *policy = SP_SYSTEM;
- } else if (!strcmp(grpBuf, "apps/bg_non_interactive")) {
- *policy = SP_BACKGROUND;
- } else if (!strcmp(grpBuf, "apps")) {
*policy = SP_FOREGROUND;
+ } else if (!strcmp(grpBuf, "bg_non_interactive")) {
+ *policy = SP_BACKGROUND;
} else {
errno = ERANGE;
return -1;
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index 255dc2e..cd1bf33 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -59,7 +59,8 @@
-g \
-Wall -Wextra \
-Werror \
- -fno-builtin
+ -fno-builtin \
+ -std=gnu++11
test_src_files := \
liblog_test.cpp
diff --git a/libnativebridge/Android.mk b/libnativebridge/Android.mk
index 6c2e43e..83169eb 100644
--- a/libnativebridge/Android.mk
+++ b/libnativebridge/Android.mk
@@ -13,7 +13,7 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CLANG := true
LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
@@ -30,11 +30,11 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CLANG := true
LOCAL_CPP_EXTENSION := .cc
-LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CFLAGS += -Werror -Wall
LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
LOCAL_LDFLAGS := -ldl
LOCAL_MULTILIB := both
include $(BUILD_HOST_SHARED_LIBRARY)
-include $(LOCAL_PATH)/tests/Android.mk
\ No newline at end of file
+include $(LOCAL_PATH)/tests/Android.mk
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 3facedd..eab2de0 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -43,14 +43,16 @@
enum class NativeBridgeState {
kNotSetup, // Initial state.
kOpened, // After successful dlopen.
+ kPreInitialized, // After successful pre-initialization.
kInitialized, // After successful initialization.
kClosed // Closed or errors.
};
-static const char* kNotSetupString = "kNotSetup";
-static const char* kOpenedString = "kOpened";
-static const char* kInitializedString = "kInitialized";
-static const char* kClosedString = "kClosed";
+static constexpr const char* kNotSetupString = "kNotSetup";
+static constexpr const char* kOpenedString = "kOpened";
+static constexpr const char* kPreInitializedString = "kPreInitialized";
+static constexpr const char* kInitializedString = "kInitialized";
+static constexpr const char* kClosedString = "kClosed";
static const char* GetNativeBridgeStateString(NativeBridgeState state) {
switch (state) {
@@ -60,6 +62,9 @@
case NativeBridgeState::kOpened:
return kOpenedString;
+ case NativeBridgeState::kPreInitialized:
+ return kPreInitializedString;
+
case NativeBridgeState::kInitialized:
return kInitializedString;
@@ -82,8 +87,14 @@
// Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge.
static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr;
-// The app's data directory.
-static char* app_data_dir = nullptr;
+// The app's code cache directory.
+static char* app_code_cache_dir = nullptr;
+
+// Code cache directory (relative to the application private directory)
+// Ideally we'd like to call into framework to retrieve this name. However that's considered an
+// implementation detail and will require either hacks or consistent refactorings. We compromise
+// and hard code the directory name again here.
+static constexpr const char* kCodeCacheDir = "code_cache";
static constexpr uint32_t kNativeBridgeCallbackVersion = 1;
@@ -132,6 +143,13 @@
return cb != nullptr && cb->version == kNativeBridgeCallbackVersion;
}
+static void CloseNativeBridge(bool with_error) {
+ state = NativeBridgeState::kClosed;
+ had_error |= with_error;
+ delete[] app_code_cache_dir;
+ app_code_cache_dir = nullptr;
+}
+
bool LoadNativeBridge(const char* nb_library_filename,
const NativeBridgeRuntimeCallbacks* runtime_cbs) {
// We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not
@@ -149,12 +167,11 @@
}
if (nb_library_filename == nullptr || *nb_library_filename == 0) {
- state = NativeBridgeState::kClosed;
- return true;
+ CloseNativeBridge(false);
+ return false;
} else {
if (!NativeBridgeNameAcceptable(nb_library_filename)) {
- state = NativeBridgeState::kClosed;
- had_error = true;
+ CloseNativeBridge(true);
} else {
// Try to open the library.
void* handle = dlopen(nb_library_filename, RTLD_LAZY);
@@ -178,8 +195,7 @@
// Two failure conditions: could not find library (dlopen failed), or could not find native
// bridge interface (dlsym failed). Both are an error and close the native bridge.
if (callbacks == nullptr) {
- had_error = true;
- state = NativeBridgeState::kClosed;
+ CloseNativeBridge(true);
} else {
runtime_callbacks = runtime_cbs;
state = NativeBridgeState::kOpened;
@@ -216,19 +232,32 @@
template<typename T> void UNUSED(const T&) {}
#endif
-void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) {
- if (app_data_dir_in == nullptr) {
- return;
+bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) {
+ if (state != NativeBridgeState::kOpened) {
+ ALOGE("Invalid state: native bridge is expected to be opened.");
+ CloseNativeBridge(true);
+ return false;
}
- const size_t len = strlen(app_data_dir_in);
- // Make a copy for us.
- app_data_dir = new char[len];
- strncpy(app_data_dir, app_data_dir_in, len);
+ if (app_data_dir_in == nullptr) {
+ ALOGE("Application private directory cannot be null.");
+ CloseNativeBridge(true);
+ return false;
+ }
+
+ // Create the path to the application code cache directory.
+ // The memory will be release after Initialization or when the native bridge is closed.
+ const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2; // '\0' + '/'
+ app_code_cache_dir = new char[len];
+ snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir);
+
+ // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo.
+ // Failure is not fatal and will keep the native bridge in kPreInitialized.
+ state = NativeBridgeState::kPreInitialized;
#ifndef __APPLE__
if (instruction_set == nullptr) {
- return;
+ return true;
}
size_t isa_len = strlen(instruction_set);
if (isa_len > 10) {
@@ -237,11 +266,11 @@
// be another instruction set in the future.
ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.",
instruction_set);
- return;
+ return true;
}
- // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. If the file does not exist, the
- // mount command will fail, so we safe the extra file existence check...
+ // If the file does not exist, the mount command will fail,
+ // so we save the extra file existence check.
char cpuinfo_path[1024];
#ifdef HAVE_ANDROID_OS
@@ -263,10 +292,12 @@
nullptr)) == -1) { // "Data."
ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno));
}
-#else
+#else // __APPLE__
UNUSED(instruction_set);
ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible.");
#endif
+
+ return true;
}
static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) {
@@ -353,20 +384,40 @@
// We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that
// point we are not multi-threaded, so we do not need locking here.
- if (state == NativeBridgeState::kOpened) {
- // Try to initialize.
- if (callbacks->initialize(runtime_callbacks, app_data_dir, instruction_set)) {
- SetupEnvironment(callbacks, env, instruction_set);
- state = NativeBridgeState::kInitialized;
- } else {
- // Unload the library.
- dlclose(native_bridge_handle);
- had_error = true;
- state = NativeBridgeState::kClosed;
+ if (state == NativeBridgeState::kPreInitialized) {
+ // Check for code cache: if it doesn't exist try to create it.
+ struct stat st;
+ if (stat(app_code_cache_dir, &st) == -1) {
+ if (errno == ENOENT) {
+ if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) {
+ ALOGE("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
+ CloseNativeBridge(true);
+ }
+ } else {
+ ALOGE("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
+ CloseNativeBridge(true);
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ ALOGE("Code cache is not a directory %s.", app_code_cache_dir);
+ CloseNativeBridge(true);
+ }
+
+ // If we're still PreInitialized (dind't fail the code cache checks) try to initialize.
+ if (state == NativeBridgeState::kPreInitialized) {
+ if (callbacks->initialize(runtime_callbacks, app_code_cache_dir, instruction_set)) {
+ SetupEnvironment(callbacks, env, instruction_set);
+ state = NativeBridgeState::kInitialized;
+ // We no longer need the code cache path, release the memory.
+ delete[] app_code_cache_dir;
+ app_code_cache_dir = nullptr;
+ } else {
+ // Unload the library.
+ dlclose(native_bridge_handle);
+ CloseNativeBridge(true);
+ }
}
} else {
- had_error = true;
- state = NativeBridgeState::kClosed;
+ CloseNativeBridge(true);
}
return state == NativeBridgeState::kInitialized;
@@ -378,22 +429,22 @@
switch(state) {
case NativeBridgeState::kOpened:
+ case NativeBridgeState::kPreInitialized:
case NativeBridgeState::kInitialized:
// Unload.
dlclose(native_bridge_handle);
+ CloseNativeBridge(false);
break;
case NativeBridgeState::kNotSetup:
// Not even set up. Error.
- had_error = true;
+ CloseNativeBridge(true);
break;
case NativeBridgeState::kClosed:
// Ignore.
break;
}
-
- state = NativeBridgeState::kClosed;
}
bool NativeBridgeError() {
@@ -401,7 +452,9 @@
}
bool NativeBridgeAvailable() {
- return state == NativeBridgeState::kOpened || state == NativeBridgeState::kInitialized;
+ return state == NativeBridgeState::kOpened
+ || state == NativeBridgeState::kPreInitialized
+ || state == NativeBridgeState::kInitialized;
}
bool NativeBridgeInitialized() {
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 9c7e1b8..f28c490 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -1,19 +1,29 @@
# Build the unit tests.
LOCAL_PATH := $(call my-dir)
+
+include $(LOCAL_PATH)/Android.nativebridge-dummy.mk
+
include $(CLEAR_VARS)
# Build the unit tests.
test_src_files := \
+ CodeCacheCreate_test.cpp \
+ CodeCacheExists_test.cpp \
+ CompleteFlow_test.cpp \
InvalidCharsNativeBridge_test.cpp \
NeedsNativeBridge_test.cpp \
PreInitializeNativeBridge_test.cpp \
+ PreInitializeNativeBridgeFail1_test.cpp \
+ PreInitializeNativeBridgeFail2_test.cpp \
ReSetupNativeBridge_test.cpp \
UnavailableNativeBridge_test.cpp \
ValidNameNativeBridge_test.cpp
+
shared_libraries := \
liblog \
- libnativebridge
+ libnativebridge \
+ libnativebridge-dummy
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
@@ -33,4 +43,4 @@
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
$(eval include $(BUILD_HOST_NATIVE_TEST)) \
-)
\ No newline at end of file
+)
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk
new file mode 100644
index 0000000..1caf50a
--- /dev/null
+++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+NATIVE_BRIDGE_COMMON_SRC_FILES := \
+ DummyNativeBridge.cpp
+
+# Shared library for target
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= libnativebridge-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+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-dummy
+
+LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES)
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -Werror -Wall
+LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected
+LOCAL_LDFLAGS := -ldl
+LOCAL_MULTILIB := both
+
+include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/libnativebridge/tests/CodeCacheCreate_test.cpp b/libnativebridge/tests/CodeCacheCreate_test.cpp
new file mode 100644
index 0000000..58270c4
--- /dev/null
+++ b/libnativebridge/tests/CodeCacheCreate_test.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace android {
+
+// Tests that the bridge initialization creates the code_cache if it doesn't
+// exists.
+TEST_F(NativeBridgeTest, CodeCacheCreate) {
+ // Make sure that code_cache does not exists
+ struct stat st;
+ ASSERT_EQ(-1, stat(kCodeCache, &st));
+ ASSERT_EQ(ENOENT, errno);
+
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_FALSE(NativeBridgeError());
+
+ // Check that code_cache was created
+ ASSERT_EQ(0, stat(kCodeCache, &st));
+ ASSERT_TRUE(S_ISDIR(st.st_mode));
+
+ // Clean up
+ UnloadNativeBridge();
+ ASSERT_EQ(0, rmdir(kCodeCache));
+
+ ASSERT_FALSE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/CodeCacheExists_test.cpp b/libnativebridge/tests/CodeCacheExists_test.cpp
new file mode 100644
index 0000000..8ba0158
--- /dev/null
+++ b/libnativebridge/tests/CodeCacheExists_test.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+namespace android {
+
+// Tests that the bridge is initialized without errors if the code_cache already
+// exists.
+TEST_F(NativeBridgeTest, CodeCacheExists) {
+ // Make sure that code_cache does not exists
+ struct stat st;
+ ASSERT_EQ(-1, stat(kCodeCache, &st));
+ ASSERT_EQ(ENOENT, errno);
+
+ // Create the code_cache
+ ASSERT_EQ(0, mkdir(kCodeCache, S_IRWXU | S_IRWXG | S_IXOTH));
+
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_FALSE(NativeBridgeError());
+
+ // Check that the code cache is still there
+ ASSERT_EQ(0, stat(kCodeCache, &st));
+ ASSERT_TRUE(S_ISDIR(st.st_mode));
+
+ // Clean up
+ UnloadNativeBridge();
+ ASSERT_EQ(0, rmdir(kCodeCache));
+
+ ASSERT_FALSE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/CompleteFlow_test.cpp b/libnativebridge/tests/CompleteFlow_test.cpp
new file mode 100644
index 0000000..cf06d2c
--- /dev/null
+++ b/libnativebridge/tests/CompleteFlow_test.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <unistd.h>
+
+namespace android {
+
+TEST_F(NativeBridgeTest, CompleteFlow) {
+ // Init
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(PreInitializeNativeBridge(".", "isa"));
+ ASSERT_TRUE(NativeBridgeAvailable());
+ ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr));
+ ASSERT_TRUE(NativeBridgeAvailable());
+
+ // Basic calls to check that nothing crashes
+ ASSERT_FALSE(NativeBridgeIsSupported(nullptr));
+ ASSERT_EQ(nullptr, NativeBridgeLoadLibrary(nullptr, 0));
+ ASSERT_EQ(nullptr, NativeBridgeGetTrampoline(nullptr, nullptr, nullptr, 0));
+
+ // Unload
+ UnloadNativeBridge();
+ ASSERT_FALSE(NativeBridgeAvailable());
+ ASSERT_FALSE(NativeBridgeError());
+
+ // Clean-up code_cache
+ ASSERT_EQ(0, rmdir(kCodeCache));
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/DummyNativeBridge.cpp b/libnativebridge/tests/DummyNativeBridge.cpp
new file mode 100644
index 0000000..b9894f6
--- /dev/null
+++ b/libnativebridge/tests/DummyNativeBridge.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+// A dummy implementation of the native-bridge interface.
+
+#include "nativebridge/native_bridge.h"
+
+// NativeBridgeCallbacks implementations
+extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* /* art_cbs */,
+ const char* /* app_code_cache_dir */,
+ const char* /* isa */) {
+ return true;
+}
+
+extern "C" void* native_bridge_loadLibrary(const char* /* libpath */, int /* flag */) {
+ return nullptr;
+}
+
+extern "C" void* native_bridge_getTrampoline(void* /* handle */, const char* /* name */,
+ const char* /* shorty */, uint32_t /* len */) {
+ return nullptr;
+}
+
+extern "C" bool native_bridge_isSupported(const char* /* libpath */) {
+ return false;
+}
+
+extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv(
+ const char* /* abi */) {
+ return nullptr;
+}
+
+android::NativeBridgeCallbacks NativeBridgeItf {
+ .version = 1,
+ .initialize = &native_bridge_initialize,
+ .loadLibrary = &native_bridge_loadLibrary,
+ .getTrampoline = &native_bridge_getTrampoline,
+ .isSupported = &native_bridge_isSupported,
+ .getAppEnv = &native_bridge_getAppEnv
+};
diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h
index 0d731cb..6a5c126 100644
--- a/libnativebridge/tests/NativeBridgeTest.h
+++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -22,6 +22,9 @@
#include <nativebridge/native_bridge.h>
#include <gtest/gtest.h>
+constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so";
+constexpr const char* kCodeCache = "./code_cache";
+
namespace android {
class NativeBridgeTest : public testing::Test {
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
new file mode 100644
index 0000000..69c30a1
--- /dev/null
+++ b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
@@ -0,0 +1,38 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+namespace android {
+
+TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail1) {
+ // Needs a valid application directory.
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
+ ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa"));
+ ASSERT_TRUE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
new file mode 100644
index 0000000..74e96e0
--- /dev/null
+++ b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "NativeBridgeTest.h"
+
+#include <cstdio>
+#include <cstring>
+#include <cutils/log.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+namespace android {
+
+TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail2) {
+ // Needs LoadNativeBridge() first
+ ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa"));
+ ASSERT_TRUE(NativeBridgeError());
+}
+
+} // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
index 84078f7..cec26ce 100644
--- a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
+++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
@@ -31,6 +31,7 @@
static constexpr const char* kTestData = "PreInitializeNativeBridge test.";
TEST_F(NativeBridgeTest, PreInitializeNativeBridge) {
+ ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr));
#ifndef __APPLE__ // Mac OS does not support bind-mount.
#ifndef HAVE_ANDROID_OS // Cannot write into the hard-wired location.
// Try to create our mount namespace.
@@ -41,8 +42,7 @@
fprintf(cpuinfo, kTestData);
fclose(cpuinfo);
- // Call the setup.
- PreInitializeNativeBridge("does not matter 1", "short 2");
+ ASSERT_TRUE(PreInitializeNativeBridge("does not matter 1", "short 2"));
// Read /proc/cpuinfo
FILE* proc_cpuinfo = fopen("/proc/cpuinfo", "r");
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index f8d6162..ee2f32d 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -22,15 +22,26 @@
#include <sys/klog.h>
#include <sys/prctl.h>
#include <sys/uio.h>
+#include <syslog.h>
#include "libaudit.h"
#include "LogAudit.h"
+#define KMSG_PRIORITY(PRI) \
+ '<', \
+ '0' + (LOG_AUTH | (PRI)) / 10, \
+ '0' + (LOG_AUTH | (PRI)) % 10, \
+ '>'
+
LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg)
: SocketListener(getLogSocket(), false)
, logbuf(buf)
, reader(reader)
, fdDmesg(-1) {
+ static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
+ 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
+ ' ', 's', 't', 'a', 'r', 't', '\n' };
+ write(fdDmsg, auditd_message, sizeof(auditd_message));
logDmesg();
fdDmesg = fdDmsg;
}
@@ -75,13 +86,19 @@
memmove(cp, cp + 1, strlen(cp + 1) + 1);
}
+ bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
if (fdDmesg >= 0) {
- struct iovec iov[2];
+ struct iovec iov[3];
+ static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
+ static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
- iov[0].iov_base = str;
- iov[0].iov_len = strlen(str);
- iov[1].iov_base = const_cast<char *>("\n");
- iov[1].iov_len = 1;
+ 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;
writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
}
@@ -175,10 +192,7 @@
if (!newstr) {
rc = -ENOMEM;
} else {
- *newstr = (strstr(str, " permissive=1")
- || strstr(str, " policy loaded "))
- ? ANDROID_LOG_INFO
- : ANDROID_LOG_WARN;
+ *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
strlcpy(newstr + 1, comm, l);
strncpy(newstr + 1 + l, str, estr - str);
strcpy(newstr + 1 + l + (estr - str), ecomm);
@@ -234,7 +248,7 @@
if (fd < 0) {
return fd;
}
- if (audit_set_pid(fd, getpid(), WAIT_YES) < 0) {
+ if (audit_setup(fd, getpid()) < 0) {
audit_close(fd);
fd = -1;
}
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index cd9ea20..8c1c344 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -93,9 +93,9 @@
}
LogBuffer::LogBuffer(LastLogTimes *times)
- : mTimes(*times) {
+ : dgramQlenStatistics(false)
+ , mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
- dgram_qlen_statistics = false;
static const char global_tuneable[] = "persist.logd.size"; // Settings App
static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
@@ -150,10 +150,10 @@
while (--it != mLogElements.begin()) {
if ((*it)->getRealTime() <= realtime) {
// halves the peak performance, use with caution
- if (dgram_qlen_statistics) {
+ if (dgramQlenStatistics) {
LogBufferElementCollection::iterator ib = it;
unsigned short buckets, num = 1;
- for (unsigned short i = 0; (buckets = stats.dgram_qlen(i)); ++i) {
+ for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) {
buckets -= num;
num += buckets;
while (buckets && (--ib != mLogElements.begin())) {
@@ -267,8 +267,7 @@
if (uid == caller_uid) {
it = mLogElements.erase(it);
- unsigned short len = e->getMsgLen();
- stats.subtract(len, id, uid, e->getPid());
+ stats.subtract(e->getMsgLen(), id, uid, e->getPid());
delete e;
pruneRows--;
if (pruneRows == 0) {
@@ -318,23 +317,19 @@
uid_t uid = e->getUid();
- if (uid == worst) {
+ if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed
it = mLogElements.erase(it);
unsigned short len = e->getMsgLen();
- stats.subtract(len, id, worst, e->getPid());
- delete e;
- kick = true;
- pruneRows--;
- if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
- break;
- }
- worst_sizes -= len;
- } else if (mPrune.naughty(e)) { // BlackListed
- it = mLogElements.erase(it);
- stats.subtract(e->getMsgLen(), id, uid, e->getPid());
+ stats.subtract(len, id, uid, e->getPid());
delete e;
pruneRows--;
- if (pruneRows == 0) {
+ if (uid == worst) {
+ kick = true;
+ if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) {
+ break;
+ }
+ worst_sizes -= len;
+ } else if (pruneRows == 0) {
break;
}
} else {
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 4b982a8..879baea 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -37,8 +37,7 @@
pthread_mutex_t mLogElementsLock;
LogStatistics stats;
-
- bool dgram_qlen_statistics;
+ bool dgramQlenStatistics;
PruneList mPrune;
@@ -66,7 +65,11 @@
void enableDgramQlenStatistics() {
stats.enableDgramQlenStatistics();
- dgram_qlen_statistics = true;
+ dgramQlenStatistics = true;
+ }
+
+ void enableStatistics() {
+ stats.enableStatistics();
}
int initPrune(char *cp) { return mPrune.init(cp); }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index a2f27c6..2a45590 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -51,11 +51,11 @@
}
bool PidStatistics::pidGone() {
- if (mGone) {
+ if (mGone || (pid == gone)) {
return true;
}
- if (pid == gone) {
- return true;
+ if (pid == 0) {
+ return false;
}
if (kill(pid, 0) && (errno != EPERM)) {
mGone = true;
@@ -90,9 +90,14 @@
}
// must call free to release return value
+// If only we could sniff our own logs for:
+// <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid>
+// which debuggerd prints as a process is crashing.
char *PidStatistics::pidToName(pid_t pid) {
char *retval = NULL;
- if (pid != gone) {
+ if (pid == 0) { // special case from auditd for kernel
+ retval = strdup("logd.auditd");
+ } else if (pid != gone) {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
int fd = open(buffer, O_RDONLY);
@@ -122,7 +127,7 @@
PidStatisticsCollection::iterator it;
for (it = begin(); it != end();) {
delete (*it);
- it = Pids.erase(it);
+ it = erase(it);
}
}
@@ -130,7 +135,7 @@
mSizes += size;
++mElements;
- PidStatistics *p;
+ PidStatistics *p = NULL;
PidStatisticsCollection::iterator last;
PidStatisticsCollection::iterator it;
for (last = it = begin(); it != end(); last = it, ++it) {
@@ -141,12 +146,12 @@
}
}
// insert if the gone entry.
- bool insert = (last != it) && (p->getPid() == p->gone);
+ bool insert_before_last = (last != it) && p && (p->getPid() == p->gone);
p = new PidStatistics(pid, pidToName(pid));
- if (insert) {
- Pids.insert(last, p);
+ if (insert_before_last) {
+ insert(last, p);
} else {
- Pids.push_back(p);
+ push_back(p);
}
p->add(size);
}
@@ -163,17 +168,17 @@
size_t szsTotal = p->sizesTotal();
size_t elsTotal = p->elementsTotal();
delete p;
- Pids.erase(it);
+ erase(it);
it = end();
--it;
if (it == end()) {
p = new PidStatistics(p->gone);
- Pids.push_back(p);
+ push_back(p);
} else {
p = *it;
if (p->getPid() != p->gone) {
p = new PidStatistics(p->gone);
- Pids.push_back(p);
+ push_back(p);
}
}
p->addTotal(szsTotal, elsTotal);
@@ -194,8 +199,8 @@
PidStatistics *n = (*it);
if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) {
pass = true;
- Pids.erase(it);
- Pids.insert(lt, n);
+ erase(it);
+ insert(lt, n);
it = lt;
n = l;
}
@@ -302,6 +307,10 @@
}
void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) {
+ if (uid == (uid_t) -1) { // init
+ uid = (uid_t) AID_ROOT;
+ }
+
UidStatisticsCollection::iterator it;
for (it = begin(); it != end(); ++it) {
UidStatistics *u = *it;
@@ -384,24 +393,25 @@
}
LogStatistics::LogStatistics()
- : start(CLOCK_MONOTONIC) {
+ : mStatistics(false)
+ , dgramQlenStatistics(false)
+ , start(CLOCK_MONOTONIC) {
log_id_for_each(i) {
mSizes[i] = 0;
mElements[i] = 0;
}
- dgram_qlen_statistics = false;
- for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) {
+ for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) {
mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max;
mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max;
}
}
-// Each bucket below represents a dgram_qlen of log messages. By
+// Each bucket below represents a dgramQlen of log messages. By
// finding the minimum period of time from start to finish
-// of each dgram_qlen, we can get a performance expectation for
+// of each dgramQlen, we can get a performance expectation for
// the user space logger. The net result is that the period
-// of time divided by the dgram_qlen will give us the average time
+// of time divided by the dgramQlen will give us the average time
// between log messages; at the point where the average time
// is greater than the throughput capability of the logger
// we will not longer require the benefits of the FIFO formed
@@ -412,7 +422,7 @@
//
// for example (reformatted):
//
-// Minimum time between log events per dgram_qlen:
+// Minimum time between log events per dgramQlen:
// 1 2 3 5 10 20 30 50 100 200 300 400 500 600
// 5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5
//
@@ -426,12 +436,12 @@
// a large engineering margin so the rule of thumb that lead us to 100 is
// fine.
//
-// bucket dgram_qlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
+// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300
const unsigned short LogStatistics::mBuckets[] = {
1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600
};
-unsigned short LogStatistics::dgram_qlen(unsigned short bucket) {
+unsigned short LogStatistics::dgramQlen(unsigned short bucket) {
if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) {
return 0;
}
@@ -455,6 +465,9 @@
log_id_t log_id, uid_t uid, pid_t pid) {
mSizes[log_id] += size;
++mElements[log_id];
+ if (!mStatistics) {
+ return;
+ }
id(log_id).add(size, uid, pid);
}
@@ -462,6 +475,9 @@
log_id_t log_id, uid_t uid, pid_t pid) {
mSizes[log_id] -= size;
--mElements[log_id];
+ if (!mStatistics) {
+ return;
+ }
id(log_id).subtract(size, uid, pid);
}
@@ -545,25 +561,28 @@
spaces = 1;
log_time t(CLOCK_MONOTONIC);
- unsigned long long d = t.nsec() - start.nsec();
- string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
+ unsigned long long d;
+ if (mStatistics) {
+ d = t.nsec() - start.nsec();
+ string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu",
d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
(d / NS_PER_SEC) % 60, d % NS_PER_SEC);
- log_id_for_each(i) {
- if (!(logMask & (1 << i))) {
- continue;
+ log_id_for_each(i) {
+ if (!(logMask & (1 << i))) {
+ continue;
+ }
+ oldLength = string.length();
+ if (spaces < 0) {
+ spaces = 0;
+ }
+ string.appendFormat("%*s%zu/%zu", spaces, "",
+ sizesTotal(i), elementsTotal(i));
+ spaces += spaces_total + oldLength - string.length();
}
- oldLength = string.length();
- if (spaces < 0) {
- spaces = 0;
- }
- string.appendFormat("%*s%zu/%zu", spaces, "",
- sizesTotal(i), elementsTotal(i));
- spaces += spaces_total + oldLength - string.length();
+ spaces = 1;
}
- spaces = 1;
d = t.nsec() - oldest.nsec();
string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu",
d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60,
@@ -686,23 +705,23 @@
pids.clear();
}
- if (dgram_qlen_statistics) {
+ if (dgramQlenStatistics) {
const unsigned short spaces_time = 6;
const unsigned long long max_seconds = 100000;
spaces = 0;
- string.append("\n\nMinimum time between log events per dgram_qlen:\n");
- for(unsigned short i = 0; dgram_qlen(i); ++i) {
+ string.append("\n\nMinimum time between log events per max_dgram_qlen:\n");
+ for(unsigned short i = 0; dgramQlen(i); ++i) {
oldLength = string.length();
if (spaces < 0) {
spaces = 0;
}
- string.appendFormat("%*s%u", spaces, "", dgram_qlen(i));
+ string.appendFormat("%*s%u", spaces, "", dgramQlen(i));
spaces += spaces_time + oldLength - string.length();
}
string.append("\n");
spaces = 0;
unsigned short n;
- for(unsigned short i = 0; (n = dgram_qlen(i)); ++i) {
+ for(unsigned short i = 0; (n = dgramQlen(i)); ++i) {
unsigned long long duration = minimum(i);
if (duration) {
duration /= n;
@@ -724,8 +743,8 @@
/ (NS_PER_SEC / 1000));
} else if (duration >= (NS_PER_SEC / (1000000 / 10))) {
string.appendFormat("%lluu",
- (duration + (NS_PER_SEC / 2 / 1000000))
- / (NS_PER_SEC / 1000000));
+ (duration + (NS_PER_SEC / 2 / 1000000))
+ / (NS_PER_SEC / 1000000));
} else {
string.appendFormat("%llun", duration);
}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 3733137..f6c4329 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -72,6 +72,10 @@
PidStatisticsCollection Pids;
+ void insert(PidStatisticsCollection::iterator i, PidStatistics *p)
+ { Pids.insert(i, p); }
+ void push_back(PidStatistics *p) { Pids.push_back(p); }
+
size_t mSizes;
size_t mElements;
@@ -81,6 +85,8 @@
PidStatisticsCollection::iterator begin() { return Pids.begin(); }
PidStatisticsCollection::iterator end() { return Pids.end(); }
+ PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i)
+ { return Pids.erase(i); }
uid_t getUid() { return uid; }
@@ -138,7 +144,8 @@
size_t mSizes[LOG_ID_MAX];
size_t mElements[LOG_ID_MAX];
- bool dgram_qlen_statistics;
+ bool mStatistics;
+ bool dgramQlenStatistics;
static const unsigned short mBuckets[14];
log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])];
@@ -150,8 +157,9 @@
LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; }
- void enableDgramQlenStatistics() { dgram_qlen_statistics = true; }
- static unsigned short dgram_qlen(unsigned short bucket);
+ void enableDgramQlenStatistics() { dgramQlenStatistics = true; }
+ void enableStatistics() { mStatistics = true; }
+ static unsigned short dgramQlen(unsigned short bucket);
unsigned long long minimum(unsigned short bucket);
void recordDiff(log_time diff, unsigned short bucket);
diff --git a/logd/README.property b/logd/README.property
index f4b3c3c..b7fcece 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -4,6 +4,9 @@
logd.auditd bool true Enable selinux audit daemon
logd.auditd.dmesg bool true selinux audit messages duplicated and
sent on to dmesg log
+logd.statistics bool depends Enable logcat -S statistics.
+ro.config.low_ram bool false if true, logd.statistics default false
+ro.build.type string if user, logd.statistics default false
logd.statistics.dgram_qlen bool false Record dgram_qlen statistics. This
represents a performance impact and
is used to determine the platform's
diff --git a/logd/libaudit.c b/logd/libaudit.c
index ca88d1b..d00d579 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -162,7 +162,7 @@
return rc;
}
-int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode)
+int audit_setup(int fd, uint32_t pid)
{
int rc;
struct audit_message rep;
@@ -176,7 +176,8 @@
* and the the mask set to AUDIT_STATUS_PID
*/
status.pid = pid;
- status.mask = AUDIT_STATUS_PID;
+ status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
+ status.rate_limit = 20; // audit entries per second
/* Let the kernel know this pid will be registering for audit events */
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -188,24 +189,21 @@
/*
* In a request where we need to wait for a response, wait for the message
* and discard it. This message confirms and sync's us with the kernel.
- * This daemon is now registered as the audit logger. Only wait if the
- * wmode is != WAIT_NO
+ * This daemon is now registered as the audit logger.
+ *
+ * TODO
+ * If the daemon dies and restarts the message didn't come back,
+ * so I went to non-blocking and it seemed to fix the bug.
+ * Need to investigate further.
*/
- if (wmode != WAIT_NO) {
- /* TODO
- * If the daemon dies and restarts the message didn't come back,
- * so I went to non-blocking and it seemed to fix the bug.
- * Need to investigate further.
- */
- audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
- }
+ audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
return 0;
}
int audit_open()
{
- return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
+ return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
}
int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
diff --git a/logd/libaudit.h b/logd/libaudit.h
index cb114f9..b9e330d 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -37,11 +37,6 @@
GET_REPLY_NONBLOCKING
} reply_t;
-typedef enum {
- WAIT_NO,
- WAIT_YES
-} rep_wait_t;
-
/* type == AUDIT_SIGNAL_INFO */
struct audit_sig_info {
uid_t uid;
@@ -92,12 +87,10 @@
* The fd returned by a call to audit_open()
* @param pid
* The pid whom to set as the reciever of audit messages
- * @param wmode
- * Whether or not to block on the underlying socket io calls.
* @return
* This function returns 0 on success, -errno on error.
*/
-extern int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode);
+extern int audit_setup(int fd, uint32_t pid);
__END_DECLS
diff --git a/logd/main.cpp b/logd/main.cpp
index 1e1a718..54da7e3 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -152,6 +152,15 @@
if (property_get_bool("logd.statistics.dgram_qlen", false)) {
logBuf->enableDgramQlenStatistics();
}
+ {
+ char property[PROPERTY_VALUE_MAX];
+ property_get("ro.build.type", property, "");
+ if (property_get_bool("logd.statistics",
+ !!strcmp(property, "user")
+ && !property_get_bool("ro.config.low_ram", false))) {
+ logBuf->enableStatistics();
+ }
+ }
// LogReader listens on /dev/socket/logdr. When a client
// connects, log entries in the LogBuffer are written to the client.
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 67222d7..30bef46 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -10,4 +10,3 @@
export LOOP_MOUNTPOINT /mnt/obb
export BOOTCLASSPATH %BOOTCLASSPATH%
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
- export LD_PRELOAD libsigchain.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 76c90df..34b10d2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -119,25 +119,18 @@
mount cgroup none /dev/cpuctl cpu
chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
- chmod 0660 /dev/cpuctl/tasks
+ chmod 0666 /dev/cpuctl/tasks
write /dev/cpuctl/cpu.shares 1024
- write /dev/cpuctl/cpu.rt_runtime_us 950000
+ write /dev/cpuctl/cpu.rt_runtime_us 800000
write /dev/cpuctl/cpu.rt_period_us 1000000
- mkdir /dev/cpuctl/apps
- chown system system /dev/cpuctl/apps/tasks
- chmod 0666 /dev/cpuctl/apps/tasks
- write /dev/cpuctl/apps/cpu.shares 1024
- write /dev/cpuctl/apps/cpu.rt_runtime_us 800000
- write /dev/cpuctl/apps/cpu.rt_period_us 1000000
-
- mkdir /dev/cpuctl/apps/bg_non_interactive
- chown system system /dev/cpuctl/apps/bg_non_interactive/tasks
- chmod 0666 /dev/cpuctl/apps/bg_non_interactive/tasks
+ mkdir /dev/cpuctl/bg_non_interactive
+ chown system system /dev/cpuctl/bg_non_interactive/tasks
+ chmod 0666 /dev/cpuctl/bg_non_interactive/tasks
# 5.0 %
- write /dev/cpuctl/apps/bg_non_interactive/cpu.shares 52
- write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000
- write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000
+ write /dev/cpuctl/bg_non_interactive/cpu.shares 52
+ write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000
+ write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000
# qtaguid will limit access to specific data based on group memberships.
# net_bw_acct grants impersonation of socket owners.
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index eff24c3..474f630 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -88,6 +88,7 @@
/dev/ppp 0660 radio vpn
# sysfs properties
+/sys/devices/platform/trusty.* trusty_version 0440 root log
/sys/devices/virtual/input/input* enable 0660 root input
/sys/devices/virtual/input/input* poll_delay 0660 root input
/sys/devices/virtual/usb_composite/* enable 0664 root system
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 7bf6394..9cfb040 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -168,6 +168,11 @@
__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;
@@ -224,6 +229,25 @@
struct node root;
char obbpath[PATH_MAX];
+ /* 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;
+
Hashmap* package_to_appid;
Hashmap* appid_with_rw;
};
@@ -387,7 +411,7 @@
static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node)
{
- attr->ino = node->nid;
+ attr->ino = node->ino;
attr->size = s->st_size;
attr->blocks = s->st_blocks;
attr->atime = s->st_atime;
@@ -575,6 +599,13 @@
struct node *node;
size_t namelen = strlen(name);
+ // Detect overflows in the inode counter. "4 billion nodes should be enough
+ // for everybody".
+ if (fuse->inode_ctr == 0) {
+ ERROR("No more inode numbers available");
+ return NULL;
+ }
+
node = calloc(1, sizeof(struct node));
if (!node) {
return NULL;
@@ -596,6 +627,7 @@
}
node->namelen = namelen;
node->nid = ptr_to_id(node);
+ node->ino = fuse->inode_ctr++;
node->gen = fuse->next_generation++;
derive_permissions_locked(fuse, parent, node);
@@ -700,6 +732,7 @@
fuse->derive = derive;
fuse->split_perms = split_perms;
fuse->write_gid = write_gid;
+ fuse->inode_ctr = 1;
memset(&fuse->root, 0, sizeof(fuse->root));
fuse->root.nid = FUSE_ROOT_ID; /* 1 */
@@ -1807,7 +1840,7 @@
"fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d",
fd, uid, gid);
- res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts);
+ res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts);
if (res < 0) {
ERROR("cannot mount fuse filesystem: %s\n", strerror(errno));
goto error;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index d8d397e..84714cf 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -176,6 +176,7 @@
readlink \
renice \
restorecon \
+ prlimit \
rmmod \
route \
runcon \
diff --git a/toolbox/prlimit.c b/toolbox/prlimit.c
new file mode 100644
index 0000000..8cf202a
--- /dev/null
+++ b/toolbox/prlimit.c
@@ -0,0 +1,76 @@
+/*
+ * 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/top.c b/toolbox/top.c
index 280a032..b1a275c 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -32,6 +32,7 @@
#include <ctype.h>
#include <dirent.h>
#include <grp.h>
+#include <inttypes.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -59,13 +60,13 @@
char name[PROC_NAME_LEN];
char tname[THREAD_NAME_LEN];
char state;
- long unsigned utime;
- long unsigned stime;
- long unsigned delta_utime;
- long unsigned delta_stime;
- long unsigned delta_time;
- long vss;
- long rss;
+ uint64_t utime;
+ uint64_t stime;
+ uint64_t delta_utime;
+ uint64_t delta_stime;
+ uint64_t delta_time;
+ uint64_t vss;
+ uint64_t rss;
int prs;
int num_threads;
char policy[POLICY_NAME_LEN];
@@ -344,10 +345,19 @@
proc->tname[THREAD_NAME_LEN-1] = 0;
/* Scan rest of string. */
- sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld "
- "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d",
- &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss, &proc->prs);
+ sscanf(close_paren + 1,
+ " %c " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+ "%" SCNu64
+ "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d "
+ "%" SCNu64
+ "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
+ "%d",
+ &proc->state,
+ &proc->utime,
+ &proc->stime,
+ &proc->vss,
+ &proc->rss,
+ &proc->prs);
return 0;
}
@@ -470,12 +480,15 @@
snprintf(user_buf, 20, "%d", proc->uid);
user_str = user_buf;
}
- if (!threads)
- printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
- else
- printf("%5d %5d %2d %3ld%% %c %6ldK %6ldK %3s %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name);
+ if (!threads) {
+ printf("%5d %2d %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %s\n",
+ proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname);
+ } else {
+ printf("%5d %5d %2d %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %-15s %s\n",
+ proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state,
+ proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name);
+ }
}
}