diff --git a/include/android/log.h b/include/android/log.h
index 1c171b7bf2b5d9e1bdc5a18bae28263e7885d055..391c826d5c6862594b3112a07b93198d3e2ee55d 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -88,6 +88,11 @@ typedef enum android_LogPriority {
     ANDROID_LOG_SILENT,     /* only for SetMinPriority(); must be last */
 } android_LogPriority;
 
+/*
+ * Release any logger resources (a new log write will immediately re-acquire)
+ */
+void __android_log_close();
+
 /*
  * Send a simple string to the log.
  */
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index b2668cedb7a272f55e72c53e0bd11a6e2a2223a9..6451abec0b8d5b6039e113f628bc2fec7080337b 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -282,6 +282,45 @@ const char *android_log_id_to_name(log_id_t log_id)
 }
 #endif
 
+/*
+ * Release any logger resources. A new log write will immediately re-acquire.
+ */
+void __android_log_close()
+{
+#if FAKE_LOG_DEVICE
+    int i;
+#endif
+
+#ifdef HAVE_PTHREADS
+    pthread_mutex_lock(&log_init_lock);
+#endif
+
+    write_to_log = __write_to_log_init;
+
+    /*
+     * Threads that are actively writing at this point are not held back
+     * by a lock and are at risk of dropping the messages with a return code
+     * -EBADF. Prefer to return error code than add the overhead of a lock to
+     * each log writing call to guarantee delivery. In addition, anyone
+     * calling this is doing so to release the logging resources and shut down,
+     * for them to do so with outstanding log requests in other threads is a
+     * disengenuous use of this function.
+     */
+#if FAKE_LOG_DEVICE
+    for (i = 0; i < LOG_ID_MAX; i++) {
+        fakeLogClose(log_fds[i]);
+        log_fds[i] = -1;
+    }
+#else
+    close(logd_fd);
+    logd_fd = -1;
+#endif
+
+#ifdef HAVE_PTHREADS
+    pthread_mutex_unlock(&log_init_lock);
+#endif
+}
+
 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
 {
 #ifdef HAVE_PTHREADS
diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c
index ae621cb13a63f4e3f84c21a47ce7762cbb422223..0b97d855044bbdb146ba663a3b73af50d4088963 100644
--- a/liblog/logd_write_kern.c
+++ b/liblog/logd_write_kern.c
@@ -117,6 +117,41 @@ static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr)
     return ret;
 }
 
+/*
+ * Release any logger resources. A new log write will immediately re-acquire.
+ */
+void __android_log_close()
+{
+#ifdef HAVE_PTHREADS
+    pthread_mutex_lock(&log_init_lock);
+#endif
+
+    write_to_log = __write_to_log_init;
+
+    /*
+     * Threads that are actively writing at this point are not held back
+     * by a lock and are at risk of dropping the messages with a return code
+     * -EBADF. Prefer to return error code than add the overhead of a lock to
+     * each log writing call to guarantee delivery. In addition, anyone
+     * calling this is doing so to release the logging resources and shut down,
+     * for them to do so with outstanding log requests in other threads is a
+     * disengenuous use of this function.
+     */
+
+    log_close(log_fds[LOG_ID_MAIN]);
+    log_fds[LOG_ID_MAIN] = -1;
+    log_close(log_fds[LOG_ID_RADIO]);
+    log_fds[LOG_ID_RADIO] = -1;
+    log_close(log_fds[LOG_ID_EVENTS]);
+    log_fds[LOG_ID_EVENTS] = -1;
+    log_close(log_fds[LOG_ID_SYSTEM]);
+    log_fds[LOG_ID_SYSTEM] = -1;
+
+#ifdef HAVE_PTHREADS
+    pthread_mutex_unlock(&log_init_lock);
+#endif
+}
+
 static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
 {
 #ifdef HAVE_PTHREADS
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index b43a90295dc772d97486e3f08be44e986b022ecf..61e226e96eca89c6608ff89169b4cdc45b9470a3 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -124,12 +124,17 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) {
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
         LOG_ID_EVENTS, O_RDONLY | O_NDELAY, 1000, pid)));
 
+    // Check that we can close and reopen the logger
     log_time ts(CLOCK_MONOTONIC);
-
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
+    __android_log_close();
+
+    log_time ts1(CLOCK_MONOTONIC);
+    ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
     usleep(1000000);
 
     int count = 0;
+    int second_count = 0;
 
     for (;;) {
         log_msg log_msg;
@@ -153,10 +158,13 @@ TEST(liblog, __android_log_btwrite__android_logger_list_read) {
         log_time tx(eventData + 4 + 1);
         if (ts == tx) {
             ++count;
+        } else if (ts1 == tx) {
+            ++second_count;
         }
     }
 
     EXPECT_EQ(1, count);
+    EXPECT_EQ(1, second_count);
 
     android_logger_list_close(logger_list);
 }