jni: Initial implementation for NFD start/stop facility

Current limitations:
- fixed configuration

Change-Id: Ia6b47cc682f133c9c504b24211855e1904f2236e
Refs: #2509
diff --git a/.gitmodules b/.gitmodules
index 6ce4745..97b91e7 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,13 +1,13 @@
-[submodule "app/src/main/jni/ndn-cxx"]
-	path = app/src/main/jni/ndn-cxx
-	url = https://github.com/named-data/ndn-cxx
 [submodule "app/src/main/jni/cryptopp"]
-	path = app/src/main/jni/cryptopp
-	url = http://github.com/cawka/cryptopp
-	branch = android
+    path = app/src/main/jni/cryptopp
+    url = http://github.com/cawka/cryptopp
+    branch = android
 [submodule "app/src/main/jni/sqlite3"]
-	path = app/src/main/jni/sqlite3
-	url = https://github.com/cawka/sqlite3-android.git
+    path = app/src/main/jni/sqlite3
+    url = https://github.com/cawka/sqlite3-android.git
+[submodule "app/src/main/jni/ndn-cxx"]
+    path = app/src/main/jni/ndn-cxx
+    url = ../ndn-cxx
 [submodule "app/src/main/jni/NFD"]
-	path = app/src/main/jni/NFD
-	url = https://github.com/named-data/NFD
+    path = app/src/main/jni/NFD
+    url = ../NFD
diff --git a/app/src/main/java/net/named_data/nfd/NfdMainActivity.java b/app/src/main/java/net/named_data/nfd/NfdMainActivity.java
index b429e43..76711b4 100644
--- a/app/src/main/java/net/named_data/nfd/NfdMainActivity.java
+++ b/app/src/main/java/net/named_data/nfd/NfdMainActivity.java
@@ -83,7 +83,7 @@
   public void startNfd(View view) {
     G.Log("Starting NFD through JNI ...");
 
-    NfdWrapper.startNfd();
+    NfdWrapper.startNfd(getFilesDir().getAbsolutePath());
   }
 
   public void stopNfd(View view) {
diff --git a/app/src/main/java/net/named_data/nfd/NfdSettingsActivity.java b/app/src/main/java/net/named_data/nfd/NfdSettingsActivity.java
index c288219..99cbfa0 100644
--- a/app/src/main/java/net/named_data/nfd/NfdSettingsActivity.java
+++ b/app/src/main/java/net/named_data/nfd/NfdSettingsActivity.java
@@ -35,11 +35,8 @@
 import android.preference.RingtonePreference;
 import android.text.TextUtils;
 
-
 import java.util.List;
 
-import net.named_data.nfd.wrappers.Example;
-
 /**
  * A {@link PreferenceActivity} that presents a set of application settings. On
  * handset devices, settings are presented as a single list. On tablets,
@@ -67,9 +64,6 @@
   {
     super.onPostCreate(savedInstanceState);
 
-    /// @todo Remove after the example no longer needed
-    Example.main();
-
     setupSimplePreferencesScreen();
   }
 
diff --git a/app/src/main/java/net/named_data/nfd/wrappers/Example.java b/app/src/main/java/net/named_data/nfd/wrappers/Example.java
deleted file mode 100644
index 62f2109..0000000
--- a/app/src/main/java/net/named_data/nfd/wrappers/Example.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.named_data.nfd.wrappers;
-
-/**
- * Created by cawka on 1/27/15.
- */
-public class Example
-{
-  static {
-    System.loadLibrary("nfd-wrapper");
-  }
-
-  public native static void main();
-}
diff --git a/app/src/main/java/net/named_data/nfd/wrappers/NfdWrapper.java b/app/src/main/java/net/named_data/nfd/wrappers/NfdWrapper.java
index ffad298..48172da 100644
--- a/app/src/main/java/net/named_data/nfd/wrappers/NfdWrapper.java
+++ b/app/src/main/java/net/named_data/nfd/wrappers/NfdWrapper.java
@@ -24,7 +24,7 @@
     }
 
     public native static void
-    startNfd();
+    startNfd(String homePath);
 
     public native static void
     stopNfd();
diff --git a/app/src/main/jni/Android.mk b/app/src/main/jni/Android.mk
index bee4601..3eed95a 100644
--- a/app/src/main/jni/Android.mk
+++ b/app/src/main/jni/Android.mk
@@ -4,7 +4,7 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := nfd-wrapper
 LOCAL_SRC_FILES := nfd-wrapper.cpp
