jni: Android-specific custom logger for NFD

Change-Id: I4d98a58b8320735e40b5da3d358b9c71b558d995
Refs: #2508
diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk
index 7bae03f..bee4601 100644
--- a/app/src/main/jni/Android.mk
+++ b/app/src/main/jni/Android.mk
@@ -3,10 +3,12 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := nfd-wrapper
-LOCAL_SRC_FILES := android-logger-streambuf.cpp nfd-wrapper.cpp
+LOCAL_SRC_FILES := nfd-wrapper.cpp
+LOCAL_SHARED_LIBRARIES := nfd-daemon ndn-cxx boost_system_shared
 LOCAL_LDLIBS := -llog
-LOCAL_SHARED_LIBRARIES := nfd-daemon
 include $(BUILD_SHARED_LIBRARY)
 
 include $(LOCAL_PATH_SAVED)/ndn-cxx.mk
 include $(LOCAL_PATH_SAVED)/nfd.mk
+
+$(call import-module,boost/1.57.0)
diff --git a/app/src/main/jni/NFD b/app/src/main/jni/NFD
index e46279d..6f570de 160000
--- a/app/src/main/jni/NFD
+++ b/app/src/main/jni/NFD
@@ -1 +1 @@
-Subproject commit e46279dc8382316fb933697346b66f22cad1ee5e
+Subproject commit 6f570de8d7fdf36703cab0d1bf61c5ccff3b0143
diff --git a/app/src/main/jni/android-logger-streambuf.cpp b/app/src/main/jni/android-logger-streambuf.cpp
deleted file mode 100644
index f693501..0000000
--- a/app/src/main/jni/android-logger-streambuf.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2014-2015,  Regents of the University of California,
- *                           Arizona Board of Regents,
- *                           Colorado State University,
- *                           University Pierre & Marie Curie, Sorbonne University,
- *                           Washington University in St. Louis,
- *                           Beijing Institute of Technology,
- *                           The University of Memphis.
- *
- * This file is part of NFD (Named Data Networking Forwarding Daemon).
- * See AUTHORS.md for complete list of NFD authors and contributors.
- *
- * NFD is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE.  See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "android-logger-streambuf.hpp"
-
-#include <android/log.h>
-
-namespace nfd_android {
-
-AndroidLoggerStreambuf::AndroidLoggerStreambuf()
-{
-  this->setp(buffer, buffer + MAX_BUF_SIZE - 1);
-}
-
-int
-AndroidLoggerStreambuf::overflow(int c)
-{
-  if (c == traits_type::eof()) {
-    *this->pptr() = traits_type::to_char_type(c);
-    this->sbumpc();
-  }
-  return this->sync()? traits_type::eof(): traits_type::not_eof(c);
-}
-
-int
-AndroidLoggerStreambuf::sync()
-{
-  int rc = 0;
-  if (this->pbase() != this->pptr()) {
-    __android_log_print(ANDROID_LOG_INFO, "Native", "%s",
-                        std::string(this->pbase(), this->pptr() - this->pbase()).c_str());
-    rc = 0;
-    this->setp(buffer, buffer + MAX_BUF_SIZE - 1);
-  }
-  return rc;
-}
-
-} // namespace nfd_android
diff --git a/app/src/main/jni/ndn-cxx b/app/src/main/jni/ndn-cxx
index cf3a667..ea71967 160000
--- a/app/src/main/jni/ndn-cxx
+++ b/app/src/main/jni/ndn-cxx
@@ -1 +1 @@
-Subproject commit cf3a667634ef93c47c0ef3056a01c47112e49427
+Subproject commit ea71967f812be196a43c7704bf7fcf053f8533a7
diff --git a/app/src/main/jni/ndn-cxx.mk b/app/src/main/jni/ndn-cxx.mk
index 1e93bdb..0419abc 100644
--- a/app/src/main/jni/ndn-cxx.mk
+++ b/app/src/main/jni/ndn-cxx.mk
@@ -6,7 +6,86 @@
 NDN_CXX_BOOST_LIBS = system filesystem date_time iostreams program_options chrono random
 LOCAL_SHARED_LIBRARIES := cryptopp $(addsuffix _shared,$(addprefix boost_,$(NDN_CXX_BOOST_LIBS)))
 LOCAL_STATIC_LIBRARIES := sqlite3 boost_regex_static
