Merge "debuggerd: kill crashing processes with the signal they died with."
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 8893780..2767f73 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -16,6 +16,7 @@
 
 #include <fcntl.h>
 #include <inttypes.h>
+#include <semaphore.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/types.h>
@@ -531,9 +532,15 @@
 }
 
 static unsigned signaled;
-log_time signal_time;
+static log_time signal_time;
 
-static void caught_blocking(int /*signum*/)
+/*
+ *  Strictly, we are not allowed to log messages in a signal context, but we
+ * do make an effort to keep the failure surface minimized, and this in-effect
+ * should catch any regressions in that effort. The odds of a logged message
+ * in a signal handler causing a lockup problem should be _very_ small.
+ */
+static void caught_blocking_signal(int /*signum*/)
 {
     unsigned long long v = 0xDEADBEEFA55A0000ULL;
 
@@ -583,7 +590,7 @@
     }
 }
 
-TEST(liblog, android_logger_list_read__cpu) {
+TEST(liblog, android_logger_list_read__cpu_signal) {
     struct logger_list *logger_list;
     unsigned long long v = 0xDEADBEEFA55A0000ULL;
 
@@ -606,7 +613,7 @@
 
     memset(&signal_time, 0, sizeof(signal_time));
 
-    signal(SIGALRM, caught_blocking);
+    signal(SIGALRM, caught_blocking_signal);
     alarm(alarm_time);
 
     signaled = 0;
@@ -651,7 +658,158 @@
     alarm(0);
     signal(SIGALRM, SIG_DFL);
 
-    EXPECT_LT(1, count);
+    EXPECT_LE(1, count);
+
+    EXPECT_EQ(1, signals);
+
+    android_logger_list_close(logger_list);
+
+    unsigned long long uticks_end;
+    unsigned long long sticks_end;
+    get_ticks(&uticks_end, &sticks_end);
+
+    // Less than 1% in either user or system time, or both
+    const unsigned long long one_percent_ticks = alarm_time;
+    unsigned long long user_ticks = uticks_end - uticks_start;
+    unsigned long long system_ticks = sticks_end - sticks_start;
+    EXPECT_GT(one_percent_ticks, user_ticks);
+    EXPECT_GT(one_percent_ticks, system_ticks);
+    EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
+}
+
+/*
+ *  Strictly, we are not allowed to log messages in a signal context, the
+ * correct way to handle this is to ensure the messages are constructed in
+ * a thread; the signal handler should only unblock the thread.
+ */
+static sem_t thread_trigger;
+
+static void caught_blocking_thread(int /*signum*/)
+{
+    sem_post(&thread_trigger);
+}
+
+static void *running_thread(void *) {
+    unsigned long long v = 0xDEADBEAFA55A0000ULL;
+
+    v += getpid() & 0xFFFF;
+
+    struct timespec timeout;
+    clock_gettime(CLOCK_REALTIME, &timeout);
+    timeout.tv_sec += 55;
+    sem_timedwait(&thread_trigger, &timeout);
+
+    ++signaled;
+    if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
+        signal_time = log_time(CLOCK_MONOTONIC);
+        signal_time.tv_sec += 2;
+    }
+
+    LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
+
+    return NULL;
+}
+
+int start_thread()
+{
+    sem_init(&thread_trigger, 0, 0);
+
+    pthread_attr_t attr;
+    if (pthread_attr_init(&attr)) {
+        return -1;
+    }
+
+    struct sched_param param;
+
+    memset(&param, 0, sizeof(param));
+    pthread_attr_setschedparam(&attr, &param);
+    pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
+
+    if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
+        pthread_attr_destroy(&attr);
+        return -1;
+    }
+
+    pthread_t thread;
+    if (pthread_create(&thread, &attr, running_thread, NULL)) {
+        pthread_attr_destroy(&attr);
+        return -1;
+    }
+
+    pthread_attr_destroy(&attr);
+    return 0;
+}
+
+TEST(liblog, android_logger_list_read__cpu_thread) {
+    struct logger_list *logger_list;
+    unsigned long long v = 0xDEADBEAFA55A0000ULL;
+
+    pid_t pid = getpid();
+
+    v += pid & 0xFFFF;
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY, 1000, pid)));
+
+    int count = 0;
+
+    int signals = 0;
+
+    unsigned long long uticks_start;
+    unsigned long long sticks_start;
+    get_ticks(&uticks_start, &sticks_start);
+
+    const unsigned alarm_time = 10;
+
+    memset(&signal_time, 0, sizeof(signal_time));
+
+    signaled = 0;
+    EXPECT_EQ(0, start_thread());
+
+    signal(SIGALRM, caught_blocking_thread);
+    alarm(alarm_time);
+
+    do {
+        log_msg log_msg;
+        if (LOG_FAILURE_RETRY(android_logger_list_read(logger_list, &log_msg)) <= 0) {
+            break;
+        }
+
+        alarm(alarm_time);
+
+        ++count;
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != (4 + 1 + 8))
+         || (log_msg.id() != LOG_ID_EVENTS)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        if (eventData[4] != EVENT_TYPE_LONG) {
+            continue;
+        }
+
+        unsigned long long l = eventData[4 + 1 + 0] & 0xFF;
+        l |= (unsigned long long) (eventData[4 + 1 + 1] & 0xFF) << 8;
+        l |= (unsigned long long) (eventData[4 + 1 + 2] & 0xFF) << 16;
+        l |= (unsigned long long) (eventData[4 + 1 + 3] & 0xFF) << 24;
+        l |= (unsigned long long) (eventData[4 + 1 + 4] & 0xFF) << 32;
+        l |= (unsigned long long) (eventData[4 + 1 + 5] & 0xFF) << 40;
+        l |= (unsigned long long) (eventData[4 + 1 + 6] & 0xFF) << 48;
+        l |= (unsigned long long) (eventData[4 + 1 + 7] & 0xFF) << 56;
+
+        if (l == v) {
+            ++signals;
+            break;
+        }
+    } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
+    alarm(0);
+    signal(SIGALRM, SIG_DFL);
+
+    EXPECT_LE(1, count);
 
     EXPECT_EQ(1, signals);
 