-LOCAL_SHARED_LIBRARIES := nfd-daemon ndn-cxx boost_system_shared
+LOCAL_SHARED_LIBRARIES := nfd-daemon ndn-cxx boost_system_shared boost_thread_shared
 LOCAL_LDLIBS := -llog
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/app/src/main/jni/NFD b/app/src/main/jni/NFD
index 6f570de..90c20fa 160000
--- a/app/src/main/jni/NFD
+++ b/app/src/main/jni/NFD
@@ -1 +1 @@
-Subproject commit 6f570de8d7fdf36703cab0d1bf61c5ccff3b0143
+Subproject commit 90c20face84003b5a646f130e35bd04d60d70fdb
diff --git a/app/src/main/jni/nfd-android/version.hpp b/app/src/main/jni/nfd-android/version.hpp
index afa7ae1..c945a45 100644
--- a/app/src/main/jni/nfd-android/version.hpp
+++ b/app/src/main/jni/nfd-android/version.hpp
@@ -60,7 +60,7 @@
  *
  * Example, 0.1.0-rc1-1-g5c86570
  */
-#define NFD_VERSION_BUILD_STRING "0.3.0-8-g6f570de"
+#define NFD_VERSION_BUILD_STRING "0.3.0-18-g9a36c76"
 
 /// MAJOR version
 #define NFD_VERSION_MAJOR 0
diff --git a/app/src/main/jni/nfd-wrapper.cpp b/app/src/main/jni/nfd-wrapper.cpp
index 8b8dafc..5142965 100644
--- a/app/src/main/jni/nfd-wrapper.cpp
+++ b/app/src/main/jni/nfd-wrapper.cpp
@@ -25,17 +25,35 @@
 #include "core/global-io.hpp"
 #include "core/config-file.hpp"
 #include "core/logger.hpp"
+#include "core/privilege-helper.hpp"
 
+#include <stdlib.h>
 #include <boost/property_tree/info_parser.hpp>
+#include <boost/thread.hpp>
+#include <mutex>
 
 NFD_LOG_INIT("NfdWrapper");
 
 namespace nfd {
 
+
+// A little bit of cheating to make sure NFD can be properly restarted
+
+namespace scheduler {
+// defined in scheduler.cpp
+void
+resetGlobalScheduler();
+} // namespace scheduler
+
+void
+resetGlobalIoService();
+
+
 class Runner
 {
 public:
   Runner()
+    : m_io(nullptr)
   {
     std::string initialConfig =
       "general\n"
@@ -44,7 +62,13 @@
       "\n"
       "log\n"
       "{\n"
-      "  default_level INFO\n"
+      "  default_level ALL\n"
+      "  NameTree INFO\n"
+      "  BestRouteStrategy2 INFO\n"
+      "  InternalFace INFO\n"
+      "  Forwarder INFO\n"
+      "  ContentStore INFO\n"
+      "  DeadNonceList INFO\n"
       "}\n"
       "tables\n"
       "{\n"
@@ -98,7 +122,7 @@
       "      type any\n"
       "    }\n"
       "  }\n"
-      "}\n"
+      "\n"
       "  remote_register\n"
       "  {\n"
       "    cost 15\n"
@@ -106,29 +130,52 @@
       "    retry 0\n"
       "    refresh_interval 300\n"
       "  }\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));
+    std::unique_lock<std::mutex> lock(m_pointerMutex);
+    m_nfd.reset(new Nfd(m_config, m_keyChain));
+    m_nrd.reset(new rib::Nrd(m_config, m_keyChain));
 
     m_nfd->initialize();
     m_nrd->initialize();
   }
 
-  void
-  run()
+  ~Runner()
   {
+    stop();
+    m_io->reset();
+  }
+
+  void
+  start()
+  {
+    {
+      std::unique_lock<std::mutex> lock(m_pointerMutex);
+      m_io = &getGlobalIoService();
+    }
+    m_io->run();
+    m_io->reset();
   }
 
   void
   stop()
   {
+    std::unique_lock<std::mutex> lock(m_pointerMutex);
+
+    m_io->post([this] {
+        m_io->stop();
+        this->m_nrd.reset();
+        this->m_nfd.reset();
+      });
   }
 
 private:
+  std::mutex m_pointerMutex;
+  boost::asio::io_service* m_io;
   ndn::KeyChain m_keyChain;
   unique_ptr<Nfd> m_nfd; // will use globalIoService
   unique_ptr<rib::Nrd> m_nrd; // will use globalIoService
@@ -137,35 +184,50 @@
 };
 
 static unique_ptr<Runner> g_runner;
+static boost::thread g_thread;
 
 } // namespace nfd
 
 JNIEXPORT void JNICALL
