From 503f8a003e3693baa03b4374f2202263c58035e3 Mon Sep 17 00:00:00 2001 From: r4sas Date: Mon, 29 Jul 2024 23:25:49 +0000 Subject: [PATCH] revert switching from JNI to binary Signed-off-by: r4sas --- .github/workflows/android.yml | 6 +- README.md | 7 +- app/build.gradle | 17 +- app/jni/Android.mk | 80 +++++++++ app/jni/Application.mk | 23 +++ app/jni/DaemonAndroid.cpp | 138 ++++++++++++++ app/jni/DaemonAndroid.h | 53 ++++++ app/jni/i2pd_android.cpp | 141 +++++++++++++++ app/jni/org_purplei2p_i2pd_I2PD_JNI.h | 73 ++++++++ app/src/main/AndroidManifest.xml | 1 - .../org/purplei2p/i2pd/AbstractProcess.java | 7 - .../org/purplei2p/i2pd/DaemonWrapper.java | 170 +++++++++--------- .../org/purplei2p/i2pd/ForegroundService.java | 9 - .../java/org/purplei2p/i2pd/I2PDActivity.java | 68 +++---- .../java/org/purplei2p/i2pd/I2PD_JNI.java | 35 ++++ .../main/java/org/purplei2p/i2pd/I2pdApi.java | 154 ---------------- .../i2pd/NetworkStateChangeReceiver.java | 2 +- .../purplei2p/i2pd/WebConsoleActivity.java | 2 +- .../java/org/purplei2p/i2pd/appscope/App.java | 126 ------------- app/src/main/res/layout/activity_main.xml | 4 +- app/src/main/res/menu/options_main.xml | 4 +- binary/jni/build.sh | 14 +- binary/libs/.gitkeep | 0 .../android/en-US/changelogs/2530010.txt | 2 + 24 files changed, 686 insertions(+), 450 deletions(-) create mode 100644 app/jni/Android.mk create mode 100644 app/jni/Application.mk create mode 100644 app/jni/DaemonAndroid.cpp create mode 100644 app/jni/DaemonAndroid.h create mode 100644 app/jni/i2pd_android.cpp create mode 100644 app/jni/org_purplei2p_i2pd_I2PD_JNI.h delete mode 100644 app/src/main/java/org/purplei2p/i2pd/AbstractProcess.java create mode 100644 app/src/main/java/org/purplei2p/i2pd/I2PD_JNI.java delete mode 100644 app/src/main/java/org/purplei2p/i2pd/I2pdApi.java delete mode 100644 app/src/main/java/org/purplei2p/i2pd/appscope/App.java create mode 100644 binary/libs/.gitkeep create mode 100644 fastlane/metadata/android/en-US/changelogs/2530010.txt diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 85cdc94..b3baf9f 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -21,7 +21,7 @@ jobs: run: | export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/23.2.8568313 pushd binary/jni - ./build.sh -md + ./build.sh popd - name: Build with Gradle run: ./gradlew --no-daemon assembleDebug @@ -45,11 +45,11 @@ jobs: run: export JAVA_HOME=$JAVA_HOME_11_X64 - name: Install required Android SDK packages run: $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "cmake;3.22.1" "ndk;23.2.8568313" - - name: Build binaries with NDK + - name: Build binary with NDK run: | export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/23.2.8568313 pushd binary/jni - ./build.sh + ./build.sh -b popd - name: Create package with built binaries run: | diff --git a/README.md b/README.md index 883da4e..1121a90 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,6 @@ unzip commandlinetools-linux-8092744_latest.zip ```bash git clone --recurse-submodules https://github.com/PurpleI2P/i2pd-android.git -cd i2pd-android ``` ### Compile application @@ -54,8 +53,10 @@ export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 export ANDROID_HOME=/opt/android-sdk export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/23.2.8568313 -pushd binary/jni -./build.sh -md +pushd app/jni +./build_boost.sh +./build_openssl.sh +./build_miniupnpc.sh popd gradle clean assembleDebug diff --git a/app/build.gradle b/app/build.gradle index 896a828..7a0664b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -29,8 +29,8 @@ android { targetSdkVersion 33 // TODO: 24? minSdkVersion 16 - versionCode 2530000 - versionName "2.53.0" + versionCode 2530010 + versionName "2.53.0.1" archivesBaseName += "-$versionName" ndkVersion "23.2.8568313" @@ -40,6 +40,13 @@ android { abiFilters "arm64-v8a" abiFilters "x86_64" } + + externalNativeBuild { + ndkBuild { + arguments "NDK_MODULE_PATH:=${rootProject.projectDir}/binary/jni" + arguments "-j${Runtime.getRuntime().availableProcessors()}" + } + } } splits { @@ -71,9 +78,9 @@ android { } } - sourceSets { - main { - jniLibs.srcDir file("${rootProject.projectDir}/binary/libs") + externalNativeBuild { + ndkBuild { + path "${rootProject.projectDir}/app/jni/Android.mk" } } diff --git a/app/jni/Android.mk b/app/jni/Android.mk new file mode 100644 index 0000000..3938cf4 --- /dev/null +++ b/app/jni/Android.mk @@ -0,0 +1,80 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := i2pd +LOCAL_CPP_FEATURES := rtti exceptions +LOCAL_C_INCLUDES += $(IFADDRS_PATH) $(LIB_SRC_PATH) $(LIB_CLIENT_SRC_PATH) $(LANG_SRC_PATH) $(DAEMON_SRC_PATH) +LOCAL_STATIC_LIBRARIES := \ + boost_system \ + boost_date_time \ + boost_filesystem \ + boost_program_options \ + crypto \ + ssl \ + miniupnpc +LOCAL_LDLIBS := -lz + +LOCAL_SRC_FILES := \ + DaemonAndroid.cpp \ + i2pd_android.cpp \ + $(IFADDRS_PATH)/ifaddrs.cpp \ + $(IFADDRS_PATH)/bionic_netlink.cpp \ + $(wildcard $(LIB_SRC_PATH)/*.cpp) \ + $(wildcard $(LIB_CLIENT_SRC_PATH)/*.cpp) \ + $(wildcard $(LANG_SRC_PATH)/*.cpp) \ + $(DAEMON_SRC_PATH)/Daemon.cpp \ + $(DAEMON_SRC_PATH)/UPnP.cpp \ + $(DAEMON_SRC_PATH)/HTTPServer.cpp \ + $(DAEMON_SRC_PATH)/I2PControl.cpp \ + $(DAEMON_SRC_PATH)/I2PControlHandlers.cpp + +include $(BUILD_SHARED_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_system +LOCAL_SRC_FILES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/lib/libboost_system.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_date_time +LOCAL_SRC_FILES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/lib/libboost_date_time.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_filesystem +LOCAL_SRC_FILES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/lib/libboost_filesystem.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := boost_program_options +LOCAL_SRC_FILES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/lib/libboost_program_options.a +LOCAL_EXPORT_C_INCLUDES := $(BOOST_PATH)/build/out/$(TARGET_ARCH_ABI)/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := crypto +LOCAL_SRC_FILES := $(OPENSSL_PATH)/out/$(TARGET_ARCH_ABI)/lib/libcrypto.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/out/$(TARGET_ARCH_ABI)/include +include $(PREBUILT_STATIC_LIBRARY) + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) +LOCAL_MODULE := ssl +LOCAL_SRC_FILES := $(OPENSSL_PATH)/out/$(TARGET_ARCH_ABI)/lib/libssl.a +LOCAL_EXPORT_C_INCLUDES := $(OPENSSL_PATH)/out/$(TARGET_ARCH_ABI)/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)/miniupnpc/out/$(TARGET_ARCH_ABI)/lib/libminiupnpc.a +LOCAL_EXPORT_C_INCLUDES := $(MINIUPNP_PATH)/miniupnpc/out/$(TARGET_ARCH_ABI)/include +include $(PREBUILT_STATIC_LIBRARY) diff --git a/app/jni/Application.mk b/app/jni/Application.mk new file mode 100644 index 0000000..f167780 --- /dev/null +++ b/app/jni/Application.mk @@ -0,0 +1,23 @@ +NDK_TOOLCHAIN_VERSION := clang +APP_STL := c++_static + +# Enable c++17 extensions in source code +APP_CPPFLAGS += -std=c++17 -fexceptions -frtti + +APP_CPPFLAGS += -DANDROID -D__ANDROID__ -DUSE_UPNP -Wno-deprecated-declarations +ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) +APP_CPPFLAGS += -DANDROID_ARM7A +endif + +IFADDRS_PATH = $(NDK_MODULE_PATH)/android-ifaddrs +BOOST_PATH = $(NDK_MODULE_PATH)/boost +MINIUPNP_PATH = $(NDK_MODULE_PATH)/miniupnp +OPENSSL_PATH = $(NDK_MODULE_PATH)/openssl + +# don't change me +I2PD_SRC_PATH = $(NDK_MODULE_PATH)/i2pd + +LIB_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd +LIB_CLIENT_SRC_PATH = $(I2PD_SRC_PATH)/libi2pd_client +LANG_SRC_PATH = $(I2PD_SRC_PATH)/i18n +DAEMON_SRC_PATH = $(I2PD_SRC_PATH)/daemon diff --git a/app/jni/DaemonAndroid.cpp b/app/jni/DaemonAndroid.cpp new file mode 100644 index 0000000..097e694 --- /dev/null +++ b/app/jni/DaemonAndroid.cpp @@ -0,0 +1,138 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include +#include +#include +#include +#include +//#include "mainwindow.h" +#include "FS.h" +#include "DaemonAndroid.h" +#include "Daemon.h" +#include "I18N.h" + +namespace i2p +{ +namespace android +{ + std::string dataDir = ""; + std::string language = ""; + + DaemonAndroidImpl::DaemonAndroidImpl () + { + } + + DaemonAndroidImpl::~DaemonAndroidImpl () + { + } + + bool DaemonAndroidImpl::init(int argc, char* argv[]) + { + return Daemon.init(argc, argv); + } + + void DaemonAndroidImpl::start() + { + Daemon.start(); + } + + void DaemonAndroidImpl::stop() + { + Daemon.stop(); + } + + void DaemonAndroidImpl::restart() + { + stop(); + start(); + } + + void DaemonAndroidImpl::setDataDir(std::string path) + { + Daemon.setDataDir(path); + } + + static DaemonAndroidImpl daemon; + static char* argv[1]={strdup("tmp")}; + /** + * returns error details if failed + * returns "ok" if daemon initialized and started okay + */ + std::string start(/*int argc, char* argv[]*/) + { + try + { + { + // make sure assets are ready before proceed + i2p::fs::DetectDataDir(dataDir, false); + int numAttempts = 0; + do + { + if (i2p::fs::Exists (i2p::fs::DataDirPath("assets.ready"))) break; // assets ready + numAttempts++; + std::this_thread::sleep_for (std::chrono::seconds(1)); // otherwise wait for 1 more second + } + while (numAttempts <= 10); // 10 seconds max + + // Set application directory + daemon.setDataDir(dataDir); + + bool daemonInitSuccess = daemon.init(1, argv); + if(!daemonInitSuccess) + { + return "Daemon init failed"; + } + + // Set webconsole language from application + i2p::i18n::SetLanguage(language); + + daemon.start(); + } + } + catch (boost::exception& ex) + { + std::stringstream ss; + ss << boost::diagnostic_information(ex); + return ss.str(); + } + catch (std::exception& ex) + { + std::stringstream ss; + ss << ex.what(); + return ss.str(); + } + catch(...) + { + return "unknown exception"; + } + return "ok"; + } + + void stop() + { + daemon.stop(); + } + + void SetDataDir(std::string jdataDir) + { + dataDir = jdataDir; + } + + std::string GetDataDir(void) + { + return dataDir; + } + + void SetLanguage(std::string jlanguage) + { + language = jlanguage; + } +} +} diff --git a/app/jni/DaemonAndroid.h b/app/jni/DaemonAndroid.h new file mode 100644 index 0000000..6dbed75 --- /dev/null +++ b/app/jni/DaemonAndroid.h @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#ifndef DAEMON_ANDROID_H +#define DAEMON_ANDROID_H + +#include + +namespace i2p +{ +namespace android +{ + class DaemonAndroidImpl + { + public: + + DaemonAndroidImpl (); + ~DaemonAndroidImpl (); + + /** + * @return success + */ + bool init (int argc, char* argv[]); + void start (); + void stop (); + void restart (); + + void setDataDir (std::string path); + }; + + /** + * returns "ok" if daemon init failed + * returns errinfo if daemon initialized and started okay + */ + std::string start (); + + void stop (); + + // set datadir received from jni + void SetDataDir (std::string jdataDir); + // get datadir + std::string GetDataDir (void); + // set webconsole language + void SetLanguage (std::string jlanguage); +} +} + +#endif // DAEMON_ANDROID_H diff --git a/app/jni/i2pd_android.cpp b/app/jni/i2pd_android.cpp new file mode 100644 index 0000000..94a52c5 --- /dev/null +++ b/app/jni/i2pd_android.cpp @@ -0,0 +1,141 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +#include +#include "org_purplei2p_i2pd_I2PD_JNI.h" +#include "DaemonAndroid.h" +#include "Config.h" +#include "RouterContext.h" +#include "ClientContext.h" +#include "Transports.h" +#include "Tunnel.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 jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon + (JNIEnv *env, jclass clazz) { + return env->NewStringUTF(i2p::android::start().c_str()); +} + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getDataDir + (JNIEnv *env, jclass clazz) { + return env->NewStringUTF(i2p::android::GetDataDir().c_str()); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon + (JNIEnv *env, jclass clazz) { + i2p::android::stop(); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels + (JNIEnv *env, jclass clazz) { + i2p::context.SetAcceptsTunnels (false); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels + (JNIEnv *env, jclass clazz) { + i2p::context.SetAcceptsTunnels (true); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_reloadTunnelsConfigs + (JNIEnv *env, jclass clazz) { + i2p::client::context.ReloadConfig(); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged + (JNIEnv *env, jclass clazz, jboolean isConnected) { + bool isConnectedBool = (bool) isConnected; + i2p::transport::transports.SetOnline (isConnectedBool); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setDataDir + (JNIEnv *env, jclass clazz, jstring jdataDir) { + auto dataDir = env->GetStringUTFChars(jdataDir, NULL); + i2p::android::SetDataDir(dataDir); + env->ReleaseStringUTFChars(jdataDir, dataDir); +} + +JNIEXPORT jint JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getTransitTunnelsCount + (JNIEnv *env, jclass clazz) { + return i2p::tunnel::tunnels.CountTransitTunnels(); +} + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getWebConsAddr + (JNIEnv *env, jclass clazz) { + std::string httpAddr; i2p::config::GetOption("http.address", httpAddr); + uint16_t httpPort; i2p::config::GetOption("http.port", httpPort); + std::string result = "http://" + httpAddr + ":" + std::to_string(httpPort) + "/"; + return env->NewStringUTF(result.c_str()); +} + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setLanguage + (JNIEnv *env, jclass clazz, jstring jlanguage) { + auto language = env->GetStringUTFChars(jlanguage, NULL); + i2p::android::SetLanguage(language); + env->ReleaseStringUTFChars(jlanguage, language); +} + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getHTTPProxyState + (JNIEnv *, jclass) { + return i2p::client::context.GetHttpProxy () ? true : false; +} + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getSOCKSProxyState + (JNIEnv *, jclass) { + return i2p::client::context.GetSocksProxy() ? true : false; +} + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getBOBState + (JNIEnv *, jclass) { + return i2p::client::context.GetBOBCommandChannel() ? true : false; +} + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getSAMState + (JNIEnv *, jclass) { + return i2p::client::context.GetSAMBridge() ? true : false; +} + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getI2CPState + (JNIEnv *, jclass) { + return i2p::client::context.GetI2CPServer() ? true : false; +} diff --git a/app/jni/org_purplei2p_i2pd_I2PD_JNI.h b/app/jni/org_purplei2p_i2pd_I2PD_JNI.h new file mode 100644 index 0000000..4c37e3d --- /dev/null +++ b/app/jni/org_purplei2p_i2pd_I2PD_JNI.h @@ -0,0 +1,73 @@ +/* +* Copyright (c) 2013-2022, The PurpleI2P Project +* +* This file is part of Purple i2pd project and licensed under BSD3 +* +* See full license text in LICENSE file at top of project tree +*/ + +/* 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 + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith + (JNIEnv *, jclass); + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startAcceptingTunnels + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopAcceptingTunnels + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_reloadTunnelsConfigs + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setDataDir + (JNIEnv *env, jclass clazz, jstring jdataDir); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_setLanguage + (JNIEnv *env, jclass clazz, jstring jlanguage); + +JNIEXPORT jint JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getTransitTunnelsCount + (JNIEnv *, jclass); + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getWebConsAddr + (JNIEnv *, jclass); + +JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getDataDir + (JNIEnv *, jclass); + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getHTTPProxyState + (JNIEnv *, jclass); + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getSOCKSProxyState + (JNIEnv *, jclass); + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getBOBState + (JNIEnv *, jclass); + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getSAMState + (JNIEnv *, jclass) ; + +JNIEXPORT jboolean JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getI2CPState + (JNIEnv *, jclass); + +JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_onNetworkStateChanged + (JNIEnv * env, jclass clazz, jboolean isConnected); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0eab729..e7c2d76 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -16,7 +16,6 @@ { - synchronized(DaemonWrapper.this) { - if (getState() == State.startedOkay) return; - try { - processAssets(); - //registerNetworkCallback(); - } catch (Throwable tr) { - lastThrowable = tr; - setState(State.startFailed); - return; - } - try { - String locale = getAppLocale(); - Log.i(TAG, "setting webconsole language to " + locale); + try { + processAssets(); + I2PD_JNI.loadLibraries(); + //registerNetworkCallback(); + } catch (Throwable tr) { + lastThrowable = tr; + setState(State.startFailed); + return; + } + try { + synchronized (DaemonWrapper.this) { + I2PD_JNI.setDataDir(i2pdpath); // (Environment.getExternalStorageDirectory().getAbsolutePath() + "/i2pd"); + + Log.i(TAG, "setting webconsole language to " + appLocale); + I2PD_JNI.setLanguage(appLocale); - daemonStartResult = I2pdApi.startDaemon(ctx, i2pdpath, locale, DaemonWrapper.this); + daemonStartResult = I2PD_JNI.startDaemon(); if ("ok".equals(daemonStartResult)) { setState(State.startedOkay); } else setState(State.startFailed); - } catch (Throwable tr) { - lastThrowable = tr; - setState(State.startFailed); } + } catch (Throwable tr) { + lastThrowable = tr; + setState(State.startFailed); } }, "i2pdDaemonStart").start(); } @@ -210,75 +207,71 @@ private void processAssets() { String versionName = BuildConfig.VERSION_NAME; // here will be app version, like 2.XX.XX StringBuilder text = new StringBuilder(); Log.d(TAG, "checking assets"); - try { - if (holderFile.exists()) { - try { // if holder file exists, read assets version string - FileReader fileReader = new FileReader(holderFile); + + if (holderFile.exists()) { + try { // if holder file exists, read assets version string + FileReader fileReader = new FileReader(holderFile); + + try { + BufferedReader br = new BufferedReader(fileReader); try { - BufferedReader br = new BufferedReader(fileReader); + String line; - try { - String line; - - while ((line = br.readLine()) != null) { - text.append(line); - } - } finally { - try { - br.close(); - } catch (IOException e) { - Log.e(TAG, "", e); - } + while ((line = br.readLine()) != null) { + text.append(line); } - } finally { + }finally { try { - fileReader.close(); + br.close(); } catch (IOException e) { Log.e(TAG, "", e); } } - } catch (IOException e) { - Log.e(TAG, "", e); + } finally { + try { + fileReader.close(); + } catch (IOException e) { + Log.e(TAG, "", e); + } } + } catch (IOException e) { + Log.e(TAG, "", e); } + } - // if version differs from current app version or null, try to delete certificates folder - if (!text.toString().contains(versionName)) { + // if version differs from current app version or null, try to delete certificates folder + if (!text.toString().contains(versionName)) { + try { + boolean deleteResult = holderFile.delete(); + if (!deleteResult) + Log.e(TAG, "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile.getAbsolutePath() + "'"); + File certPath = new File(i2pdpath, "certificates"); + deleteRecursive(certPath); + + // copy assets. If processed file exists, it won't be overwritten + copyAsset("addressbook"); + copyAsset("certificates"); + copyAsset("tunnels.d"); + copyAsset("i2pd.conf"); + copyAsset("tunnels.conf"); + + // update holder file about successful copying + FileWriter writer = new FileWriter(holderFile); try { - boolean deleteResult = holderFile.delete(); - if (!deleteResult) - Log.e(TAG, "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile.getAbsolutePath() + "'"); - File certPath = new File(i2pdpath, "certificates"); - deleteRecursive(certPath); - - // copy assets. If processed file exists, it won't be overwritten - copyAsset("addressbook"); - copyAsset("certificates"); - copyAsset("tunnels.d"); - copyAsset("i2pd.conf"); - copyAsset("tunnels.conf"); - - // update holder file about successful copying - FileWriter writer = new FileWriter(holderFile); + writer.append(versionName); + } finally { try { - writer.append(versionName); - } finally { - try { - writer.close(); - } catch (IOException e) { - Log.e(TAG, "on writer close", e); - } + writer.close(); + } catch (IOException e) { + Log.e(TAG,"on writer close", e); } - } catch (Throwable tr) { - Log.e(TAG, "on assets copying", tr); } } - }catch(Throwable tr) { - if(tr.getMessage().contains("Permission denied")) { - Log.e(TAG, "Permission denied on assets copying", tr); + catch (Throwable tr) + { + Log.e(TAG,"on assets copying", tr); } - throw new RuntimeException(tr); } } @@ -378,18 +371,15 @@ private static final class NetworkStateCallbackImpl extends ConnectivityManager. @Override public void onAvailable(Network network) { super.onAvailable(network); - //I2PD_JNI.onNetworkStateChanged(true); + I2PD_JNI.onNetworkStateChanged(true); Log.d(TAG, "NetworkCallback.onAvailable"); } @Override public void onLost(Network network) { super.onLost(network); - //I2PD_JNI.onNetworkStateChanged(false); + I2PD_JNI.onNetworkStateChanged(false); Log.d(TAG, " NetworkCallback.onLost"); } } - private String getAppLocale() { - return Locale.getDefault().getDisplayLanguage(Locale.ENGLISH).toLowerCase(); // lower-case system language (like "english") - } } diff --git a/app/src/main/java/org/purplei2p/i2pd/ForegroundService.java b/app/src/main/java/org/purplei2p/i2pd/ForegroundService.java index 7d38575..c6b87e6 100644 --- a/app/src/main/java/org/purplei2p/i2pd/ForegroundService.java +++ b/app/src/main/java/org/purplei2p/i2pd/ForegroundService.java @@ -19,11 +19,6 @@ public class ForegroundService extends Service { private static final String TAG = "FgService"; private volatile boolean shown; - - public static ForegroundService getInstance() { - return instance; - } - private static ForegroundService instance; private static volatile DaemonWrapper daemon; private static final Object initDeinitLock = new Object(); @@ -97,10 +92,6 @@ public int onStartCommand(Intent intent, int flags, int startId) { @Override public void onDestroy() { - stop(); - } - - public void stop() { cancelNotification(); deinitCheck(); instance = null; diff --git a/app/src/main/java/org/purplei2p/i2pd/I2PDActivity.java b/app/src/main/java/org/purplei2p/i2pd/I2PDActivity.java index 19c3f98..2ebdd15 100644 --- a/app/src/main/java/org/purplei2p/i2pd/I2PDActivity.java +++ b/app/src/main/java/org/purplei2p/i2pd/I2PDActivity.java @@ -38,8 +38,6 @@ import static android.provider.Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS; -import org.purplei2p.i2pd.appscope.App; - public class I2PDActivity extends Activity { private static final String TAG = "i2pdActvt"; private static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 1; @@ -47,12 +45,14 @@ public class I2PDActivity extends Activity { public static final String PACKAGE_URI_SCHEME = "package:"; private TextView textView; - /*private CheckBox HTTPProxyState; + private CheckBox HTTPProxyState; private CheckBox SOCKSProxyState; private CheckBox BOBState; private CheckBox SAMState; private CheckBox I2CPState; -*/ + + + private static volatile DaemonWrapper daemon; private final DaemonWrapper.StateUpdateListener daemonStateUpdatedListener = new DaemonWrapper.StateUpdateListener() { @Override @@ -60,10 +60,6 @@ public void daemonStateUpdate(DaemonWrapper.State oldValue, DaemonWrapper.State updateStatusText(); } }; - - private DaemonWrapper getDaemon() { - return App.getDaemonWrapper(); - } private void updateStatusText() { runOnUiThread(() -> { @@ -71,25 +67,23 @@ private void updateStatusText() { if (textView == null) return; - Throwable tr = getDaemon().getLastThrowable(); + Throwable tr = daemon.getLastThrowable(); if (tr != null) { textView.setText(throwableToString(tr)); return; } - DaemonWrapper.State state = getDaemon().getState(); + DaemonWrapper.State state = daemon.getState(); - if (getDaemon().isStartedOkay()) { - /* + if (daemon.isStartedOkay()) { HTTPProxyState.setChecked(I2PD_JNI.getHTTPProxyState()); SOCKSProxyState.setChecked(I2PD_JNI.getSOCKSProxyState()); BOBState.setChecked(I2PD_JNI.getBOBState()); SAMState.setChecked(I2PD_JNI.getSAMState()); I2CPState.setChecked(I2PD_JNI.getI2CPState()); - */ } - String startResultStr = DaemonWrapper.State.startFailed==state ? String.format(": %s", getDaemon().getDaemonStartResult()) : ""; + String startResultStr = DaemonWrapper.State.startFailed.equals(state) ? String.format(": %s", daemon.getDaemonStartResult()) : ""; String graceStr = DaemonWrapper.State.gracefulShutdownInProgress.equals(state) ? String.format(": %s %s", formatGraceTimeRemaining(), getText(R.string.remaining)) : ""; textView.setText(String.format("%s%s%s", getText(state.getStatusStringResourceId()), startResultStr, graceStr)); } catch (Throwable tr) { @@ -119,21 +113,20 @@ public void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); startService(new Intent(this, ForegroundService.class)); textView = (TextView) findViewById(R.id.appStatusText); - /* HTTPProxyState = (CheckBox) findViewById(R.id.service_httpproxy_box); SOCKSProxyState = (CheckBox) findViewById(R.id.service_socksproxy_box); BOBState = (CheckBox) findViewById(R.id.service_bob_box); SAMState = (CheckBox) findViewById(R.id.service_sam_box); - I2CPState = (CheckBox) findViewById(R.id.service_i2cp_box);*/ + I2CPState = (CheckBox) findViewById(R.id.service_i2cp_box); - /*if (getDaemon() == null) { + if (daemon == null) { ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); - getDaemon() = new getDaemon()Wrapper(getAssets(), connectivityManager); + daemon = new DaemonWrapper(getAssets(), connectivityManager); } - ForegroundService.init(getDaemon()); + ForegroundService.init(daemon); - */ - //getDaemon()StateUpdatedListener.getDaemon()StateUpdate(getDaemon()Wrapper.State.uninitialized, App.getgetDaemon()Wrapper().getState()); + daemon.addStateChangeListener(daemonStateUpdatedListener); + daemonStateUpdatedListener.daemonStateUpdate(DaemonWrapper.State.uninitialized, daemon.getState()); // request permissions if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { @@ -149,11 +142,6 @@ public void onCreate(Bundle savedInstanceState) { } } - //here, we might have datadir access permissions, - // it's maybe safe to call daemon start which copies i2pd assets - getDaemon().startDaemonIfStopped(getApplicationContext()); - getDaemon().addStateChangeListener(daemonStateUpdatedListener); - updateStatusText(); doBindService(); final Timer gracefulQuitTimer = getGracefulQuitTimer(); @@ -173,7 +161,7 @@ protected void onDestroy() { super.onDestroy(); textView = null; ForegroundService.deinit(); - getDaemon().removeStateChangeListener(daemonStateUpdatedListener); + daemon.removeStateChangeListener(daemonStateUpdatedListener); //cancelGracefulStop0(); try { doUnbindService(); @@ -306,15 +294,15 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) { onActionBatteryOptimizations(); return true; -/* case R.id.action_reload_tunnels_config: + case R.id.action_reload_tunnels_config: onReloadTunnelsConfig(); - return true;*/ + return true; case R.id.action_start_webview: - if(getDaemon().isStartedOkay()) + if(daemon.isStartedOkay()) startActivity(new Intent(getApplicationContext(), WebConsoleActivity.class)); else - Toast.makeText(this,"I2Pd not started!", Toast.LENGTH_SHORT).show(); + Toast.makeText(this,"I2Pd not was started!", Toast.LENGTH_SHORT).show(); return true; case R.id.action_settings: startActivity(new Intent(getApplicationContext(), SettingsActivity.class)); @@ -337,7 +325,7 @@ private void onActionBatteryOptimizations() { private void onReloadTunnelsConfig() { Log.i(TAG, "reloading tunnels"); - getDaemon().reloadTunnelsConfigs(); + daemon.reloadTunnelsConfigs(); Toast.makeText(this, R.string.tunnels_reloading, Toast.LENGTH_SHORT).show(); } @@ -347,7 +335,7 @@ private void i2pdStop() { textView.setText(getText(R.string.stopping)); new Thread(() -> { try { - getDaemon().stopDaemon(null); + daemon.stopDaemon(); } catch (Throwable tr) { Log.e(TAG, "", tr); } @@ -358,7 +346,7 @@ private void i2pdStop() { private static volatile Timer gracefulQuitTimer; private void i2pdGracefulStop() { - if (getDaemon().getState() == DaemonWrapper.State.stopped) { + if (daemon.getState() == DaemonWrapper.State.stopped) { Toast.makeText(this, R.string.already_stopped, Toast.LENGTH_SHORT).show(); return; } @@ -370,8 +358,8 @@ private void i2pdGracefulStop() { Toast.makeText(this, R.string.graceful_stop_is_in_progress, Toast.LENGTH_SHORT).show(); new Thread(() -> { try { - if (getDaemon().isStartedOkay()) { - getDaemon().stopAcceptingTunnels(); + if (daemon.isStartedOkay()) { + daemon.stopAcceptingTunnels(); long gracefulStopAtMillis; synchronized (graceStartedMillis_LOCK) { graceStartedMillis = System.currentTimeMillis(); @@ -392,8 +380,8 @@ private void cancelGracefulStop() Log.i(TAG, "canceling graceful stop"); new Thread(() -> { try { - if (getDaemon().isStartedOkay()) { - getDaemon().startAcceptingTunnels(); + if (daemon.isStartedOkay()) { + daemon.startAcceptingTunnels(); runOnUiThread(() -> Toast.makeText(this, R.string.shutdown_canceled, Toast.LENGTH_SHORT).show()); } else i2pdStop(); @@ -407,7 +395,7 @@ private void rescheduleGraceStop(Timer gracefulQuitTimerOld, long gracefulStopAt if (gracefulQuitTimerOld != null) gracefulQuitTimerOld.cancel(); - if (getDaemon().getTransitTunnelsCount() <= 0) { // no tunnels left + if (daemon.getTransitTunnelsCount() <= 0) { // no tunnels left Log.i(TAG, "no transit tunnels left, stopping"); i2pdStop(); return; @@ -519,7 +507,7 @@ private void quit() { Log.e(TAG, "", tr); } try { - ((App)getApplication()).quit(); + daemon.stopDaemon(); } catch (Throwable tr) { Log.e(TAG, "", tr); } diff --git a/app/src/main/java/org/purplei2p/i2pd/I2PD_JNI.java b/app/src/main/java/org/purplei2p/i2pd/I2PD_JNI.java new file mode 100644 index 0000000..c1f7d1c --- /dev/null +++ b/app/src/main/java/org/purplei2p/i2pd/I2PD_JNI.java @@ -0,0 +1,35 @@ +package org.purplei2p.i2pd; + +public class I2PD_JNI { + public static native String getABICompiledWith(); + + public static void loadLibraries() { + System.loadLibrary("i2pd"); + } + + /** + * returns error info if failed + * returns "ok" if daemon initialized and started okay + */ + public static native String startDaemon(); + public static native void stopDaemon(); + + public static native void startAcceptingTunnels(); + public static native void stopAcceptingTunnels(); + public static native void reloadTunnelsConfigs(); + + public static native void setDataDir(String jdataDir); + public static native void setLanguage(String jlanguage); + + public static native int getTransitTunnelsCount(); + public static native String getWebConsAddr(); + public static native String getDataDir(); + + public static native boolean getHTTPProxyState(); + public static native boolean getSOCKSProxyState(); + public static native boolean getBOBState(); + public static native boolean getSAMState(); + public static native boolean getI2CPState(); + + public static native void onNetworkStateChanged(boolean isConnected); +} diff --git a/app/src/main/java/org/purplei2p/i2pd/I2pdApi.java b/app/src/main/java/org/purplei2p/i2pd/I2pdApi.java deleted file mode 100644 index 78d932f..0000000 --- a/app/src/main/java/org/purplei2p/i2pd/I2pdApi.java +++ /dev/null @@ -1,154 +0,0 @@ -package org.purplei2p.i2pd; - -import android.content.Context; -import android.util.Log; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStreamReader; - -/** i2pd process API calls via TCP between the Android Java app and i2pd C++-only process. - * TODO - */ -public class I2pdApi { - private static String dataDir; - private static AbstractProcess i2pdProcess; - private static final String TAG = "I2pdApi"; - - /** - * returns error info if failed - * returns "ok" if daemon initialized and started okay - */ - public static String startDaemon(final Context ctx, final String dataDir, String ignoredLanguage, final DaemonWrapper daemonWrapper){ - try { - i2pdProcess = null; - I2pdApi.dataDir = dataDir; - File pidFile = new File(dataDir, "i2pd.pid"); - Log.i(TAG,"Launching an i2pd process"); - final Process p = Runtime.getRuntime().exec(new String[]{ - "/system/bin/sh", - "-c", - "ulimit -c unlimited && "+ - ctx.getApplicationInfo().nativeLibraryDir + - "/libi2pd.so --datadir=" + dataDir + - " --pidfile=" + pidFile.getAbsolutePath() + - " > "+dataDir+"/s.log 2>&1" - }); - i2pdProcess = (Throwable tr) -> { - try { - if (tr != null) - Log.e(TAG, "destroying the subprocess \"i2pd\", reason: " + tr, tr); - else - Log.e(TAG, "destroying the subprocess \"i2pd\", reason: null"); - p.destroy(); - } catch (Throwable tr2) { - Log.e(TAG, "", tr2); - } - }; - new Thread(() -> { - try { - try (BufferedInputStream bis = new BufferedInputStream(p.getInputStream())) { - try (InputStreamReader sr = new InputStreamReader(bis)) { - try (BufferedReader r = new BufferedReader(sr)) { - while (true) { - String s = r.readLine(); - if (s == null) break; - Log.i(TAG, s); - } - } - } - } - } catch (Throwable tr) { - Log.e(TAG, "", tr); - } - }, "i2pd-stdout").start(); - new Thread(() -> { - try { - try (BufferedInputStream bis = new BufferedInputStream(p.getErrorStream())) { - try (InputStreamReader sr = new InputStreamReader(bis)) { - try (BufferedReader r = new BufferedReader(sr)) { - while (true) { - String s = r.readLine(); - if (s == null) break; - Log.i(TAG, s); - } - } - } - } - } catch (Throwable tr) { - Log.e(TAG, "", tr); - } - try { - p.waitFor(); - } catch (Throwable tr) { - Log.e(TAG, "", tr); - } - final int errorLevel = p.exitValue(); - Log.i(TAG, "i2pd process exit code: " + errorLevel); - final Throwable trReason = new Throwable("subprocess \"i2pd\" exited with exit code " + errorLevel); - try { - stopDaemon(trReason); - Log.i(TAG, "stopDaemon completed"); - } catch (Throwable tr) { - Log.e(TAG, "Called stopDaemon, got exception", tr); - } - new Thread(() -> { - try { - daemonWrapper.stopDaemon(trReason); - Log.i(TAG, "daemonWrapper.stopDaemon completed"); - } catch (Throwable tr) { - Log.e(TAG, "Called daemonWrapper.stopDaemon, got exception", tr); - } - }, "stop the daemonWrapper thread").start(); - }, "i2pd-stderr").start(); - new Thread(() -> { - try { -// try (BufferedOutputStream bos = new BufferedOutputStream(p.getOutputStream())) { -// try (OutputStreamWriter sr = new OutputStreamWriter(bos)) { -// try (BufferedWriter r = new BufferedWriter(sr)) { - while (true) { - synchronized (Thread.currentThread()) { - Thread.currentThread().wait(100); - } - } -// } -// } -// } - } catch (Throwable tr) { - Log.e(TAG, "", tr); - } - }, "i2pd-stdin").start(); - return "ok"; - } catch (Throwable tr) { - Log.e(TAG, "", tr); - return "Error in exec(): " + tr; - } - } - - public static void stopDaemon(Throwable tr){ - AbstractProcess p = i2pdProcess; - if (p != null) { - p.kill(tr); - i2pdProcess = null; - } - } - - public static void startAcceptingTunnels(){} - public static void stopAcceptingTunnels(){} - public static void reloadTunnelsConfigs(){} - - public static int getTransitTunnelsCount(){return -1;} - public static String getWebConsAddr(){return "";} - public static String getDataDir() { - return dataDir; - } - - public static boolean getHTTPProxyState(){return false;} - public static boolean getSOCKSProxyState(){return false;} - public static boolean getBOBState(){return false;} - public static boolean getSAMState(){return false;} - public static boolean getI2CPState(){return false;} - - public static void onNetworkStateChanged(boolean isConnected){} -} diff --git a/app/src/main/java/org/purplei2p/i2pd/NetworkStateChangeReceiver.java b/app/src/main/java/org/purplei2p/i2pd/NetworkStateChangeReceiver.java index 27509da..35975a0 100644 --- a/app/src/main/java/org/purplei2p/i2pd/NetworkStateChangeReceiver.java +++ b/app/src/main/java/org/purplei2p/i2pd/NetworkStateChangeReceiver.java @@ -19,7 +19,7 @@ public void onReceive(final Context context, final Intent intent) { NetworkInfo activeNetworkInfo = cm.getActiveNetworkInfo(); boolean isConnected = activeNetworkInfo != null && activeNetworkInfo.isConnected(); - //I2PD_JNI.onNetworkStateChanged(isConnected); + I2PD_JNI.onNetworkStateChanged(isConnected); } catch (Throwable tr) { Log.e(TAG, "", tr); } diff --git a/app/src/main/java/org/purplei2p/i2pd/WebConsoleActivity.java b/app/src/main/java/org/purplei2p/i2pd/WebConsoleActivity.java index 7df7c2a..e96d068 100644 --- a/app/src/main/java/org/purplei2p/i2pd/WebConsoleActivity.java +++ b/app/src/main/java/org/purplei2p/i2pd/WebConsoleActivity.java @@ -27,7 +27,7 @@ protected void onCreate(Bundle savedInstanceState) { final WebSettings webSettings = webView.getSettings(); webSettings.setBuiltInZoomControls(true); webSettings.setJavaScriptEnabled(false); - webView.loadUrl("http://localhost:7070/"/*I2PD_JNI.getWebConsAddr()*/); + webView.loadUrl(I2PD_JNI.getWebConsAddr()); swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipe); swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { diff --git a/app/src/main/java/org/purplei2p/i2pd/appscope/App.java b/app/src/main/java/org/purplei2p/i2pd/appscope/App.java deleted file mode 100644 index d624b96..0000000 --- a/app/src/main/java/org/purplei2p/i2pd/appscope/App.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.purplei2p.i2pd.appscope; - -import android.app.Application; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.net.ConnectivityManager; -import android.os.IBinder; -import android.util.Log; - -import org.purplei2p.i2pd.BuildConfig; -import org.purplei2p.i2pd.I2PDActivity; -import org.purplei2p.i2pd.*; - -public class App extends Application { - private static final String TAG = "i2pd.app"; - - //private static final I2PD_JNI jniHolder = new I2PD_JNI(); - - private static volatile DaemonWrapper daemonWrapper; - private String versionName; - - private static volatile boolean mIsBound; - - - - public synchronized static DaemonWrapper getDaemonWrapper() { - return daemonWrapper; - } - - @Override - public void onCreate() { - super.onCreate(); - synchronized (this) { - if (getDaemonWrapper() == null) { - createDaemonWrapper(); - } - versionName = BuildConfig.VERSION_NAME; - doBindService(); - startService(new Intent(this, ForegroundService.class)); - } - } - - private void createDaemonWrapper() { - ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService( - Context.CONNECTIVITY_SERVICE); - daemonWrapper = new DaemonWrapper(getApplicationContext(), getAssets(), connectivityManager); - ForegroundService.init(daemonWrapper); - } - - private synchronized void doBindService() { - if (mIsBound) - return; - // Establish a connection with the service. We use an explicit - // class name because we want a specific service implementation that - // we know will be running in our own process (and thus won't be - // supporting component replacement by other applications). - bindService(new Intent(this, ForegroundService.class), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; - } - - private synchronized void doUnbindService() { - if (mIsBound) { - // Detach our existing connection. - unbindService(mConnection); - mIsBound = false; - } - } - - @Override - public void onTerminate() { - quit(); - super.onTerminate(); - } - - private final ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - /* This is called when the connection with the service has been - established, giving us the service object we can use to - interact with the service. Because we have bound to a explicit - service that we know is running in our own process, we can - cast its IBinder to a concrete class and directly access it. */ - // mBoundService = ((LocalService.LocalBinder)service).getService(); - - /* Tell the user about this for our demo. */ - // Toast.makeText(Binding.this, R.string.local_service_connected, - // Toast.LENGTH_SHORT).show(); - } - - public void onServiceDisconnected(ComponentName className) { - /* This is called when the connection with the service has been - unexpectedly disconnected -- that is, its process crashed. - Because it is running in our same process, we should never - see this happen. */ - // mBoundService = null; - // Toast.makeText(Binding.this, R.string.local_service_disconnected, - // Toast.LENGTH_SHORT).show(); - } - }; - - public synchronized void quit() { - try { - if(daemonWrapper!=null)daemonWrapper.stopDaemon(null); - } catch (Throwable tr) { - Log.e(TAG, "", tr); - } - try { - doUnbindService(); - } catch (IllegalArgumentException ex) { - Log.e(TAG, "throwable caught and ignored", ex); - if (ex.getMessage().startsWith("Service not registered: " + I2PDActivity.class.getName())) { - Log.i(TAG, "Service not registered exception seems to be normal, not a bug it seems."); - } - } catch (Throwable tr) { - Log.e(TAG, "throwable caught and ignored", tr); - } - try{ - ForegroundService fs = ForegroundService.getInstance(); - if(fs!=null)fs.stop(); - }catch(Throwable tr) { - Log.e(TAG, "", tr); - } - - } -} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 805bdd6..793a9ae 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -58,7 +58,7 @@ - + diff --git a/app/src/main/res/menu/options_main.xml b/app/src/main/res/menu/options_main.xml index c1157a4..6857d41 100644 --- a/app/src/main/res/menu/options_main.xml +++ b/app/src/main/res/menu/options_main.xml @@ -15,10 +15,10 @@ android:id="@+id/action_start_webview" android:orderInCategory="96" android:title="@string/action_start_webview" /> - + android:title="@string/action_reload_tunnels_config" /> /dev/null diff --git a/binary/libs/.gitkeep b/binary/libs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/fastlane/metadata/android/en-US/changelogs/2530010.txt b/fastlane/metadata/android/en-US/changelogs/2530010.txt new file mode 100644 index 0000000..d427eae --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/2530010.txt @@ -0,0 +1,2 @@ +* Updated codebase to 2.53.1 +* Revert to usage of the JNI