From d41fabbc9fdcb324ecab7796775398a6f78219fc Mon Sep 17 00:00:00 2001 From: unknown542a Date: Sat, 6 Jan 2018 23:59:22 +0300 Subject: [PATCH 1/8] netDB and certificates in internal storage --- .../src/org/purplei2p/i2pd/Decompress.java | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 android/src/org/purplei2p/i2pd/Decompress.java diff --git a/android/src/org/purplei2p/i2pd/Decompress.java b/android/src/org/purplei2p/i2pd/Decompress.java new file mode 100644 index 00000000..917abc7c --- /dev/null +++ b/android/src/org/purplei2p/i2pd/Decompress.java @@ -0,0 +1,83 @@ +package org.purplei2p.i2pd; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import android.content.Context; +import android.util.Log; + +public class Decompress { + private static final int BUFFER_SIZE = 1024 * 10; + private static final String TAG = "Decompress"; + + public static void unzipFromAssets(Context context, String zipFile, String destination) { + try { + if (destination == null || destination.length() == 0) + destination = context.getFilesDir().getAbsolutePath(); + InputStream stream = context.getAssets().open(zipFile); + unzip(stream, destination); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void unzip(String zipFile, String location) { + try { + FileInputStream fin = new FileInputStream(zipFile); + unzip(fin, location); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + } + + public static void unzip(InputStream stream, String destination) { + dirChecker(destination, ""); + byte[] buffer = new byte[BUFFER_SIZE]; + try { + ZipInputStream zin = new ZipInputStream(stream); + ZipEntry ze = null; + + while ((ze = zin.getNextEntry()) != null) { + Log.v(TAG, "Unzipping " + ze.getName()); + + if (ze.isDirectory()) { + dirChecker(destination, ze.getName()); + } else { + File f = new File(destination + ze.getName()); + if (!f.exists()) { + FileOutputStream fout = new FileOutputStream(destination + ze.getName()); + int count; + while ((count = zin.read(buffer)) != -1) { + fout.write(buffer, 0, count); + } + zin.closeEntry(); + fout.close(); + } + } + + } + zin.close(); + } catch (Exception e) { + Log.e(TAG, "unzip", e); + } + + } + + private static void dirChecker(String destination, String dir) { + File f = new File(destination + dir); + + if (!f.isDirectory()) { + boolean success = f.mkdirs(); + if (!success) { + Log.w(TAG, "Failed to create folder " + f.getName()); + } + } + } +} From 81d7a832c098d21df939eea2e2d74312c1ba8232 Mon Sep 17 00:00:00 2001 From: unknown542a Date: Sun, 7 Jan 2018 00:08:07 +0300 Subject: [PATCH 2/8] netDB and certificates in internal storage --- android/.gitignore | 6 ++- android/build.gradle | 47 +++++++++++++++--------- android/jni/DaemonAndroid.cpp | 5 +-- android/jni/DaemonAndroid.h | 2 +- android/jni/i2pd_android.cpp | 11 +++++- android/src/org/purplei2p/i2pd/I2PD.java | 12 +++++- 6 files changed, 59 insertions(+), 24 deletions(-) diff --git a/android/.gitignore b/android/.gitignore index d9fa5a57..7e166aa6 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -5,4 +5,8 @@ ant.properties local.properties build.sh bin -log* \ No newline at end of file +log* +.gradle* +build +assets +gradle-app.setting diff --git a/android/build.gradle b/android/build.gradle index a88403fd..b69967ef 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,26 +8,32 @@ buildscript { } } +task clean(type: Delete,overwrite: true) { + delete 'build' + delete 'assets' +} + apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" - defaultConfig { - applicationId "org.purplei2p.i2pd" - targetSdkVersion 25 - minSdkVersion 14 - versionCode 1 - versionName "2.17.1" - } + compileSdkVersion 25 + buildToolsVersion "25.0.0" + defaultConfig { + applicationId "org.purplei2p.i2pd" + targetSdkVersion 25 + minSdkVersion 14 + versionCode 1 + versionName "2.17.2b" + } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] - res.srcDirs = ['res'] - jniLibs.srcDirs = ['libs'] - } + res.srcDirs = ['res'] + jniLibs.srcDirs = ['libs'] + assets.srcDirs = ['assets'] } + } signingConfigs { orignal { storeFile file("i2pdapk.jks") @@ -37,11 +43,18 @@ android { } } buildTypes { - release { - minifyEnabled false - signingConfig signingConfigs.orignal - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' - } + release { + minifyEnabled false + signingConfig signingConfigs.orignal + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' + } } } +task zipCerts(type: Zip) { + archiveName 'certificates.zip' + destinationDir file('assets') + from (files('../contrib/certificates')) +} + +preBuild.dependsOn zipCerts diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 75584740..9865ac79 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -126,12 +126,11 @@ namespace android } */ 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[]*/) + std::string start(int argc, char* argv[]) { try { @@ -139,7 +138,7 @@ namespace android { //Log.d(TAG"Initialising the daemon..."); - bool daemonInitSuccess = daemon.init(1,argv); + bool daemonInitSuccess = daemon.init(argc,argv); if(!daemonInitSuccess) { //QMessageBox::critical(0, "Error", "Daemon init failed"); diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h index 9cc8219b..81031936 100644 --- a/android/jni/DaemonAndroid.h +++ b/android/jni/DaemonAndroid.h @@ -37,7 +37,7 @@ namespace android * returns "ok" if daemon init failed * returns errinfo if daemon initialized and started okay */ - std::string start(); + std::string start(int argc, char* argv[]); // stops the daemon void stop(); diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp index 8791c90b..b4bfa6e6 100755 --- a/android/jni/i2pd_android.cpp +++ b/android/jni/i2pd_android.cpp @@ -45,7 +45,16 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon (JNIEnv * env, jclass clazz) { - return env->NewStringUTF(i2p::android::start().c_str()); + + int argc=5; + static char* argv[]={ + "i2pd", "--service", "--daemon", + "--conf=/sdcard/i2pd/i2pd.conf", + "--tunconf=/sdcard/i2pd/tunnels.conf", + "--datadir=/data/data/org.purplei2p.i2pd/app_data/" + }; + + return env->NewStringUTF(i2p::android::start(argc,argv).c_str()); } JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon diff --git a/android/src/org/purplei2p/i2pd/I2PD.java b/android/src/org/purplei2p/i2pd/I2PD.java index 86b877ac..869cf570 100755 --- a/android/src/org/purplei2p/i2pd/I2PD.java +++ b/android/src/org/purplei2p/i2pd/I2PD.java @@ -2,6 +2,13 @@ package org.purplei2p.i2pd; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + import java.util.Timer; import java.util.TimerTask; @@ -26,7 +33,7 @@ public class I2PD extends Activity { private TextView textView; private final DaemonSingleton daemon = DaemonSingleton.getInstance(); - + private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton.StateUpdateListener() { @@ -58,6 +65,9 @@ public class I2PD extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + //install certs every time + Decompress.unzipFromAssets(this, "certificates.zip", "/data/data/org.purplei2p.i2pd/app_data/"); + textView = new TextView(this); setContentView(textView); DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); From 8864cbf80ad50146757985b6b36a5aaa94aa91ff Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Sun, 7 Jan 2018 00:40:17 +0300 Subject: [PATCH 3/8] return to strdup() when filling argv[] for i2p::android::start(argc,argv).c_str() --- android/build.gradle | 2 +- android/jni/i2pd_android.cpp | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index b69967ef..fb2fe8c6 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -23,7 +23,7 @@ android { targetSdkVersion 25 minSdkVersion 14 versionCode 1 - versionName "2.17.2b" + versionName "2.17.2c" } sourceSets { main { diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp index b4bfa6e6..ac1e2b70 100755 --- a/android/jni/i2pd_android.cpp +++ b/android/jni/i2pd_android.cpp @@ -46,13 +46,14 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon (JNIEnv * env, jclass clazz) { - int argc=5; - static char* argv[]={ - "i2pd", "--service", "--daemon", - "--conf=/sdcard/i2pd/i2pd.conf", - "--tunconf=/sdcard/i2pd/tunnels.conf", - "--datadir=/data/data/org.purplei2p.i2pd/app_data/" - }; + int argc=5; + static char* argv[]={ + strdup("i2pd"), + strdup("--conf=/sdcard/i2pd/i2pd.conf"), + strdup("--tunconf=/sdcard/i2pd/tunnels.conf"), + strdup("--datadir=/data/data/org.purplei2p.i2pd/app_data/"), + strdup("--service"), strdup("--daemon") + }; return env->NewStringUTF(i2p::android::start(argc,argv).c_str()); } From cf5081d300051b7c188ff39aacadad29d492900e Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Sun, 7 Jan 2018 19:30:32 +0300 Subject: [PATCH 4/8] fixed creating certificates.zip when target zip did not include the directory certificates, so they were bein unpacked into datadir. Added entryCompression ZipEntryCompression.STORED since final APK is being compressed as well. Put all custom tasks under android plugin definitions --- android/build.gradle | 22 ++++++++++++---------- android/gradle.properties | 1 + 2 files changed, 13 insertions(+), 10 deletions(-) create mode 100644 android/gradle.properties diff --git a/android/build.gradle b/android/build.gradle index fb2fe8c6..fcbb47ec 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,11 +8,6 @@ buildscript { } } -task clean(type: Delete,overwrite: true) { - delete 'build' - delete 'assets' -} - apply plugin: 'com.android.application' android { @@ -23,7 +18,7 @@ android { targetSdkVersion 25 minSdkVersion 14 versionCode 1 - versionName "2.17.2c" + versionName "2.17.2e" } sourceSets { main { @@ -51,10 +46,17 @@ android { } } -task zipCerts(type: Zip) { - archiveName 'certificates.zip' +task zipCerts(type:Zip) { + from (files('../contrib/')) + include 'certificates/**/*.crt' destinationDir file('assets') - from (files('../contrib/certificates')) + archiveName 'certificates.zip' + entryCompression ZipEntryCompression.STORED } - preBuild.dependsOn zipCerts + +task clean(type: Delete,overwrite: true) { + delete 'build' + delete 'assets' +} + diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 00000000..e32ec00b --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 From bc72800fef9aa42bef305bb6700da167c5ba00fe Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Wed, 17 Jan 2018 20:58:56 +0300 Subject: [PATCH 5/8] moved hard code into java side and successfully passed back to native --- android/jni/i2pd_android.cpp | 29 ++++++++++++------- android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 2 +- .../org/purplei2p/i2pd/DaemonSingleton.java | 11 ++++++- android/src/org/purplei2p/i2pd/I2PD_JNI.java | 2 +- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp index ac1e2b70..5a8d8eaf 100755 --- a/android/jni/i2pd_android.cpp +++ b/android/jni/i2pd_android.cpp @@ -44,18 +44,27 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith } JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv * env, jclass clazz) { + (JNIEnv * env, jclass clazz, jobjectArray args) { + int argc = env->GetArrayLength(args); + typedef char *pchar; + pchar* argv = new pchar[argc]; + for (int i = 0; i < argc; i++) { + jstring arg = (jstring) env->GetObjectArrayElement(args, i); + const char *argStr = env->GetStringUTFChars(arg, 0); + size_t len = strlen(argStr); + argv[i] = new char[len + 1]; + strcpy(argv[i], argStr); + env->ReleaseStringUTFChars(arg, argStr); + } - int argc=5; - static char* argv[]={ - strdup("i2pd"), - strdup("--conf=/sdcard/i2pd/i2pd.conf"), - strdup("--tunconf=/sdcard/i2pd/tunnels.conf"), - strdup("--datadir=/data/data/org.purplei2p.i2pd/app_data/"), - strdup("--service"), strdup("--daemon") - }; + const char* result = i2p::android::start(argc,argv).c_str(); + + for (int i = 0; i < argc; i++) { + delete [] argv[i]; + } + delete [] argv; - return env->NewStringUTF(i2p::android::start(argc,argv).c_str()); + return env->NewStringUTF(result); } JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h index 04923d22..484b3230 100644 --- a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h +++ b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h @@ -16,7 +16,7 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith (JNIEnv *, jclass); JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv *, jclass); + (JNIEnv *, jclass, jobjectArray args); JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon (JNIEnv *, jclass); diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java index e1ebc269..e95e0df1 100644 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java @@ -62,7 +62,16 @@ public class DaemonSingleton { } try { synchronized (DaemonSingleton.this) { - daemonStartResult = I2PD_JNI.startDaemon(); + String args[] = { + "i2pd", + "--conf=/sdcard/i2pd/i2pd.conf", + "--tunconf=/sdcard/i2pd/tunnels.conf", + "--datadir=/data/data/org.purplei2p.i2pd/app_data/", + "--service", + "--daemon" + }; + + daemonStartResult = I2PD_JNI.startDaemon(args); if("ok".equals(daemonStartResult)){ state=State.startedOkay; setStartedOkay(true); diff --git a/android/src/org/purplei2p/i2pd/I2PD_JNI.java b/android/src/org/purplei2p/i2pd/I2PD_JNI.java index 5a3addbf..bfdf8967 100644 --- a/android/src/org/purplei2p/i2pd/I2PD_JNI.java +++ b/android/src/org/purplei2p/i2pd/I2PD_JNI.java @@ -6,7 +6,7 @@ public class I2PD_JNI { * returns error info if failed * returns "ok" if daemon initialized and started okay */ - public static native String startDaemon(); + public static native String startDaemon(String args[]); //should only be called after startDaemon() success public static native void stopDaemon(); From 0bd4db4cc795d968e1f24fa81d95179d3fdf394a Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 18 Jan 2018 16:41:02 +0300 Subject: [PATCH 6/8] less lines --- android/jni/i2pd_android.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp index 5a8d8eaf..19f78a8d 100755 --- a/android/jni/i2pd_android.cpp +++ b/android/jni/i2pd_android.cpp @@ -56,14 +56,11 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon strcpy(argv[i], argStr); env->ReleaseStringUTFChars(arg, argStr); } - const char* result = i2p::android::start(argc,argv).c_str(); - for (int i = 0; i < argc; i++) { delete [] argv[i]; } delete [] argv; - return env->NewStringUTF(result); } From 4c6988e3bc9ebd1d34e0b5faa50748c75a160c8b Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Thu, 18 Jan 2018 19:35:37 +0300 Subject: [PATCH 7/8] code cleanup --- android/build.gradle | 5 +++++ android/gradle.properties | 2 +- .../src/org/purplei2p/i2pd/DaemonSingleton.java | 17 ++++++++--------- .../org/purplei2p/i2pd/ForegroundService.java | 13 +++++++++++-- android/src/org/purplei2p/i2pd/I2PD.java | 2 +- 5 files changed, 26 insertions(+), 13 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index fcbb47ec..46d0d057 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -46,6 +46,11 @@ android { } } +tasks.withType(JavaCompile) { + options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation' + options.deprecation = true +} + task zipCerts(type:Zip) { from (files('../contrib/')) include 'certificates/**/*.crt' diff --git a/android/gradle.properties b/android/gradle.properties index e32ec00b..d8894a70 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1 +1 @@ -org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +org.gradle.jvmargs=-Xmx2048M -XX:MaxPermSize=256M -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java index e95e0df1..031a7ef1 100644 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java @@ -38,7 +38,7 @@ public class DaemonSingleton { public State getState() { return state; } - public synchronized void start() { + public synchronized void start(final String confDir, final String dataDir) { if(state != State.uninitialized)return; state = State.starting; fireStateUpdate(); @@ -62,14 +62,13 @@ public class DaemonSingleton { } try { synchronized (DaemonSingleton.this) { - String args[] = { - "i2pd", - "--conf=/sdcard/i2pd/i2pd.conf", - "--tunconf=/sdcard/i2pd/tunnels.conf", - "--datadir=/data/data/org.purplei2p.i2pd/app_data/", - "--service", - "--daemon" - }; + + String args[] = new String[] { + "i2pd", "--service", "--daemon", + "--datadir=" + dataDir, + "--conf=" + confDir + "/i2pd.conf", + "--tunconf=" + confDir + "/tunnels.conf" + }; daemonStartResult = I2PD_JNI.startDaemon(args); if("ok".equals(daemonStartResult)){ diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index d25d0a88..645d0dca 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -5,6 +5,8 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; +import android.content.Context; +import android.os.Environment; import android.os.Binder; import android.os.IBinder; import android.util.Log; @@ -28,13 +30,20 @@ public class ForegroundService extends Service { } } + private String dataDir; + private String confDir; + @Override public void onCreate() { notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + dataDir = this.getDir("data", Context.MODE_PRIVATE).toString(); + confDir = Environment.getExternalStoragePublicDirectory("i2pd").toString(); // Display a notification about us starting. We put an icon in the status bar. showNotification(); - daemon.start(); + + Log.i("ForegroundService", "About to start daemon with dataDir: " + dataDir + ", confDir: " + confDir); + daemon.start(confDir, dataDir); // Tell the user we started. Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); } @@ -42,7 +51,7 @@ public class ForegroundService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("ForegroundService", "Received start id " + startId + ": " + intent); - daemon.start(); + daemon.start(confDir, dataDir); return START_STICKY; } diff --git a/android/src/org/purplei2p/i2pd/I2PD.java b/android/src/org/purplei2p/i2pd/I2PD.java index 869cf570..b9d8d037 100755 --- a/android/src/org/purplei2p/i2pd/I2PD.java +++ b/android/src/org/purplei2p/i2pd/I2PD.java @@ -66,7 +66,7 @@ public class I2PD extends Activity { super.onCreate(savedInstanceState); //install certs every time - Decompress.unzipFromAssets(this, "certificates.zip", "/data/data/org.purplei2p.i2pd/app_data/"); + Decompress.unzipFromAssets(this, "certificates.zip", this.getDir("data", Context.MODE_PRIVATE).toString() + "/" ); textView = new TextView(this); setContentView(textView); From 347a2c215001f888f047c3fe26834477dec15567 Mon Sep 17 00:00:00 2001 From: unlnown542a Date: Mon, 22 Jan 2018 01:30:21 +0300 Subject: [PATCH 8/8] fixing conflicts --- android/.gitignore | 6 +- android/build.gradle | 54 ++++++++---- android/jni/DaemonAndroid.cpp | 5 +- android/jni/DaemonAndroid.h | 2 +- android/jni/i2pd_android.cpp | 20 ++++- android/jni/org_purplei2p_i2pd_I2PD_JNI.h | 2 +- .../org/purplei2p/i2pd/DaemonSingleton.java | 39 +++++---- .../src/org/purplei2p/i2pd/Decompress.java | 83 +++++++++++++++++++ .../org/purplei2p/i2pd/ForegroundService.java | 17 +++- android/src/org/purplei2p/i2pd/I2PD.java | 26 ++++-- android/src/org/purplei2p/i2pd/I2PD_JNI.java | 6 +- 11 files changed, 205 insertions(+), 55 deletions(-) create mode 100644 android/src/org/purplei2p/i2pd/Decompress.java diff --git a/android/.gitignore b/android/.gitignore index d9fa5a57..7e166aa6 100644 --- a/android/.gitignore +++ b/android/.gitignore @@ -5,4 +5,8 @@ ant.properties local.properties build.sh bin -log* \ No newline at end of file +log* +.gradle* +build +assets +gradle-app.setting diff --git a/android/build.gradle b/android/build.gradle index a88403fd..46d0d057 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -11,23 +11,24 @@ buildscript { apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" - defaultConfig { - applicationId "org.purplei2p.i2pd" - targetSdkVersion 25 - minSdkVersion 14 - versionCode 1 - versionName "2.17.1" - } + compileSdkVersion 25 + buildToolsVersion "25.0.0" + defaultConfig { + applicationId "org.purplei2p.i2pd" + targetSdkVersion 25 + minSdkVersion 14 + versionCode 1 + versionName "2.17.2e" + } sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] - res.srcDirs = ['res'] - jniLibs.srcDirs = ['libs'] - } + res.srcDirs = ['res'] + jniLibs.srcDirs = ['libs'] + assets.srcDirs = ['assets'] } + } signingConfigs { orignal { storeFile file("i2pdapk.jks") @@ -37,11 +38,30 @@ android { } } buildTypes { - release { - minifyEnabled false - signingConfig signingConfigs.orignal - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' - } + release { + minifyEnabled false + signingConfig signingConfigs.orignal + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' + } } } +tasks.withType(JavaCompile) { + options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation' + options.deprecation = true +} + +task zipCerts(type:Zip) { + from (files('../contrib/')) + include 'certificates/**/*.crt' + destinationDir file('assets') + archiveName 'certificates.zip' + entryCompression ZipEntryCompression.STORED +} +preBuild.dependsOn zipCerts + +task clean(type: Delete,overwrite: true) { + delete 'build' + delete 'assets' +} + diff --git a/android/jni/DaemonAndroid.cpp b/android/jni/DaemonAndroid.cpp index 75584740..9865ac79 100644 --- a/android/jni/DaemonAndroid.cpp +++ b/android/jni/DaemonAndroid.cpp @@ -126,12 +126,11 @@ namespace android } */ 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[]*/) + std::string start(int argc, char* argv[]) { try { @@ -139,7 +138,7 @@ namespace android { //Log.d(TAG"Initialising the daemon..."); - bool daemonInitSuccess = daemon.init(1,argv); + bool daemonInitSuccess = daemon.init(argc,argv); if(!daemonInitSuccess) { //QMessageBox::critical(0, "Error", "Daemon init failed"); diff --git a/android/jni/DaemonAndroid.h b/android/jni/DaemonAndroid.h index 9cc8219b..81031936 100644 --- a/android/jni/DaemonAndroid.h +++ b/android/jni/DaemonAndroid.h @@ -37,7 +37,7 @@ namespace android * returns "ok" if daemon init failed * returns errinfo if daemon initialized and started okay */ - std::string start(); + std::string start(int argc, char* argv[]); // stops the daemon void stop(); diff --git a/android/jni/i2pd_android.cpp b/android/jni/i2pd_android.cpp index 8791c90b..1079a252 100755 --- a/android/jni/i2pd_android.cpp +++ b/android/jni/i2pd_android.cpp @@ -44,8 +44,24 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith } JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv * env, jclass clazz) { - return env->NewStringUTF(i2p::android::start().c_str()); + (JNIEnv * env, jclass clazz, jobjectArray args) { + int argc = env->GetArrayLength(args); + typedef char *pchar; + pchar* argv = new pchar[argc]; + for (int i = 0; i < argc; i++) { + jstring arg = (jstring) env->GetObjectArrayElement(args, i); + const char *argStr = env->GetStringUTFChars(arg, 0); + size_t len = strlen(argStr); + argv[i] = new char[len + 1]; + strcpy(argv[i], argStr); + env->ReleaseStringUTFChars(arg, argStr); + } + const char* result = i2p::android::start(argc,argv).c_str(); + for (int i = 0; i < argc; i++) { + delete [] argv[i]; + } + delete [] argv; + return env->NewStringUTF(result); } JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon diff --git a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h index 04923d22..484b3230 100644 --- a/android/jni/org_purplei2p_i2pd_I2PD_JNI.h +++ b/android/jni/org_purplei2p_i2pd_I2PD_JNI.h @@ -16,7 +16,7 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith (JNIEnv *, jclass); JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon - (JNIEnv *, jclass); + (JNIEnv *, jclass, jobjectArray args); JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon (JNIEnv *, jclass); diff --git a/android/src/org/purplei2p/i2pd/DaemonSingleton.java b/android/src/org/purplei2p/i2pd/DaemonSingleton.java index 65afd0f5..beff0c39 100644 --- a/android/src/org/purplei2p/i2pd/DaemonSingleton.java +++ b/android/src/org/purplei2p/i2pd/DaemonSingleton.java @@ -14,10 +14,10 @@ public class DaemonSingleton { public static DaemonSingleton getInstance() { return instance; } - + public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } - + public synchronized void stopAcceptingTunnels() { if(isStartedOkay()){ state=State.gracefulShutdownInProgress; @@ -25,20 +25,21 @@ public class DaemonSingleton { I2PD_JNI.stopAcceptingTunnels(); } } - + public void onNetworkStateChange(boolean isConnected) { I2PD_JNI.onNetworkStateChanged(isConnected); } - + private boolean startedOkay; public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress}; - + private State state = State.uninitialized; - + public State getState() { return state; } + + public synchronized void start(final String confDir, final String dataDir) { - public synchronized void start() { if(state != State.uninitialized)return; state = State.starting; fireStateUpdate(); @@ -62,7 +63,15 @@ public class DaemonSingleton { } try { synchronized (DaemonSingleton.this) { - daemonStartResult = I2PD_JNI.startDaemon(); + + String args[] = new String[] { + "i2pd", "--service", "--daemon", + "--datadir=" + dataDir, + "--conf=" + confDir + "/i2pd.conf", + "--tunconf=" + confDir + "/tunnels.conf" + }; + + daemonStartResult = I2PD_JNI.startDaemon(args); if("ok".equals(daemonStartResult)){ state=State.startedOkay; setStartedOkay(true); @@ -76,9 +85,9 @@ public class DaemonSingleton { fireStateUpdate(); } return; - } + } } - + }, "i2pdDaemonStart").start(); } private Throwable lastThrowable; @@ -87,10 +96,10 @@ public class DaemonSingleton { private synchronized void fireStateUpdate() { Log.i(TAG, "daemon state change: "+state); for(StateUpdateListener listener : stateUpdateListeners) { - try { - listener.daemonStateUpdate(); - } catch (Throwable tr) { - Log.e(TAG, "exception in listener ignored", tr); + try { + listener.daemonStateUpdate(); + } catch (Throwable tr) { + Log.e(TAG, "exception in listener ignored", tr); } } } @@ -102,7 +111,7 @@ public class DaemonSingleton { public String getDaemonStartResult() { return daemonStartResult; } - + private final Object startedOkayLock = new Object(); public boolean isStartedOkay() { diff --git a/android/src/org/purplei2p/i2pd/Decompress.java b/android/src/org/purplei2p/i2pd/Decompress.java new file mode 100644 index 00000000..917abc7c --- /dev/null +++ b/android/src/org/purplei2p/i2pd/Decompress.java @@ -0,0 +1,83 @@ +package org.purplei2p.i2pd; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import android.content.Context; +import android.util.Log; + +public class Decompress { + private static final int BUFFER_SIZE = 1024 * 10; + private static final String TAG = "Decompress"; + + public static void unzipFromAssets(Context context, String zipFile, String destination) { + try { + if (destination == null || destination.length() == 0) + destination = context.getFilesDir().getAbsolutePath(); + InputStream stream = context.getAssets().open(zipFile); + unzip(stream, destination); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void unzip(String zipFile, String location) { + try { + FileInputStream fin = new FileInputStream(zipFile); + unzip(fin, location); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + } + + public static void unzip(InputStream stream, String destination) { + dirChecker(destination, ""); + byte[] buffer = new byte[BUFFER_SIZE]; + try { + ZipInputStream zin = new ZipInputStream(stream); + ZipEntry ze = null; + + while ((ze = zin.getNextEntry()) != null) { + Log.v(TAG, "Unzipping " + ze.getName()); + + if (ze.isDirectory()) { + dirChecker(destination, ze.getName()); + } else { + File f = new File(destination + ze.getName()); + if (!f.exists()) { + FileOutputStream fout = new FileOutputStream(destination + ze.getName()); + int count; + while ((count = zin.read(buffer)) != -1) { + fout.write(buffer, 0, count); + } + zin.closeEntry(); + fout.close(); + } + } + + } + zin.close(); + } catch (Exception e) { + Log.e(TAG, "unzip", e); + } + + } + + private static void dirChecker(String destination, String dir) { + File f = new File(destination + dir); + + if (!f.isDirectory()) { + boolean success = f.mkdirs(); + if (!success) { + Log.w(TAG, "Failed to create folder " + f.getName()); + } + } + } +} diff --git a/android/src/org/purplei2p/i2pd/ForegroundService.java b/android/src/org/purplei2p/i2pd/ForegroundService.java index bfd650c8..645d0dca 100644 --- a/android/src/org/purplei2p/i2pd/ForegroundService.java +++ b/android/src/org/purplei2p/i2pd/ForegroundService.java @@ -5,6 +5,8 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; +import android.content.Context; +import android.os.Environment; import android.os.Binder; import android.os.IBinder; import android.util.Log; @@ -28,13 +30,20 @@ public class ForegroundService extends Service { } } + private String dataDir; + private String confDir; + @Override public void onCreate() { notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + dataDir = this.getDir("data", Context.MODE_PRIVATE).toString(); + confDir = Environment.getExternalStoragePublicDirectory("i2pd").toString(); // Display a notification about us starting. We put an icon in the status bar. showNotification(); - daemon.start(); + + Log.i("ForegroundService", "About to start daemon with dataDir: " + dataDir + ", confDir: " + confDir); + daemon.start(confDir, dataDir); // Tell the user we started. Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); } @@ -42,7 +51,7 @@ public class ForegroundService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i("ForegroundService", "Received start id " + startId + ": " + intent); - daemon.start(); + daemon.start(confDir, dataDir); return START_STICKY; } @@ -50,7 +59,7 @@ public class ForegroundService extends Service { public void onDestroy() { // Cancel the persistent notification. notificationManager.cancel(NOTIFICATION); - + stopForeground(true); // Tell the user we stopped. @@ -91,7 +100,7 @@ public class ForegroundService extends Service { //mNM.notify(NOTIFICATION, notification); startForeground(NOTIFICATION, notification); } - + private final DaemonSingleton daemon = DaemonSingleton.getInstance(); } diff --git a/android/src/org/purplei2p/i2pd/I2PD.java b/android/src/org/purplei2p/i2pd/I2PD.java index a2494b2b..d66a0174 100755 --- a/android/src/org/purplei2p/i2pd/I2PD.java +++ b/android/src/org/purplei2p/i2pd/I2PD.java @@ -2,6 +2,13 @@ package org.purplei2p.i2pd; import java.io.PrintWriter; import java.io.StringWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + import java.util.Timer; import java.util.TimerTask; @@ -24,12 +31,12 @@ public class I2PD extends Activity { private static final String TAG = "i2pd"; private TextView textView; - + private final DaemonSingleton daemon = DaemonSingleton.getInstance(); private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton.StateUpdateListener() { - + @Override public void daemonStateUpdate() { runOnUiThread(new Runnable(){ @@ -53,11 +60,14 @@ public class I2PD extends Activity { }); } }; - + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + //install certs every time + Decompress.unzipFromAssets(this, "certificates.zip", this.getDir("data", Context.MODE_PRIVATE).toString() + "/" ); + textView = new TextView(this); setContentView(textView); DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); @@ -123,7 +133,7 @@ public class I2PD extends Activity { } }; - + private boolean mIsBound; private void doBindService() { @@ -147,7 +157,7 @@ public class I2PD extends Activity { @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.options_main, menu); + getMenuInflater().inflate(R.menu.options_main, menu); return true; } @@ -216,9 +226,9 @@ public class I2PD extends Activity { @Override public void run() { - quit(); + quit(); } - + }, 10*60*1000/*milliseconds*/); }else{ quit(); @@ -227,7 +237,7 @@ public class I2PD extends Activity { Log.e(TAG,"",tr); } } - + },"gracQuitInit").start(); } diff --git a/android/src/org/purplei2p/i2pd/I2PD_JNI.java b/android/src/org/purplei2p/i2pd/I2PD_JNI.java index f965d471..bfdf8967 100644 --- a/android/src/org/purplei2p/i2pd/I2PD_JNI.java +++ b/android/src/org/purplei2p/i2pd/I2PD_JNI.java @@ -6,12 +6,12 @@ public class I2PD_JNI { * returns error info if failed * returns "ok" if daemon initialized and started okay */ - public static native String startDaemon(); + public static native String startDaemon(String args[]); //should only be called after startDaemon() success public static native void stopDaemon(); - + public static native void stopAcceptingTunnels(); - + public static native void onNetworkStateChanged(boolean isConnected); public static void loadLibraries() {