-Java_net_named_1data_nfd_wrappers_NfdWrapper_startNfd(JNIEnv *, jclass)
+Java_net_named_1data_nfd_wrappers_NfdWrapper_startNfd(JNIEnv* env, jclass, jstring homePathJ)
 {
   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());
-    }
-  }
+    // set/update HOME environment variable
+    const char* homePath = env->GetStringUTFChars(homePathJ, nullptr);
+    ::setenv("HOME", homePath, true);
+    env->ReleaseStringUTFChars(homePathJ, homePath);
+    NFD_LOG_INFO("Use [" << homePath << "] as a security storage");
 
-  if (nfd::g_runner.get() == nullptr) {
-    return;
-  }
+    nfd::g_thread = boost::thread([] {
+        NFD_LOG_INFO("Starting NFD...");
+        try {
+          nfd::g_runner.reset(new nfd::Runner());
+          nfd::g_runner->start();
+        }
+        catch (const std::exception& e) {
+          NFD_LOG_FATAL(e.what());
+        }
+        catch (const nfd::PrivilegeHelper::Error& e) {
+          NFD_LOG_FATAL("PrivilegeHelper: " << e.what());
+        }
+        catch (...) {
+          NFD_LOG_FATAL("Unknown fatal error");
+        }
 
-  nfd::g_runner->run();
+        nfd::g_runner.reset();
+        nfd::scheduler::resetGlobalScheduler();
+        nfd::resetGlobalIoService();
+        NFD_LOG_INFO("NFD stopped");
+      });
+  }
 }
 
 JNIEXPORT void JNICALL
-Java_net_named_1data_nfd_wrappers_NfdWrapper_stopNfd(JNIEnv *, jclass)
+Java_net_named_1data_nfd_wrappers_NfdWrapper_stopNfd(JNIEnv*, jclass)
 {
-  if (nfd::g_runner.get() == nullptr) {
-    return;
+  if (nfd::g_runner.get() != nullptr) {
+    NFD_LOG_INFO("Stopping NFD...");
+    nfd::g_runner->stop();
+    // do not block anything
   }
-  nfd::g_runner->stop();
-  nfd::g_runner.reset();
 }
diff --git a/app/src/main/jni/nfd-wrapper.hpp b/app/src/main/jni/nfd-wrapper.hpp
index f709a21..2b9523e 100644
--- a/app/src/main/jni/nfd-wrapper.hpp
+++ b/app/src/main/jni/nfd-wrapper.hpp
@@ -31,16 +31,16 @@
  * Method:    startNfd
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_net_named_1data_nfd_wrappers_NfdWrapper_startNfd
-  (JNIEnv *, jclass);
+JNIEXPORT void JNICALL
+Java_net_named_1data_nfd_wrappers_NfdWrapper_startNfd(JNIEnv*, jclass, jstring);
 
 /*
  * Class:     net_named_data_nfd_wrappers_NfdWrapper
  * Method:    stopNfd
  * Signature: ()V
  */
-JNIEXPORT void JNICALL Java_net_named_1data_nfd_wrappers_NfdWrapper_stopNfd
-  (JNIEnv *, jclass);
+JNIEXPORT void JNICALL
+Java_net_named_1data_nfd_wrappers_NfdWrapper_stopNfd(JNIEnv*, jclass);
 
 #ifdef __cplusplus
 }
diff --git a/app/src/main/jni/nfd.mk b/app/src/main/jni/nfd.mk
index 2cacc03..ad7d0f2 100644
--- a/app/src/main/jni/nfd.mk
+++ b/app/src/main/jni/nfd.mk
@@ -1,7 +1,7 @@
 LOCAL_PATH := $(call my-dir)
 LOCAL_PATH_SAVED := $(LOCAL_PATH)
 
-NFD_BOOST_LIBS = system filesystem chrono program_options random
+NFD_BOOST_LIBS = system filesystem chrono program_options random thread
 
 # core
 include $(CLEAR_VARS)