@@ -1032,11 +1190,20 @@
         struct logger * logger;
         EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
         EXPECT_EQ(id, android_logger_get_id(logger));
-        EXPECT_LT(0, android_logger_get_log_size(logger));
-        /* crash buffer is allowed to be empty, that is actually healthy! */
-        if (android_logger_get_log_readable_size(logger) ||
-                (strcmp("crash", name) && strcmp("security", name))) {
-            EXPECT_LT(0, android_logger_get_log_readable_size(logger));
+        ssize_t get_log_size = android_logger_get_log_size(logger);
+        /* security buffer is allowed to be denied */
+        if (strcmp("security", name)) {
+            EXPECT_LT(0, get_log_size);
+            /* crash buffer is allowed to be empty, that is actually healthy! */
+            EXPECT_LE((strcmp("crash", name)) != 0,
+                      android_logger_get_log_readable_size(logger));
+        } else {
+            EXPECT_NE(0, get_log_size);
+            if (get_log_size < 0) {
+                EXPECT_GT(0, android_logger_get_log_readable_size(logger));
+            } else {
+                EXPECT_LE(0, android_logger_get_log_readable_size(logger));
+            }
         }
         EXPECT_LT(0, android_logger_get_log_version(logger));
     }
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 5ab6195..60834fe 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -43,7 +43,14 @@
 
     uint32_t tags_addr;    /* physical addr for kernel tags */
     uint32_t page_size;    /* flash page size we assume */
-    uint32_t unused[2];    /* future expansion: should be 0 */
+    uint32_t unused;       /* reserved for future expansion: MUST be 0 */
+
+    /* operating system version and security patch level; for
+     * version "A.B.C" and patch level "Y-M-D":
+     * ver = A << 14 | B << 7 | C         (7 bits for each of A, B, C)
+     * lvl = ((Y - 2000) & 127) << 4 | M  (7 bits for Y, 4 bits for M)
+     * os_version = ver << 11 | lvl */
+    uint32_t os_version;
 
     uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
 
diff --git a/mkbootimg/mkbootimg b/mkbootimg/mkbootimg
index f95d703..7b04bcc 100755
--- a/mkbootimg/mkbootimg
+++ b/mkbootimg/mkbootimg
@@ -20,6 +20,7 @@
 from struct import pack
 from hashlib import sha1
 import sys
+import re
 
 def filesize(f):
     if f is None:
@@ -47,7 +48,7 @@
 def write_header(args):
     BOOT_MAGIC = 'ANDROID!'.encode()
     args.output.write(pack('8s', BOOT_MAGIC))