-NDN_CXX_SRC_FILES := name.cpp util/dns.cpp util/time-unit-test-clock.cpp util/segment-fetcher.cpp util/config-file.cpp util/in-memory-storage.cpp util/in-memory-storage-lfu.cpp util/in-memory-storage-fifo.cpp util/ethernet.cpp util/crypto.cpp util/regex/regex-top-matcher.cpp util/signal-scoped-connection.cpp util/dummy-client-face.cpp util/scheduler.cpp util/indented-stream.cpp util/signal-connection.cpp util/in-memory-storage-persistent.cpp util/digest.cpp util/in-memory-storage-lru.cpp util/in-memory-storage-entry.cpp util/time.cpp util/random.cpp util/face-uri.cpp interest-filter.cpp signature.cpp transport/tcp-transport.cpp transport/unix-transport.cpp management/nfd-face-event-notification.cpp management/nfd-control-command.cpp management/nfd-command-options.cpp management/nfd-face-status.cpp management/nfd-control-response.cpp management/nfd-rib-entry.cpp management/nfd-controller.cpp management/nfd-forwarder-status.cpp management/nfd-channel-status.cpp management/nfd-fib-entry.cpp management/nfd-strategy-choice.cpp management/nfd-face-query-filter.cpp management/nfd-control-parameters.cpp exclude.cpp name-component.cpp face.cpp key-locator.cpp data.cpp interest.cpp selectors.cpp meta-info.cpp signature-info.cpp encoding/nfd-constants.cpp encoding/oid.cpp encoding/cryptopp/asn_ext.cpp encoding/block.cpp encoding/buffer.cpp security/sec-public-info-sqlite3.cpp security/signature-sha256-with-rsa.cpp security/public-key.cpp security/certificate-cache-ttl.cpp security/sec-rule-specific.cpp security/sec-tpm-file.cpp security/digest-sha256.cpp security/sec-public-info.cpp security/certificate.cpp security/identity-certificate.cpp security/certificate-subject-description.cpp security/certificate-extension.cpp security/sec-tpm.cpp security/validator.cpp security/sec-rule-relative.cpp security/key-params.cpp security/secured-bag.cpp security/key-chain.cpp security/signature-sha256-with-ecdsa.cpp security/validator-config.cpp security/validator-regex.cpp
+NDN_CXX_SRC_FILES := \
+    data.cpp \
+    encoding/block.cpp \
+    encoding/buffer.cpp \
+    encoding/cryptopp/asn_ext.cpp \
+    encoding/encoder.cpp \
+    encoding/estimator.cpp \
+    encoding/nfd-constants.cpp \
+    encoding/oid.cpp \
+    exclude.cpp \
+    face.cpp \
+    interest-filter.cpp \
+    interest.cpp \
+    key-locator.cpp \
+    management/nfd-channel-status.cpp \
+    management/nfd-command-options.cpp \
+    management/nfd-control-command.cpp \
+    management/nfd-control-parameters.cpp \
+    management/nfd-control-response.cpp \
+    management/nfd-controller.cpp \
+    management/nfd-face-event-notification.cpp \
+    management/nfd-face-query-filter.cpp \
+    management/nfd-face-status.cpp \
+    management/nfd-fib-entry.cpp \
+    management/nfd-forwarder-status.cpp \
+    management/nfd-rib-entry.cpp \
+    management/nfd-strategy-choice.cpp \
+    meta-info.cpp \
+    name-component.cpp \
+    name.cpp \
+    security/certificate-cache-ttl.cpp \
+    security/certificate-extension.cpp \
+    security/certificate-subject-description.cpp \
+    security/certificate.cpp \
+    security/digest-sha256.cpp \
+    security/identity-certificate.cpp \
+    security/key-chain.cpp \
+    security/key-params.cpp \
+    security/public-key.cpp \
+    security/sec-public-info-sqlite3.cpp \
+    security/sec-public-info.cpp \
+    security/sec-rule-relative.cpp \
+    security/sec-rule-specific.cpp \
+    security/sec-tpm-file.cpp \
+    security/sec-tpm.cpp \
+    security/secured-bag.cpp \
+    security/signature-sha256-with-ecdsa.cpp \
+    security/signature-sha256-with-rsa.cpp \
+    security/validator-config.cpp \
+    security/validator-regex.cpp \
+    security/validator.cpp \
+    selectors.cpp \
+    signature-info.cpp \
+    signature.cpp \
+    transport/tcp-transport.cpp \
+    transport/unix-transport.cpp \
+    util/config-file.cpp \
+    util/crypto.cpp \
+    util/digest.cpp \
+    util/dns.cpp \
+    util/dummy-client-face.cpp \
+    util/ethernet.cpp \
+    util/face-uri.cpp \
+    util/in-memory-storage-entry.cpp \
+    util/in-memory-storage-fifo.cpp \
+    util/in-memory-storage-lfu.cpp \
+    util/in-memory-storage-lru.cpp \
+    util/in-memory-storage-persistent.cpp \
+    util/in-memory-storage.cpp \
+    util/indented-stream.cpp \
+    util/network-monitor.cpp \
+    util/random.cpp \
+    util/regex/regex-top-matcher.cpp \
+    util/scheduler-scoped-event-id.cpp \
+    util/scheduler.cpp \
+    util/segment-fetcher.cpp \
+    util/signal-connection.cpp \
+    util/signal-scoped-connection.cpp \
+    util/time-unit-test-clock.cpp \
+    util/time.cpp
 LOCAL_SRC_FILES := $(addprefix ndn-cxx/src/,$(NDN_CXX_SRC_FILES))
 LOCAL_CPPFLAGS := -I$(LOCAL_PATH)/ndn-cxx/src -I$(LOCAL_PATH)/ndn-cxx-android
 LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/ndn-cxx-android
