From 69c954760afccbcf7a4069bb973c993cc84ff7c2 Mon Sep 17 00:00:00 2001 From: hypnosis-i2p Date: Sun, 10 Jul 2016 04:54:11 +0800 Subject: [PATCH] android without qt initial commit --- .gitignore | 1 + Daemon.h | 14 ++ HTTPServer.cpp | 6 +- android/.gitignore | 4 + android/AndroidManifest.xml | 16 ++ android/jni/Android.mk | 115 ++++++++++++ android/jni/Application.mk | 30 ++++ android/jni/DaemonAndroid.cpp | 170 ++++++++++++++++++ android/jni/DaemonAndroid.h | 86 +++++++++ android/jni/i2pd_android.cpp | 53 ++++++ android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 21 +++ android/project.properties | 14 ++ android/res/drawable/icon.png | Bin 0 -> 8712 bytes .../drawable/itoopie_notification_icon.png | Bin 0 -> 33199 bytes android/res/values/strings.xml | 4 + android/src/org/purplei2p/i2pd/I2PD.java | 20 +++ android/src/org/purplei2p/i2pd/I2PD_JNI.java | 16 ++ 17 files changed, 567 insertions(+), 3 deletions(-) create mode 100644 android/.gitignore create mode 100755 android/AndroidManifest.xml create mode 100755 android/jni/Android.mk create mode 100755 android/jni/Application.mk create mode 100644 android/jni/DaemonAndroid.cpp create mode 100644 android/jni/DaemonAndroid.h create mode 100755 android/jni/i2pd_android.cpp create mode 100644 android/jni/org_purplei2p_i2pd_I2PD_JNI.h create mode 100644 android/project.properties create mode 100644 android/res/drawable/icon.png create mode 100644 android/res/drawable/itoopie_notification_icon.png create mode 100755 android/res/values/strings.xml create mode 100755 android/src/org/purplei2p/i2pd/I2PD.java create mode 100644 android/src/org/purplei2p/i2pd/I2PD_JNI.java diff --git a/.gitignore b/.gitignore index 89a17a3c..b6cffd15 100644 --- a/.gitignore +++ b/.gitignore @@ -237,3 +237,4 @@ pip-log.txt # Sphinx docs/_build +/androidIdea/ diff --git a/Daemon.h b/Daemon.h index fa4f47ec..85b31240 100644 --- a/Daemon.h +++ b/Daemon.h @@ -45,6 +45,20 @@ namespace i2p } }; +#elif defined(ANDROID) +#define Daemon i2p::util::DaemonAndroid::Instance() + // dummy, invoked from android/jni/DaemonAndroid.* + class DaemonAndroid: public i2p::util::Daemon_Singleton + { + public: + + static DaemonAndroid& Instance() + { + static DaemonAndroid instance; + return instance; + } + }; + #elif defined(_WIN32) #define Daemon i2p::util::DaemonWin32::Instance() class DaemonWin32 : public Daemon_Singleton diff --git a/HTTPServer.cpp b/HTTPServer.cpp index cfcf4261..39ced94a 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -377,7 +377,7 @@ namespace http { s << " Stop accepting tunnels
\r\n"; else s << " Start accepting tunnels
\r\n"; -#if (!defined(WIN32) && !defined(QT_GUI_LIB)) +#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) if (Daemon.gracefullShutdownInterval) { s << " Cancel gracefull shutdown ("; s << Daemon.gracefullShutdownInterval; @@ -690,12 +690,12 @@ namespace http { i2p::context.SetAcceptsTunnels (false); else if (cmd == HTTP_COMMAND_SHUTDOWN_START) { i2p::context.SetAcceptsTunnels (false); -#if (!defined(WIN32) && !defined(QT_GUI_LIB)) +#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) Daemon.gracefullShutdownInterval = 10*60; #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_CANCEL) { i2p::context.SetAcceptsTunnels (true); -#if (!defined(WIN32) && !defined(QT_GUI_LIB)) +#if (!defined(WIN32) && !defined(QT_GUI_LIB) && !defined(ANDROID)) Daemon.gracefullShutdownInterval = 0; #endif } else if (cmd == HTTP_COMMAND_SHUTDOWN_NOW) { diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 00000000..8364f857 --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,4 @@ +/gen/ +/libs/ +/tests/ +.idea diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100755 index 00000000..58d46ed8 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + diff --git a/android/jni/Android.mk b/android/jni/Android.mk new file mode 100755 index 00000000..bef6d5ec --- /dev/null +++ b/android/jni/Android.mk @@ -0,0 +1,115 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := i2pd +LOCAL_CPP_FEATURES := rtti exceptions +LOCAL_C_INCLUDES += $(IFADDRS_PATH) ../.. +LOCAL_STATIC_LIBRARIES := \ + boost_system-gcc-mt-1_53 \ + boost_date_time-gcc-mt-1_53 \ + boost_filesystem-gcc-mt-1_53 \ + boost_program_options-gcc-mt-1_53 \ + crypto ssl \ + miniupnpc +LOCAL_LDLIBS := -lz + +#LOCAL_CFLAGS := +LOCAL_SRC_FILES := DaemonAndroid.cpp i2pd_android.cpp \ + $(IFADDRS_PATH)/ifaddrs.c \ + ../../HTTPServer.cpp ../../I2PControl.cpp ../../Daemon.cpp ../../Config.cpp \ + ../../AddressBook.cpp \ + ../../api.cpp \ + ../../Base.cpp \ + ../../BOB.cpp \ + ../../ClientContext.cpp \ + ../../Crypto.cpp \ + ../../Datagram.cpp \ + ../../Destination.cpp \ + ../../Family.cpp \ + ../../FS.cpp \ + ../../Garlic.cpp \ + ../../Gzip.cpp \ + ../../HTTP.cpp \ + ../../HTTPProxy.cpp \ + ../../I2CP.cpp \ + ../../I2NPProtocol.cpp \ + ../../I2PEndian.cpp \ + ../../I2PService.cpp \ + ../../I2PTunnel.cpp \ + ../../Identity.cpp \ + ../../LeaseSet.cpp \ + ../../Log.cpp \ + ../../NetDb.cpp \ + ../../NetDbRequests.cpp \ + ../../NTCPSession.cpp \ + ../../Profiling.cpp \ + ../../Reseed.cpp \ + ../../RouterContext.cpp \ + ../../RouterInfo.cpp \ + ../../SAM.cpp \ + ../../Signature.cpp \ + ../../SOCKS.cpp \ + ../../SSU.cpp \ + ../../SSUData.cpp \ + ../../SSUSession.cpp \ + ../../Streaming.cpp \ + ../../TransitTunnel.cpp \ + ../../Transports.cpp \ + ../../Tunnel.cpp \ + ../../TunnelEndpoint.cpp \ + ../../TunnelGateway.cpp \ + ../../TunnelPool.cpp \ + ../../UPnP.cpp \ + ../../util.cpp \ + ../../i2pd.cpp + +include $(BUILD_SHARED_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_system-gcc-mt-1_53 +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_system-gcc-mt-1_53.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_date_time-gcc-mt-1_53 +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_date_time-gcc-mt-1_53.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_filesystem-gcc-mt-1_53 +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_filesystem-gcc-mt-1_53.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_program_options-gcc-mt-1_53 +LOCAL_SRC_FILES := $(BOOST_PATH)/boost_1_53_0/$(TARGET_ARCH_ABI)/lib/libboost_program_options-gcc-mt-1_53.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/boost_1_53_0/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := crypto +LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.0.2/$(TARGET_ARCH_ABI)/lib/libcrypto.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.0.2/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := ssl +LOCAL_SRC_FILES := $(OPENSSL_PATH)/openssl-1.0.2/$(TARGET_ARCH_ABI)/lib/libssl.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/openssl-1.0.2/include +LOCAL_STATIC_LIBRARIES := crypto +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := miniupnpc +LOCAL_SRC_FILES := $(MINIUPNP_PATH)/miniupnp-2.0/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a +LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnp-2.0/include +include $(PREBUILT_STATIC_LIBRARY) diff --git a/android/jni/Application.mk b/android/jni/Application.mk new file mode 100755 index 00000000..34f9dd63 --- /dev/null +++ b/android/jni/Application.mk @@ -0,0 +1,30 @@ +#APP_ABI := all +APP_ABI := armeabi-v7a x86 +#can be android-3 but will fail for x86 since arch-x86 is not present at ndkroot/platforms/android-3/ . libz is taken from there. +APP_PLATFORM := android-9 + +# http://stackoverflow.com/a/21386866/529442 http://stackoverflow.com/a/15616255/529442 to enable c++11 support in Eclipse +NDK_TOOLCHAIN_VERSION := 4.9 +# APP_STL := stlport_shared --> does not seem to contain C++11 features +APP_STL := gnustl_shared + +# Enable c++11 extentions in source code +APP_CPPFLAGS += -std=c++11 + +APP_CPPFLAGS += -DUSE_UPNP -DANDROID -D__ANDROID__ +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +APP_CPPFLAGS += -DANDROID_ARM7A +endif + +APP_OPTIM := debug + +# git clone https://github.com/PurpleI2P/Boost-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/OpenSSL-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/MiniUPnP-for-Android-Prebuilt.git +# git clone https://github.com/PurpleI2P/android-ifaddrs.git +# change to your own +I2PD_LIBS_PATH=/path/to/libraries +BOOST_PATH = $(I2PD_LIBS_PATH)/Boost-for-Android-Prebuilt +OPENSSL_PATH = $(I2PD_LIBS_PATH)/OpenSSL-for-Android-Prebuilt +MINIUPNP_PATH = $(I2PD_LIBS_PATH)/MiniUPnP-for-Android-Prebuilt +IFADDRS_PATH = $(I2PD_LIBS_PATH)/android-ifaddrs diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp new file mode 100644 index 00000000..02f6e3f7 --- /dev/null +++ b/android/jni/DaemonAndroid.cpp @@ -0,0 +1,170 @@ +#include "DaemonAndroid.h" +#include "../../Daemon.h" +//#include "mainwindow.h" + +namespace i2p +{ +namespace android +{ +/* Worker::Worker (DaemonAndroidImpl& daemon): + m_Daemon (daemon) + { + } + + void Worker::startDaemon() + { + Log.d(TAG"Performing daemon start..."); + m_Daemon.start(); + Log.d(TAG"Daemon started."); + emit resultReady(); + } + void Worker::restartDaemon() + { + Log.d(TAG"Performing daemon restart..."); + m_Daemon.restart(); + Log.d(TAG"Daemon restarted."); + emit resultReady(); + } + void Worker::stopDaemon() { + Log.d(TAG"Performing daemon stop..."); + m_Daemon.stop(); + Log.d(TAG"Daemon stopped."); + emit resultReady(); + } + + Controller::Controller(DaemonAndroidImpl& daemon): + m_Daemon (daemon) + { + Worker *worker = new Worker (m_Daemon); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &Controller::startDaemon, worker, &Worker::startDaemon); + connect(this, &Controller::stopDaemon, worker, &Worker::stopDaemon); + connect(this, &Controller::restartDaemon, worker, &Worker::restartDaemon); + connect(worker, &Worker::resultReady, this, &Controller::handleResults); + workerThread.start(); + } + Controller::~Controller() + { + Log.d(TAG"Closing and waiting for daemon worker thread..."); + workerThread.quit(); + workerThread.wait(); + Log.d(TAG"Waiting for daemon worker thread finished."); + if(m_Daemon.isRunning()) + { + Log.d(TAG"Stopping the daemon..."); + m_Daemon.stop(); + Log.d(TAG"Stopped the daemon."); + } + } +*/ + DaemonAndroidImpl::DaemonAndroidImpl (): + /*mutex(nullptr), */ + m_IsRunning(false), + m_RunningChangedCallback(nullptr) + { + } + + DaemonAndroidImpl::~DaemonAndroidImpl () + { + //delete mutex; + } + + bool DaemonAndroidImpl::init(int argc, char* argv[]) + { + //mutex=new QMutex(QMutex::Recursive); + setRunningCallback(0); + m_IsRunning=false; + return Daemon.init(argc,argv); + } + + void DaemonAndroidImpl::start() + { + //QMutexLocker locker(mutex); + setRunning(true); + Daemon.start(); + } + + void DaemonAndroidImpl::stop() + { + //QMutexLocker locker(mutex); + Daemon.stop(); + setRunning(false); + } + + void DaemonAndroidImpl::restart() + { + //QMutexLocker locker(mutex); + stop(); + start(); + } + + void DaemonAndroidImpl::setRunningCallback(runningChangedCallback cb) + { + m_RunningChangedCallback = cb; + } + + bool DaemonAndroidImpl::isRunning() + { + return m_IsRunning; + } + + void DaemonAndroidImpl::setRunning(bool newValue) + { + bool oldValue = m_IsRunning; + if(oldValue!=newValue) + { + m_IsRunning = newValue; + if(m_RunningChangedCallback) + m_RunningChangedCallback(); + } + } + + static DaemonAndroidImpl daemon; + + /** + * returns 1 if daemon init failed + * returns 0 if daemon initialized and started okay + */ + int start(/*int argc, char* argv[]*/) + { + int result; + + { + //Log.d(TAG"Initialising the daemon..."); + bool daemonInitSuccess = daemon.init(0,0/*argc, argv*/); + if(!daemonInitSuccess) + { + //QMessageBox::critical(0, "Error", "Daemon init failed"); + return 1; + } + //Log.d(TAG"Initialised, creating the main window..."); + //MainWindow w; + //Log.d(TAG"Before main window.show()..."); + //w.show (); + + { + //i2p::qt::Controller daemonQtController(daemon); + //Log.d(TAG"Starting the daemon..."); + //emit daemonQtController.startDaemon(); + //daemon.start (); + //Log.d(TAG"Starting GUI event loop..."); + //result = app.exec(); + //daemon.stop (); + daemon.start(); + return 0; + } + } + + //QMessageBox::information(&w, "Debug", "demon stopped"); + //Log.d(TAG"Exiting the application"); + //return result; + } + + void stop() + { + daemon.stop(); + } +} +} + diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h new file mode 100644 index 00000000..f6ee618f --- /dev/null +++ b/android/jni/DaemonAndroid.h @@ -0,0 +1,86 @@ +#ifndef DAEMON_ANDROID_H +#define DAEMON_ANDROID_H + +namespace i2p +{ +namespace android +{ + //FIXME currently NOT threadsafe + class DaemonAndroidImpl + { + public: + + DaemonAndroidImpl (); + ~DaemonAndroidImpl (); + + typedef void (*runningChangedCallback)(); + + /** + * @return success + */ + bool init(int argc, char* argv[]); + void start(); + void stop(); + void restart(); + void setRunningCallback(runningChangedCallback cb); + bool isRunning(); + private: + void setRunning(bool running); + private: + //QMutex* mutex; + bool m_IsRunning; + runningChangedCallback m_RunningChangedCallback; + }; + + /** + * returns 1 if daemon init failed + * returns 0 if daemon initialized and started okay + */ + int start(); + + // stops the daemon + void stop(); + + /* + class Worker : public QObject + { + Q_OBJECT + public: + + Worker (DaemonAndroidImpl& daemon); + + private: + + DaemonAndroidImpl& m_Daemon; + + public slots: + void startDaemon(); + void restartDaemon(); + void stopDaemon(); + + signals: + void resultReady(); + }; + + class Controller : public QObject + { + Q_OBJECT + QThread workerThread; + public: + Controller(DaemonAndroidImpl& daemon); + ~Controller(); + private: + DaemonAndroidImpl& m_Daemon; + + public slots: + void handleResults(){} + signals: + void startDaemon(); + void stopDaemon(); + void restartDaemon(); + }; + */ +} +} + +#endif // DAEMON_ANDROID_H diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp new file mode 100755 index 00000000..b84ec1ac --- /dev/null +++ b/android/jni/i2pd_android.cpp @@ -0,0 +1,53 @@ + +//#include +#include +#include "org_purplei2p_i2pd_I2PD_JNI.h" +#include "DaemonAndroid.h" + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith + (JNIEnv * env, jclass clazz) { +#if defined(__arm__) + #if defined(__ARM_ARCH_7A__) + #if defined(__ARM_NEON__) + #if defined(__ARM_PCS_VFP) + #define ABI "armeabi-v7a/NEON (hard-float)" + #else + #define ABI "armeabi-v7a/NEON" + #endif + #else + #if defined(__ARM_PCS_VFP) + #define ABI "armeabi-v7a (hard-float)" + #else + #define ABI "armeabi-v7a" + #endif + #endif + #else + #define ABI "armeabi" + #endif +#elif defined(__i386__) + #define ABI "x86" +#elif defined(__x86_64__) + #define ABI "x86_64" +#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */ + #define ABI "mips64" +#elif defined(__mips__) + #define ABI "mips" +#elif defined(__aarch64__) + #define ABI "arm64-v8a" +#else + #define ABI "unknown" +#endif + + return env->NewStringUTF(ABI); +} + +JNIEXPORT jint JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon + (JNIEnv * env, jclass clazz) { + return (jint)i2p::android::start(); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon + (JNIEnv * env, jclass clazz) { + i2p::android::stop(); +} + diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h new file mode 100644 index 00000000..ddbcace8 --- /dev/null +++ b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_purplei2p_i2pd_I2PD_JNI */ + +#ifndef _Included_org_purplei2p_i2pd_I2PD_JNI +#define _Included_org_purplei2p_i2pd_I2PD_JNI +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_purplei2p_i2pd_I2PD_JNI + * Method: stringFromJNI + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/android/project.properties b/android/project.properties new file mode 100644 index 00000000..c6998b3d --- /dev/null +++ b/android/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-9 diff --git a/android/res/drawable/icon.png b/android/res/drawable/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a5dc7b680ba9dee30161ffb1c9fcd17bbd6ddd84 GIT binary patch literal 8712 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 literal 0 HcmV?d00001 diff --git a/android/res/drawable/itoopie_notification_icon.png b/android/res/drawable/itoopie_notification_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8fbe24689b0af36100a6afa238829d7ce96a6529 GIT binary patch literal 33199 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 + + i2pd + diff --git a/android/src/org/purplei2p/i2pd/I2PD.java b/android/src/org/purplei2p/i2pd/I2PD.java new file mode 100755 index 00000000..6f77c53f --- /dev/null +++ b/android/src/org/purplei2p/i2pd/I2PD.java @@ -0,0 +1,20 @@ +package org.purplei2p.i2pd; + +import android.app.Activity; +import android.widget.TextView; +import android.os.Bundle; + +public class I2PD extends Activity { + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + TextView tv = new TextView(this); + tv.setText( "libi2pd.so was compiled with ABI " + getABICompiledWith()); + setContentView(tv); + } + + public String getABICompiledWith() { + return I2PD_JNI.getABICompiledWith(); + } +} diff --git a/android/src/org/purplei2p/i2pd/I2PD_JNI.java b/android/src/org/purplei2p/i2pd/I2PD_JNI.java new file mode 100644 index 00000000..040cca1c --- /dev/null +++ b/android/src/org/purplei2p/i2pd/I2PD_JNI.java @@ -0,0 +1,16 @@ +package org.purplei2p.i2pd; + +public class I2PD_JNI { + public static native String getABICompiledWith(); + /** + * returns 1 if daemon init failed + * returns 0 if daemon initialized and started okay + */ + public static native int startDaemon(); + //should only be called after startDaemon() success + public static native void stopDaemon(); + + static { + System.loadLibrary("i2pd"); + } +}