-    args.output.write(pack('8I',
+    args.output.write(pack('10I',
         filesize(args.kernel),                          # size in bytes
         args.base + args.kernel_offset,                 # physical load addr
         filesize(args.ramdisk),                         # size in bytes
@@ -55,8 +56,9 @@
         filesize(args.second),                          # size in bytes
         args.base + args.second_offset,                 # physical load addr
         args.base + args.tags_offset,                   # physical addr for kernel tags
-        args.pagesize))                                 # flash page size we assume
-    args.output.write(pack('8x'))                       # future expansion: should be 0
+        args.pagesize,                                  # flash page size we assume
+        0,                                              # future expansion: MUST be 0
+        (args.os_version << 11) | args.os_patch_level)) # os version and patch level
     args.output.write(pack('16s', args.board.encode())) # asciiz product name
     args.output.write(pack('512s', args.cmdline[:512].encode()))
 
@@ -97,6 +99,32 @@
 def parse_int(x):
     return int(x, 0)
 
+def parse_os_version(x):
+    match = re.search(r'^(\d{1,3})(?:\.(\d{1,3})(?:\.(\d{1,3}))?)?', x)
+    if match:
+        a = parse_int(match.group(1))
+        b = c = 0
+        if match.lastindex >= 2:
+            b = parse_int(match.group(2))
+        if match.lastindex == 3:
+            c = parse_int(match.group(3))
+        # 7 bits allocated for each field
+        assert a < 128
+        assert b < 128
+        assert c < 128
+        return (a << 14) | (b << 7) | c
+    return 0
+
+def parse_os_patch_level(x):
+    match = re.search(r'^(\d{4})-(\d{2})-(\d{2})', x)
+    if match:
+        y = parse_int(match.group(1)) - 2000
+        m = parse_int(match.group(2))
+        # 7 bits allocated for the year, 4 bits for the month
+        assert y >= 0 and y < 128
+        assert m > 0 and m <= 12
+        return (y << 4) | m
+    return 0
 
 def parse_cmdline():
     parser = ArgumentParser()
@@ -111,6 +139,10 @@
     parser.add_argument('--ramdisk_offset', help='ramdisk offset', type=parse_int, default=0x01000000)
     parser.add_argument('--second_offset', help='2nd bootloader offset', type=parse_int,
                         default=0x00f00000)
+    parser.add_argument('--os_version', help='operating system version', type=parse_os_version,
+                        default=0)
+    parser.add_argument('--os_patch_level', help='operating system patch level',
+                        type=parse_os_patch_level, default=0)
     parser.add_argument('--tags_offset', help='tags offset', type=parse_int, default=0x00000100)
     parser.add_argument('--board', help='board name', default='', action=ValidateStrLenAction,
                         maxlen=16)