diff --git a/app/src/main/jni/nfd-android/config.hpp b/app/src/main/jni/nfd-android/config.hpp
index 78b3f8b..f26c0f6 100644
--- a/app/src/main/jni/nfd-android/config.hpp
+++ b/app/src/main/jni/nfd-android/config.hpp
@@ -8,5 +8,6 @@
 #define HAVE_LIBRESOLV
 /*#undef HAVE_UNIX_SOCKETS*/
 #define DEFAULT_CONFIG_FILE "./nfd.conf"
+#define HAVE_CUSTOM_LOGGER 1
 
 #endif /* W_CONFIG_HPP_WAF */
diff --git a/app/src/main/jni/nfd-android/custom-logger-factory.cpp b/app/src/main/jni/nfd-android/custom-logger-factory.cpp
new file mode 100644
index 0000000..f84a663
--- /dev/null
+++ b/app/src/main/jni/nfd-android/custom-logger-factory.cpp
@@ -0,0 +1,213 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014  Regents of the University of California,
+ *                     Arizona Board of Regents,
+ *                     Colorado State University,
+ *                     University Pierre & Marie Curie, Sorbonne University,
+ *                     Washington University in St. Louis,
+ *                     Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "custom-logger-factory.hpp"
+
+namespace nfd {
+
+NFD_LOG_INIT("LoggerFactory");
+
+LoggerFactory&
+LoggerFactory::getInstance()
+{
+  static LoggerFactory globalLoggerFactory;
+
+  return globalLoggerFactory;
+}
+
+LoggerFactory::LoggerFactory()
+  : m_defaultLevel(LOG_INFO)
+{
+  m_levelNames["NONE"] = LOG_NONE;
+  m_levelNames["ERROR"] = LOG_ERROR;
+  m_levelNames["WARN"] = LOG_WARN;
+  m_levelNames["INFO"] = LOG_INFO;
+  m_levelNames["DEBUG"] = LOG_DEBUG;
+  m_levelNames["TRACE"] = LOG_TRACE;
+  m_levelNames["ALL"] = LOG_ALL;
+}
+
+void
+LoggerFactory::setConfigFile(ConfigFile& config)
+{
+  config.addSectionHandler("log", bind(&LoggerFactory::onConfig, this, _1, _2, _3));
+}
+
+LogLevel
+LoggerFactory::parseLevel(const std::string& level)
+{
+  std::string upperLevel = level;
+  boost::to_upper(upperLevel);
+
+  // std::cerr << "parsing level: " << upperLevel << std::endl;;
+  // std::cerr << "# levels: " << m_levelNames.size() << std::endl;
+  // std::cerr << m_levelNames.begin()->first << std::endl;
+
+  LevelMap::const_iterator levelIt = m_levelNames.find(upperLevel);
+  if (levelIt != m_levelNames.end())
+    {
+      return levelIt->second;
+    }
+  try
+    {
+      uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
+
+      if ((boost::lexical_cast<uint32_t>(LOG_NONE) <= levelNo &&
+           levelNo <= boost::lexical_cast<uint32_t>(LOG_TRACE)) ||
+          levelNo == LOG_ALL)
+        {
+          return static_cast<LogLevel>(levelNo);
+        }
+    }
+  catch (const boost::bad_lexical_cast& error)
+    {
+    }
+  throw LoggerFactory::Error("Unsupported logging level \"" +
+                             level + "\"");
+}
+
+LogLevel
+LoggerFactory::extractLevel(const ConfigSection& item, const std::string& key)
+{
+  std::string levelString;
+  try
+    {
+      levelString = item.get_value<std::string>();
+    }
+  catch (const boost::property_tree::ptree_error& error)
+    {
+    }
+
+  if (levelString.empty())
+    {
+      throw LoggerFactory::Error("No logging level found for option \"" + key + "\"");
+    }
+
+  return parseLevel(levelString);
+}
+
+void
+LoggerFactory::onConfig(const ConfigSection& section,
+                        bool isDryRun,
+                        const std::string& filename)
+{
+// log
+// {
+//   ; default_level specifies the logging level for modules
+//   ; that are not explicitly named. All debugging levels
+//   ; listed above the selected value are enabled.
+//
+//   default_level INFO
+//
+//   ; You may also override the default for specific modules:
+//
+//   FibManager DEBUG
+//   Forwarder WARN
+// }
+
+  if (!isDryRun)
+    {
+      ConfigSection::const_assoc_iterator item = section.find("default_level");
+      if (item != section.not_found())
+        {
+          LogLevel level = extractLevel(item->second, "default_level");
+          setDefaultLevel(level);
+        }
+      else
+        {
+          setDefaultLevel(LOG_INFO);
+        }
+    }
+
+  for (ConfigSection::const_iterator item = section.begin();
+       item != section.end();
+       ++item)
+    {
+      LogLevel level = extractLevel(item->second, item->first);
+
+      if (item->first == "default_level")
+        {
+          // do nothing
+        }
+      else
+        {
+          LoggerMap::iterator loggerIt = m_loggers.find(item->first);
+          if (loggerIt == m_loggers.end())
+            {
+              NFD_LOG_DEBUG("Failed to configure logging level for module \"" <<
+                            item->first << "\" (module not found)");
+            }
+          else if (!isDryRun)
+            {
+              // std::cerr << "changing level for module " << item->first << " to " << level << std::endl;
+              loggerIt->second.setLogLevel(level);
+            }
+        }
+    }
+}
+
+void
+LoggerFactory::setDefaultLevel(LogLevel level)
+{
+  // std::cerr << "changing to default_level " << level << std::endl;
+
+  m_defaultLevel = level;
+  for (LoggerMap::iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
+    {
+      // std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
+      i->second.setLogLevel(m_defaultLevel);
+    }
+}
+
+Logger&
+LoggerFactory::create(const std::string& moduleName)
+{
+  return LoggerFactory::getInstance().createLogger(moduleName);
+}
+
+Logger&
+LoggerFactory::createLogger(const std::string& moduleName)
+{
+  // std::cerr << "creating logger for " << moduleName
+  //           << " with level " << m_defaultLevel << std::endl;
+
+  std::pair<LoggerMap::iterator, bool> loggerIt =
+    m_loggers.insert(NameAndLogger(moduleName, Logger(moduleName, m_defaultLevel)));
+
+  return loggerIt.first->second;
+}
+
+std::list<std::string>
+LoggerFactory::getModules() const
+{
+  std::list<std::string> modules;
+  for (LoggerMap::const_iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
+    {
+      modules.push_back(i->first);
+    }
+
+  return modules;
+}
+
+} // namespace nfd
diff --git a/app/src/main/jni/nfd-android/custom-logger-factory.hpp b/app/src/main/jni/nfd-android/custom-logger-factory.hpp
new file mode 100644
index 0000000..394c90b
--- /dev/null
+++ b/app/src/main/jni/nfd-android/custom-logger-factory.hpp
@@ -0,0 +1,111 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014  Regents of the University of California,
+ *                     Arizona Board of Regents,
+ *                     Colorado State University,
+ *                     University Pierre & Marie Curie, Sorbonne University,
+ *                     Washington University in St. Louis,
+ *                     Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_ANDROID_CUSTOM_LOGGER_FACTORY_HPP
+#define NFD_ANDROID_CUSTOM_LOGGER_FACTORY_HPP
+
+#include "common.hpp"
+
+#include "config-file.hpp"
+#include "logger.hpp"
+
+namespace nfd {
+
+class LoggerFactory : noncopyable
+{
+public:
+
+  class Error : public std::runtime_error
+  {
+  public:
+    explicit
+    Error(const std::string& error)
+      : std::runtime_error(error)
+    {
+    }
+  };
+
+  static LoggerFactory&
+  getInstance();
+
+  void
+  setConfigFile(ConfigFile& config);
+
+  void
+  onConfig(const ConfigSection& section, bool isDryRun, const std::string& filename);
+
+  std::list<std::string>
+  getModules() const;
+
+  static Logger&
+  create(const std::string& moduleName);
+
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+
+  // these methods are used during unit-testing
+
+  LogLevel
+  getDefaultLevel() const;
+
+  void
+  setDefaultLevel(LogLevel level);
+
+private:
+
+  LoggerFactory();
+
+  Logger&
+  createLogger(const std::string& moduleName);
+
+  LogLevel
+  parseLevel(const std::string& level);
+
+  LogLevel
+  extractLevel(const ConfigSection& item, const std::string& key);
+
+private:
+
+  typedef std::map<std::string, LogLevel> LevelMap;
+  typedef std::pair<std::string, LogLevel> NameAndLevel;
+
+  LevelMap m_levelNames;
+
+  typedef std::map<std::string, Logger> LoggerMap;
+  typedef std::pair<std::string, Logger> NameAndLogger;
+
+  LoggerMap m_loggers;
+
+  LogLevel m_defaultLevel;
+};
+
+inline LogLevel
+LoggerFactory::getDefaultLevel() const
+{
+  return m_defaultLevel;
+}
+
+} // namespace nfd
+
+#endif // NFD_ANDROID_CUSTOM_LOGGER_FACTORY_HPP
diff --git a/app/src/main/jni/android-logger-streambuf.hpp b/app/src/main/jni/nfd-android/custom-logger.cpp
similarity index 68%
rename from app/src/main/jni/android-logger-streambuf.hpp
rename to app/src/main/jni/nfd-android/custom-logger.cpp
index 6ca2500..6b5d3ae 100644
--- a/app/src/main/jni/android-logger-streambuf.hpp
+++ b/app/src/main/jni/nfd-android/custom-logger.cpp
@@ -23,35 +23,14 @@
  * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifndef NFD_ANDROID_JNI_ANDROID_LOG_HPP
-#define NFD_ANDROID_JNI_ANDROID_LOG_HPP
+#include "custom-logger.hpp"
 
-#include <streambuf>
+namespace nfd {
 
-namespace nfd_android {
-
-/**
- * @brief Streambuf implementation to redirect to streams to Android logging facility
- *
- * Based on code from http://stackoverflow.com/a/8870278/2150331
- */
-class AndroidLoggerStreambuf : public std::streambuf
+Logger::Logger(const std::string& name, LogLevel level)
+  : m_moduleName(name)
+  , m_enabledLogLevel(level)
 {
-public:
-  AndroidLoggerStreambuf();
+}
 
-protected:
-  virtual int
-  overflow(int c);
-
-  virtual int
-  sync();
-
-private:
-  enum { MAX_BUF_SIZE = 1024 };
-  char buffer[MAX_BUF_SIZE];
-};
-
-} // namespace nfd_android
-
-#endif // NFD_ANDROID_JNI_ANDROID_LOG_HPP
+} // namespace nfd
diff --git a/app/src/main/jni/nfd-android/custom-logger.hpp b/app/src/main/jni/nfd-android/custom-logger.hpp
new file mode 100644
index 0000000..5355657
--- /dev/null
+++ b/app/src/main/jni/nfd-android/custom-logger.hpp
@@ -0,0 +1,140 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014,  Regents of the University of California,
+ *                      Arizona Board of Regents,
+ *                      Colorado State University,
+ *                      University Pierre & Marie Curie, Sorbonne University,
+ *                      Washington University in St. Louis,
+ *                      Beijing Institute of Technology,
+ *                      The University of Memphis
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef NFD_ANDROID_CUSTOM_LOGGER_HPP
+#define NFD_ANDROID_CUSTOM_LOGGER_HPP
+
+#include "common.hpp"
+#include <android/log.h>
+
+namespace nfd {
+
+/** \brief indicates a log level
+ *  \note This type is internal. Logger should be accessed through NFD_LOG_* macros.
+ */
+enum LogLevel {
+  LOG_FATAL          = -1, // fatal (will be logged unconditionally)
+  LOG_NONE           = 0, // no messages
+  LOG_ERROR          = 1, // serious error messages
+  LOG_WARN           = 2, // warning messages
+  LOG_INFO           = 3, // informational messages
+  LOG_DEBUG          = 4, // debug messages
+  LOG_TRACE          = 5, // trace messages (most verbose)
+  LOG_ALL            = 255 // all messages
+};
+
+/** \brief provides logging for a module
+ *  \note This type is internal. Logger should be accessed through NFD_LOG_* macros.
+ *  \note This type is copyable because logger can be declared as a field of
+ *        (usually template) classes, and shouldn't prevent those classes to be copyable.
+ */
+class Logger
+{
+public:
+  Logger(const std::string& name, LogLevel level);
+
+  bool
+  isEnabled(LogLevel level) const
+  {
+    return m_enabledLogLevel >= level;
+  }
+
+  void
+  setLogLevel(LogLevel level)
+  {
+    m_enabledLogLevel = level;
+  }
+
+  const std::string&
+  getName() const
+  {
+    return m_moduleName;
+  }
+
+  void
+  setName(const std::string& name)
+  {
+    m_moduleName = name;
+  }
+
+private:
+  std::string m_moduleName;
+  LogLevel    m_enabledLogLevel;
+};
+
+inline std::ostream&
+operator<<(std::ostream& output, const Logger& logger)
+{
+  output << logger.getName();
+  return output;
+}
+
+} // namespace nfd
+
+#include "core/logger-factory.hpp"
+
+namespace nfd {
+
+#define NFD_LOG_INIT(name) \
+static nfd::Logger& g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_DECLARE() \
+static nfd::Logger& g_logger
+
+#define NFD_LOG_INCLASS_DEFINE(cls, name) \
+nfd::Logger& cls::g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_TEMPLATE_DEFINE(cls, name) \
+template<class T>                                  \
+nfd::Logger& cls<T>::g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(cls, specialization, name) \
+template<>                                                                        \
+nfd::Logger& cls<specialization>::g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(cls, s1, s2, name) \
+template<>                                                                 \
+nfd::Logger& cls<s1, s2>::g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG(nfdLevel, androidLevel, msg, expression)                \
+do {                                                                    \
+  if (g_logger.isEnabled(::nfd::LOG_##nfdLevel)) {                      \
+    std::ostringstream os;                                              \
+    os << expression;                                                   \
+    __android_log_print(ANDROID_LOG_##androidLevel,                     \
+                        g_logger.getName().c_str(), "%s", os.str().c_str()); \
+  }                                                                     \
+} while (false)
+
+#define NFD_LOG_TRACE(expression) NFD_LOG(TRACE, VERBOSE, TRACE, expression)
+#define NFD_LOG_DEBUG(expression) NFD_LOG(DEBUG, DEBUG, DEBUG,   expression)
+#define NFD_LOG_INFO(expression)  NFD_LOG(INFO,  INFO,  INFO,    expression)
+#define NFD_LOG_WARN(expression)  NFD_LOG(WARN,  WARN,  WARNING, expression)
+#define NFD_LOG_ERROR(expression) NFD_LOG(ERROR, ERROR, ERROR,   expression)
+#define NFD_LOG_FATAL(expression) NFD_LOG(FATAL, FATAL, FATAL,   expression)
+
+} // namespace nfd
+
+#endif // NFD_ANDROID_CUSTOM_LOGGER_HPP
diff --git a/app/src/main/jni/nfd-android/version.hpp b/app/src/main/jni/nfd-android/version.hpp
index d9aa54a..afa7ae1 100644
--- a/app/src/main/jni/nfd-android/version.hpp
+++ b/app/src/main/jni/nfd-android/version.hpp
@@ -38,13 +38,13 @@
  *
  *  MAJOR*1000000 + MINOR*1000 + PATCH
  */
-#define NFD_VERSION 2000
+#define NFD_VERSION 3000
 
 /** \brief NFD version represented as a string
  *
  *  MAJOR.MINOR.PATCH
  */
-#define NFD_VERSION_STRING "0.2.0"
+#define NFD_VERSION_STRING "0.3.0"
 
 /** \brief NFD version string, including git commit information, if NFD is build from
  *         specific git commit
@@ -60,12 +60,12 @@
  *
  * Example, 0.1.0-rc1-1-g5c86570
  */
-#define NFD_VERSION_BUILD_STRING "0.2.0-134-gde88b46"
+#define NFD_VERSION_BUILD_STRING "0.3.0-8-g6f570de"
 
 /// MAJOR version
 #define NFD_VERSION_MAJOR 0
 /// MINOR version
-#define NFD_VERSION_MINOR 2
+#define NFD_VERSION_MINOR 3
 /// PATCH version
 #define NFD_VERSION_PATCH 0
 
diff --git a/app/src/main/jni/nfd-wrapper.cpp b/app/src/main/jni/nfd-wrapper.cpp
index 6a6e3cd..8b8dafc 100644
--- a/app/src/main/jni/nfd-wrapper.cpp
+++ b/app/src/main/jni/nfd-wrapper.cpp
@@ -18,23 +18,154 @@
  */
 
 #include "nfd-wrapper.hpp"
-#include "android-logger-streambuf.hpp"
 
-extern "C" {
-int
-main(int argc, char** argv);
-}
+#include "daemon/nfd.hpp"
+#include "rib/nrd.hpp"
 
-#include <iostream>
+#include "core/global-io.hpp"
+#include "core/config-file.hpp"
+#include "core/logger.hpp"
+
+#include <boost/property_tree/info_parser.hpp>
+
+NFD_LOG_INIT("NfdWrapper");
+
+namespace nfd {
+
+class Runner
+{
+public:
+  Runner()
+  {
+    std::string initialConfig =
+      "general\n"
+      "{\n"
+      "}\n"
+      "\n"
+      "log\n"
+      "{\n"
+      "  default_level INFO\n"
+      "}\n"
+      "tables\n"
+      "{\n"
+      "  cs_max_packets 100\n"
+      "\n"
+      "  strategy_choice\n"
+      "  {\n"
+      "    /               /localhost/nfd/strategy/best-route\n"
+      "    /localhost      /localhost/nfd/strategy/broadcast\n"
+      "    /localhost/nfd  /localhost/nfd/strategy/best-route\n"
+      "    /ndn/broadcast  /localhost/nfd/strategy/broadcast\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "face_system\n"
+      "{\n"
+      "  tcp\n"
+      "  {\n"
+      "    port 6363\n"
+      "  }\n"
+      "\n"
+      "  udp\n"
+      "  {\n"
+      "    port 6363\n"
+      "    idle_timeout 600\n"
+      "    keep_alive_interval 25\n"
+      "    mcast no\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "authorizations\n"
+      "{\n"
+      "  authorize\n"
+      "  {\n"
+      "    certfile any\n"
+      "    privileges\n"
+      "    {\n"
+      "      faces\n"
+      "      fib\n"
+      "      strategy-choice\n"
+      "    }\n"
+      "  }\n"
+      "}\n"
+      "\n"
+      "rib\n"
+      "{\n"
+      "  localhost_security\n"
+      "  {\n"
+      "    trust-anchor\n"
+      "    {\n"
+      "      type any\n"
+      "    }\n"
+      "  }\n"
+      "}\n"
+      "  remote_register\n"
+      "  {\n"
+      "    cost 15\n"
+      "    timeout 10000\n"
+      "    retry 0\n"
+      "    refresh_interval 300\n"
+      "  }\n"
+      "\n";
+
+    std::istringstream input(initialConfig);
+    boost::property_tree::read_info(input, m_config);
+
+    m_nfd.reset(new Nfd(initialConfig, m_keyChain));
+    m_nrd.reset(new rib::Nrd(initialConfig, m_keyChain));
+
+    m_nfd->initialize();
+    m_nrd->initialize();
+  }
+
+  void
+  run()
+  {
+  }
+
+  void
+  stop()
+  {
+  }
+
+private:
+  ndn::KeyChain m_keyChain;
+  unique_ptr<Nfd> m_nfd; // will use globalIoService
+  unique_ptr<rib::Nrd> m_nrd; // will use globalIoService
+
+  nfd::ConfigSection m_config;
+};
+
+static unique_ptr<Runner> g_runner;
+
+} // namespace nfd
 
 JNIEXPORT void JNICALL
 Java_net_named_1data_nfd_wrappers_NfdWrapper_startNfd(JNIEnv *, jclass)
 {
+  if (nfd::g_runner.get() == nullptr) {
+    try {
+      nfd::g_runner.reset(new nfd::Runner());
+      nfd::g_runner.reset();
+    }
+    catch (const std::exception& e) {
+      NFD_LOG_FATAL(e.what());
+    }
+  }
 
+  if (nfd::g_runner.get() == nullptr) {
+    return;
+  }
+
+  nfd::g_runner->run();
 }
 
 JNIEXPORT void JNICALL
 Java_net_named_1data_nfd_wrappers_NfdWrapper_stopNfd(JNIEnv *, jclass)
 {
-
+  if (nfd::g_runner.get() == nullptr) {
+    return;
+  }
+  nfd::g_runner->stop();
+  nfd::g_runner.reset();
 }
diff --git a/app/src/main/jni/nfd.mk b/app/src/main/jni/nfd.mk
index 04cf7e3..2cacc03 100644
--- a/app/src/main/jni/nfd.mk
+++ b/app/src/main/jni/nfd.mk
@@ -7,8 +7,18 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := nfd-core
 LOCAL_SHARED_LIBRARIES := cryptopp ndn-cxx $(addsuffix _shared,$(addprefix boost_,$(NFD_BOOST_LIBS)))
-NFD_CORE_SRC_FILES := core/network.cpp core/config-file.cpp core/network-interface.cpp core/logger-factory.cpp core/privilege-helper.cpp core/city-hash.cpp core/scheduler.cpp core/global-io.cpp core/logger.cpp core/random.cpp
-LOCAL_SRC_FILES := $(addprefix NFD/,$(NFD_CORE_SRC_FILES))
+NFD_CORE_SRC_FILES := \
+    core/city-hash.cpp \
+    core/config-file.cpp \
+    core/global-io.cpp \
+    core/network-interface.cpp \
+    core/network.cpp \
+    core/privilege-helper.cpp \
+    core/random.cpp \
+    core/scheduler.cpp
+LOCAL_SRC_FILES := $(addprefix NFD/,$(NFD_CORE_SRC_FILES)) \
+    nfd-android/custom-logger.cpp \
+    nfd-android/custom-logger-factory.cpp
 LOCAL_CPPFLAGS := -I$(LOCAL_PATH)/nfd-android -I$(LOCAL_PATH)/NFD -I$(LOCAL_PATH)/NFD/core
 LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/nfd-android $(LOCAL_PATH)/NFD $(LOCAL_PATH)/NFD/core
 include $(BUILD_STATIC_LIBRARY)
@@ -18,17 +28,78 @@
 LOCAL_MODULE := nfd-daemon
 LOCAL_SHARED_LIBRARIES := cryptopp ndn-cxx $(addsuffix _shared,$(addprefix boost_,$(NFD_BOOST_LIBS)))
 LOCAL_STATIC_LIBRARIES := nfd-core
-NFD_DAEMON_SRC_FILES := daemon/face/ndnlp-sequence-generator.cpp daemon/face/udp-channel.cpp daemon/face/ndnlp-partial-message-store.cpp daemon/face/ndnlp-parse.cpp daemon/face/face.cpp daemon/face/null-face.cpp daemon/face/tcp-factory.cpp daemon/face/ndnlp-slicer.cpp daemon/face/udp-face.cpp daemon/face/multicast-udp-face.cpp daemon/face/channel.cpp daemon/face/tcp-channel.cpp daemon/face/tcp-face.cpp daemon/face/udp-factory.cpp daemon/main.cpp daemon/table/measurements-accessor.cpp daemon/table/pit-out-record.cpp daemon/table/fib-entry.cpp daemon/table/pit-in-record.cpp daemon/table/measurements-entry.cpp daemon/table/strategy-choice.cpp daemon/table/cs-entry.cpp daemon/table/pit.cpp daemon/table/measurements.cpp daemon/table/strategy-info-host.cpp daemon/table/pit-face-record.cpp daemon/table/fib.cpp daemon/table/cs-entry-impl.cpp daemon/table/fib-nexthop.cpp daemon/table/name-tree.cpp daemon/table/name-tree-entry.cpp daemon/table/cs.cpp daemon/table/pit-entry.cpp daemon/table/strategy-choice-entry.cpp daemon/table/cs-skip-list-entry.cpp daemon/table/dead-nonce-list.cpp daemon/fw/access-strategy.cpp daemon/fw/retransmission-suppression.cpp daemon/fw/strategy.cpp daemon/fw/rtt-estimator.cpp daemon/fw/broadcast-strategy.cpp daemon/fw/client-control-strategy.cpp daemon/fw/best-route-strategy.cpp daemon/fw/face-table.cpp daemon/fw/ncc-strategy.cpp daemon/fw/forwarder.cpp daemon/fw/best-route-strategy2.cpp daemon/fw/available-strategies.cpp daemon/mgmt/status-server.cpp daemon/mgmt/tables-config-section.cpp daemon/mgmt/channel-status-publisher.cpp daemon/mgmt/strategy-choice-publisher.cpp daemon/mgmt/general-config-section.cpp daemon/mgmt/command-validator.cpp daemon/mgmt/internal-face.cpp daemon/mgmt/fib-enumeration-publisher.cpp daemon/mgmt/face-manager.cpp daemon/mgmt/manager-base.cpp daemon/mgmt/face-status-publisher.cpp daemon/mgmt/strategy-choice-manager.cpp daemon/mgmt/face-query-status-publisher.cpp daemon/mgmt/fib-manager.cpp
+NFD_DAEMON_SRC_FILES := \
+    daemon/face/channel.cpp \
+    daemon/face/face.cpp \
+    daemon/face/multicast-udp-face.cpp \
+    daemon/face/ndnlp-parse.cpp \
+    daemon/face/ndnlp-partial-message-store.cpp \
+    daemon/face/ndnlp-sequence-generator.cpp \
+    daemon/face/ndnlp-slicer.cpp \
+    daemon/face/null-face.cpp \
+    daemon/face/tcp-channel.cpp \
+    daemon/face/tcp-face.cpp \
+    daemon/face/tcp-factory.cpp \
+    daemon/face/udp-channel.cpp \
+    daemon/face/udp-face.cpp \
+    daemon/face/udp-factory.cpp \
+    daemon/fw/access-strategy.cpp \
+    daemon/fw/available-strategies.cpp \
+    daemon/fw/best-route-strategy.cpp \
+    daemon/fw/best-route-strategy2.cpp \
+    daemon/fw/broadcast-strategy.cpp \
+    daemon/fw/client-control-strategy.cpp \
+    daemon/fw/face-table.cpp \
+    daemon/fw/forwarder.cpp \
+    daemon/fw/ncc-strategy.cpp \
+    daemon/fw/retx-suppression-fixed.cpp \
+    daemon/fw/rtt-estimator.cpp \
+    daemon/fw/strategy.cpp \
+    daemon/nfd.cpp \
+    daemon/mgmt/channel-status-publisher.cpp \
+    daemon/mgmt/command-validator.cpp \
+    daemon/mgmt/face-manager.cpp \
+    daemon/mgmt/face-query-status-publisher.cpp \
+    daemon/mgmt/face-status-publisher.cpp \
+    daemon/mgmt/fib-enumeration-publisher.cpp \
+    daemon/mgmt/fib-manager.cpp \
+    daemon/mgmt/general-config-section.cpp \
+    daemon/mgmt/internal-face.cpp \
+    daemon/mgmt/manager-base.cpp \
+    daemon/mgmt/status-server.cpp \
+    daemon/mgmt/strategy-choice-manager.cpp \
+    daemon/mgmt/strategy-choice-publisher.cpp \
+    daemon/mgmt/tables-config-section.cpp \
+    daemon/table/cs-entry-impl.cpp \
+    daemon/table/cs-entry.cpp \
+    daemon/table/cs-skip-list-entry.cpp \
+    daemon/table/cs.cpp \
+    daemon/table/dead-nonce-list.cpp \
+    daemon/table/fib-entry.cpp \
+    daemon/table/fib-nexthop.cpp \
+    daemon/table/fib.cpp \
+    daemon/table/measurements-accessor.cpp \
+    daemon/table/measurements-entry.cpp \
+    daemon/table/measurements.cpp \
+    daemon/table/name-tree-entry.cpp \
+    daemon/table/name-tree.cpp \
+    daemon/table/pit-entry.cpp \
+    daemon/table/pit-face-record.cpp \
+    daemon/table/pit-in-record.cpp \
+    daemon/table/pit-out-record.cpp \
+    daemon/table/pit.cpp \
+    daemon/table/strategy-choice-entry.cpp \
+    daemon/table/strategy-choice.cpp \
+    daemon/table/strategy-info-host.cpp \
+    \
+    rib/fib-update.cpp \
+    rib/nrd.cpp \
+    rib/remote-registrator.cpp \
+    rib/rib-entry.cpp \
+    rib/rib-manager.cpp \
+    rib/rib-status-publisher.cpp \
+    rib/rib.cpp
 LOCAL_SRC_FILES := $(addprefix NFD/,$(NFD_DAEMON_SRC_FILES))
-LOCAL_CPPFLAGS := -I$(LOCAL_PATH)/NFD/daemon
-include $(BUILD_SHARED_LIBRARY)
-
-# rib manager
-include $(CLEAR_VARS)
-LOCAL_MODULE := nfd-rib
-LOCAL_SHARED_LIBRARIES := cryptopp ndn-cxx $(addsuffix _shared,$(addprefix boost_,$(NFD_BOOST_LIBS)))
-LOCAL_STATIC_LIBRARIES := nfd-core
-NFD_DAEMON_SRC_FILES := rib/fib-update.cpp rib/main.cpp rib/remote-registrator.cpp rib/rib-entry.cpp rib/rib-manager.cpp rib/rib-status-publisher.cpp rib/rib.cpp
-LOCAL_SRC_FILES := $(addprefix NFD/,$(NFD_DAEMON_SRC_FILES))
-LOCAL_CPPFLAGS := -I$(LOCAL_PATH)/NFD/rib
+LOCAL_CPPFLAGS := -I$(LOCAL_PATH)/NFD/daemon -I$(LOCAL_PATH)/NFD/rib
+LOCAL_LDLIBS := -llog
 include $(BUILD_SHARED_LIBRARY)