diff --git a/trusty/nvram/Android.mk b/trusty/nvram/Android.mk
new file mode 100644
index 0000000..18c54d5
--- /dev/null
+++ b/trusty/nvram/Android.mk
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2016 The Android Open-Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# nvram.trusty is the Trusty NVRAM HAL module.
+include $(CLEAR_VARS)
+LOCAL_MODULE := nvram.trusty
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+	module.c \
+	trusty_nvram_implementation.cpp
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -Wall -Werror -Wextra -fvisibility=hidden
+LOCAL_STATIC_LIBRARIES := libnvram-hal
+LOCAL_SHARED_LIBRARIES := libtrusty libnvram-messages liblog
+include $(BUILD_SHARED_LIBRARY)
diff --git a/trusty/nvram/module.c b/trusty/nvram/module.c
new file mode 100644
index 0000000..06819c0
--- /dev/null
+++ b/trusty/nvram/module.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/nvram.h>
+
+// This function is defined in trusty_nvram_implementation.cpp.
+int trusty_nvram_open(const hw_module_t* module,
+                      const char* device_id,
+                      hw_device_t** device_ptr);
+
+static struct hw_module_methods_t nvram_module_methods = {
+    .open = trusty_nvram_open,
+};
+
+struct nvram_module HAL_MODULE_INFO_SYM
+    __attribute__((visibility("default"))) = {
+        .common = {.tag = HARDWARE_MODULE_TAG,
+                   .module_api_version = NVRAM_MODULE_API_VERSION_0_1,
+                   .hal_api_version = HARDWARE_HAL_API_VERSION,
+                   .id = NVRAM_HARDWARE_MODULE_ID,
+                   .name = "Trusty NVRAM HAL",
+                   .author = "The Android Open Source Project",
+                   .methods = &nvram_module_methods,
+                   .dso = 0,
+                   .reserved = {}},
+};
diff --git a/trusty/nvram/trusty_nvram_implementation.cpp b/trusty/nvram/trusty_nvram_implementation.cpp
new file mode 100644
index 0000000..39496b4
--- /dev/null
+++ b/trusty/nvram/trusty_nvram_implementation.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <hardware/nvram.h>
+#include <trusty/tipc.h>
+
+#define LOG_TAG "TrustyNVRAM"
+#include <log/log.h>
+
+#include <nvram/hal/nvram_device_adapter.h>
+#include <nvram/messages/blob.h>
+#include <nvram/messages/nvram_messages.h>
+
+namespace {
+
+// Character device to open for Trusty IPC connections.
+const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
+
+// App identifier of the NVRAM app.
+const char kTrustyNvramAppId[] = "com.android.trusty.nvram";
+
+// |TrustyNvramImplementation| proxies requests to the Trusty NVRAM app. It
+// serializes the request objects, sends it to the Trusty app and finally reads
+// back the result and decodes it.
+class TrustyNvramImplementation : public nvram::NvramImplementation {
+ public:
+  ~TrustyNvramImplementation() override;
+
+  void Execute(const nvram::Request& request,
+               nvram::Response* response) override;
+
+ private:
+  // Connects the IPC channel to the Trusty app if it is not already open.
+  // Returns true if the channel is open, false on errors.
+  bool Connect();
+
+  // Dispatches a command to the trust app. Returns true if successful (note
+  // that the response may still indicate an error on the Trusty side), false if
+  // there are any I/O or encoding/decoding errors.
+  bool SendRequest(const nvram::Request& request,
+                   nvram::Response* response);
+
+  // The file descriptor for the IPC connection to the Trusty app.
+  int tipc_nvram_fd_ = -1;
+
+  // Response buffer. This puts a hard size limit on the responses from the
+  // Trusty app. 4096 matches the maximum IPC message size currently supported
+  // by Trusty.
+  uint8_t response_buffer_[4096];
+};
+
+TrustyNvramImplementation::~TrustyNvramImplementation() {
+  if (tipc_nvram_fd_ != -1) {
+    tipc_close(tipc_nvram_fd_);
+    tipc_nvram_fd_ = -1;
+  }
+}
+
+void TrustyNvramImplementation::Execute(const nvram::Request& request,
+                                        nvram::Response* response) {
+  if (!SendRequest(request, response)) {
+    response->result = NV_RESULT_INTERNAL_ERROR;
+  }
+}
+
+bool TrustyNvramImplementation::Connect() {
+  if (tipc_nvram_fd_ != -1) {
+    return true;
+  }
+
+  int rc = tipc_connect(kTrustyDeviceName, kTrustyNvramAppId);
+  if (rc < 0) {
+    ALOGE("Failed to connect to Trusty NVRAM app: %s\n", strerror(-rc));
+    return false;
+  }
+
+  tipc_nvram_fd_ = rc;
+  return true;
+}
+
+bool TrustyNvramImplementation::SendRequest(const nvram::Request& request,
+                                            nvram::Response* response) {
+  if (!Connect()) {
+    return false;
+  }
+
+  nvram::Blob request_buffer;
+  if (!nvram::Encode(request, &request_buffer)) {
+    ALOGE("Failed to encode NVRAM request.\n");
+    return false;
+  }
+
+  ssize_t rc =
+      write(tipc_nvram_fd_, request_buffer.data(), request_buffer.size());
+  if (rc < 0) {
+    ALOGE("Failed to send NVRAM request: %s\n", strerror(-rc));
+    return false;
+  }
+  if (static_cast<size_t>(rc) != request_buffer.size()) {
+    ALOGE("Failed to send full request buffer: %zd\n", rc);
+    return false;
+  }
+
+  rc = read(tipc_nvram_fd_, response_buffer_, sizeof(response_buffer_));
+  if (rc < 0) {
+    ALOGE("Failed to read NVRAM response: %s\n", strerror(-rc));
+    return false;
+  }
+
+  if (static_cast<size_t>(rc) >= sizeof(response_buffer_)) {
+    ALOGE("NVRAM response exceeds response buffer size.\n");
+    return false;
+  }
+
+  if (!nvram::Decode(response_buffer_, static_cast<size_t>(rc), response)) {
+    ALOGE("Failed to decode NVRAM response.\n");
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+extern "C" int trusty_nvram_open(const hw_module_t* module,
+                                 const char* device_id,
+                                 hw_device_t** device_ptr) {
+  if (strcmp(NVRAM_HARDWARE_DEVICE_ID, device_id) != 0) {
+    return -EINVAL;
+  }
+
+  nvram::NvramDeviceAdapter* adapter =
+      new nvram::NvramDeviceAdapter(module, new TrustyNvramImplementation);
+  *device_ptr = adapter->as_device();
+  return 0;
+}