Browse Source

Merge pull request #1065 from unlnown542a/openssl

Fixes for #1024 , #1018 #1064
pull/1066/head
orignal 7 years ago committed by GitHub
parent
commit
b8fd9ba83f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      android/.gitignore
  2. 54
      android/build.gradle
  3. 1
      android/gradle.properties
  4. 5
      android/jni/DaemonAndroid.cpp
  5. 2
      android/jni/DaemonAndroid.h
  6. 20
      android/jni/i2pd_android.cpp
  7. 2
      android/jni/org_purplei2p_i2pd_I2PD_JNI.h
  8. 39
      android/src/org/purplei2p/i2pd/DaemonSingleton.java
  9. 83
      android/src/org/purplei2p/i2pd/Decompress.java
  10. 17
      android/src/org/purplei2p/i2pd/ForegroundService.java
  11. 26
      android/src/org/purplei2p/i2pd/I2PD.java
  12. 6
      android/src/org/purplei2p/i2pd/I2PD_JNI.java

6
android/.gitignore vendored

@ -5,4 +5,8 @@ ant.properties
local.properties local.properties
build.sh build.sh
bin bin
log* log*
.gradle*
build
assets
gradle-app.setting

54
android/build.gradle

@ -11,23 +11,24 @@ buildscript {
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 25 compileSdkVersion 25
buildToolsVersion "25.0.2" buildToolsVersion "25.0.0"
defaultConfig { defaultConfig {
applicationId "org.purplei2p.i2pd" applicationId "org.purplei2p.i2pd"
targetSdkVersion 25 targetSdkVersion 25
minSdkVersion 14 minSdkVersion 14
versionCode 1 versionCode 1
versionName "2.17.1" versionName "2.17.2e"
} }
sourceSets { sourceSets {
main { main {
manifest.srcFile 'AndroidManifest.xml' manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src'] java.srcDirs = ['src']
res.srcDirs = ['res'] res.srcDirs = ['res']
jniLibs.srcDirs = ['libs'] jniLibs.srcDirs = ['libs']
} assets.srcDirs = ['assets']
} }
}
signingConfigs { signingConfigs {
orignal { orignal {
storeFile file("i2pdapk.jks") storeFile file("i2pdapk.jks")
@ -37,11 +38,30 @@ android {
} }
} }
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
signingConfig signingConfigs.orignal signingConfig signingConfigs.orignal
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' 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'
}

1
android/gradle.properties

@ -0,0 +1 @@
org.gradle.jvmargs=-Xmx2048M -XX:MaxPermSize=256M -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

5
android/jni/DaemonAndroid.cpp

@ -126,12 +126,11 @@ namespace android
} }
*/ */
static DaemonAndroidImpl daemon; static DaemonAndroidImpl daemon;
static char* argv[1]={strdup("tmp")};
/** /**
* returns error details if failed * returns error details if failed
* returns "ok" if daemon initialized and started okay * returns "ok" if daemon initialized and started okay
*/ */
std::string start(/*int argc, char* argv[]*/) std::string start(int argc, char* argv[])
{ {
try try
{ {
@ -139,7 +138,7 @@ namespace android
{ {
//Log.d(TAG"Initialising the daemon..."); //Log.d(TAG"Initialising the daemon...");
bool daemonInitSuccess = daemon.init(1,argv); bool daemonInitSuccess = daemon.init(argc,argv);
if(!daemonInitSuccess) if(!daemonInitSuccess)
{ {
//QMessageBox::critical(0, "Error", "Daemon init failed"); //QMessageBox::critical(0, "Error", "Daemon init failed");

2
android/jni/DaemonAndroid.h

@ -37,7 +37,7 @@ namespace android
* returns "ok" if daemon init failed * returns "ok" if daemon init failed
* returns errinfo if daemon initialized and started okay * returns errinfo if daemon initialized and started okay
*/ */
std::string start(); std::string start(int argc, char* argv[]);
// stops the daemon // stops the daemon
void stop(); void stop();

20
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 JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon
(JNIEnv * env, jclass clazz) { (JNIEnv * env, jclass clazz, jobjectArray args) {
return env->NewStringUTF(i2p::android::start().c_str()); 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 JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon

2
android/jni/org_purplei2p_i2pd_I2PD_JNI.h

@ -16,7 +16,7 @@ JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_getABICompiledWith
(JNIEnv *, jclass); (JNIEnv *, jclass);
JNIEXPORT jstring JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_startDaemon 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 JNIEXPORT void JNICALL Java_org_purplei2p_i2pd_I2PD_1JNI_stopDaemon
(JNIEnv *, jclass); (JNIEnv *, jclass);

39
android/src/org/purplei2p/i2pd/DaemonSingleton.java

@ -14,10 +14,10 @@ public class DaemonSingleton {
public static DaemonSingleton getInstance() { public static DaemonSingleton getInstance() {
return instance; return instance;
} }
public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); } public synchronized void addStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.add(listener); }
public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); } public synchronized void removeStateChangeListener(StateUpdateListener listener) { stateUpdateListeners.remove(listener); }
public synchronized void stopAcceptingTunnels() { public synchronized void stopAcceptingTunnels() {
if(isStartedOkay()){ if(isStartedOkay()){
state=State.gracefulShutdownInProgress; state=State.gracefulShutdownInProgress;
@ -25,20 +25,21 @@ public class DaemonSingleton {
I2PD_JNI.stopAcceptingTunnels(); I2PD_JNI.stopAcceptingTunnels();
} }
} }
public void onNetworkStateChange(boolean isConnected) { public void onNetworkStateChange(boolean isConnected) {
I2PD_JNI.onNetworkStateChanged(isConnected); I2PD_JNI.onNetworkStateChanged(isConnected);
} }
private boolean startedOkay; private boolean startedOkay;
public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress}; public static enum State {uninitialized,starting,jniLibraryLoaded,startedOkay,startFailed,gracefulShutdownInProgress};
private State state = State.uninitialized; private State state = State.uninitialized;
public State getState() { return state; } public State getState() { return state; }
public synchronized void start(final String confDir, final String dataDir) {
public synchronized void start() {
if(state != State.uninitialized)return; if(state != State.uninitialized)return;
state = State.starting; state = State.starting;
fireStateUpdate(); fireStateUpdate();
@ -62,7 +63,15 @@ public class DaemonSingleton {
} }
try { try {
synchronized (DaemonSingleton.this) { 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)){ if("ok".equals(daemonStartResult)){
state=State.startedOkay; state=State.startedOkay;
setStartedOkay(true); setStartedOkay(true);
@ -76,9 +85,9 @@ public class DaemonSingleton {
fireStateUpdate(); fireStateUpdate();
} }
return; return;
} }
} }
}, "i2pdDaemonStart").start(); }, "i2pdDaemonStart").start();
} }
private Throwable lastThrowable; private Throwable lastThrowable;
@ -87,10 +96,10 @@ public class DaemonSingleton {
private synchronized void fireStateUpdate() { private synchronized void fireStateUpdate() {
Log.i(TAG, "daemon state change: "+state); Log.i(TAG, "daemon state change: "+state);
for(StateUpdateListener listener : stateUpdateListeners) { for(StateUpdateListener listener : stateUpdateListeners) {
try { try {
listener.daemonStateUpdate(); listener.daemonStateUpdate();
} catch (Throwable tr) { } catch (Throwable tr) {
Log.e(TAG, "exception in listener ignored", tr); Log.e(TAG, "exception in listener ignored", tr);
} }
} }
} }
@ -102,7 +111,7 @@ public class DaemonSingleton {
public String getDaemonStartResult() { public String getDaemonStartResult() {
return daemonStartResult; return daemonStartResult;
} }
private final Object startedOkayLock = new Object(); private final Object startedOkayLock = new Object();
public boolean isStartedOkay() { public boolean isStartedOkay() {

83
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());
}
}
}
}

17
android/src/org/purplei2p/i2pd/ForegroundService.java

@ -5,6 +5,8 @@ import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.content.Intent; import android.content.Intent;
import android.content.Context;
import android.os.Environment;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.util.Log; import android.util.Log;
@ -28,13 +30,20 @@ public class ForegroundService extends Service {
} }
} }
private String dataDir;
private String confDir;
@Override @Override
public void onCreate() { public void onCreate() {
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); 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. // Display a notification about us starting. We put an icon in the status bar.
showNotification(); showNotification();
daemon.start();
Log.i("ForegroundService", "About to start daemon with dataDir: " + dataDir + ", confDir: " + confDir);
daemon.start(confDir, dataDir);
// Tell the user we started. // Tell the user we started.
Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.i2pd_service_started, Toast.LENGTH_SHORT).show();
} }
@ -42,7 +51,7 @@ public class ForegroundService extends Service {
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("ForegroundService", "Received start id " + startId + ": " + intent); Log.i("ForegroundService", "Received start id " + startId + ": " + intent);
daemon.start(); daemon.start(confDir, dataDir);
return START_STICKY; return START_STICKY;
} }
@ -50,7 +59,7 @@ public class ForegroundService extends Service {
public void onDestroy() { public void onDestroy() {
// Cancel the persistent notification. // Cancel the persistent notification.
notificationManager.cancel(NOTIFICATION); notificationManager.cancel(NOTIFICATION);
stopForeground(true); stopForeground(true);
// Tell the user we stopped. // Tell the user we stopped.
@ -91,7 +100,7 @@ public class ForegroundService extends Service {
//mNM.notify(NOTIFICATION, notification); //mNM.notify(NOTIFICATION, notification);
startForeground(NOTIFICATION, notification); startForeground(NOTIFICATION, notification);
} }
private final DaemonSingleton daemon = DaemonSingleton.getInstance(); private final DaemonSingleton daemon = DaemonSingleton.getInstance();
} }

26
android/src/org/purplei2p/i2pd/I2PD.java

@ -2,6 +2,13 @@ package org.purplei2p.i2pd;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; 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.Timer;
import java.util.TimerTask; import java.util.TimerTask;
@ -24,12 +31,12 @@ public class I2PD extends Activity {
private static final String TAG = "i2pd"; private static final String TAG = "i2pd";
private TextView textView; private TextView textView;
private final DaemonSingleton daemon = DaemonSingleton.getInstance(); private final DaemonSingleton daemon = DaemonSingleton.getInstance();
private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener = private DaemonSingleton.StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton.StateUpdateListener() { new DaemonSingleton.StateUpdateListener() {
@Override @Override
public void daemonStateUpdate() { public void daemonStateUpdate() {
runOnUiThread(new Runnable(){ runOnUiThread(new Runnable(){
@ -53,11 +60,14 @@ public class I2PD extends Activity {
}); });
} }
}; };
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
//install certs every time
Decompress.unzipFromAssets(this, "certificates.zip", this.getDir("data", Context.MODE_PRIVATE).toString() + "/" );
textView = new TextView(this); textView = new TextView(this);
setContentView(textView); setContentView(textView);
DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener); DaemonSingleton.getInstance().addStateChangeListener(daemonStateUpdatedListener);
@ -123,7 +133,7 @@ public class I2PD extends Activity {
} }
}; };
private boolean mIsBound; private boolean mIsBound;
private void doBindService() { private void doBindService() {
@ -147,7 +157,7 @@ public class I2PD extends Activity {
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present. // 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; return true;
} }
@ -216,9 +226,9 @@ public class I2PD extends Activity {
@Override @Override
public void run() { public void run() {
quit(); quit();
} }
}, 10*60*1000/*milliseconds*/); }, 10*60*1000/*milliseconds*/);
}else{ }else{
quit(); quit();
@ -227,7 +237,7 @@ public class I2PD extends Activity {
Log.e(TAG,"",tr); Log.e(TAG,"",tr);
} }
} }
},"gracQuitInit").start(); },"gracQuitInit").start();
} }

6
android/src/org/purplei2p/i2pd/I2PD_JNI.java

@ -6,12 +6,12 @@ public class I2PD_JNI {
* returns error info if failed * returns error info if failed
* returns "ok" if daemon initialized and started okay * 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 //should only be called after startDaemon() success
public static native void stopDaemon(); public static native void stopDaemon();
public static native void stopAcceptingTunnels(); public static native void stopAcceptingTunnels();
public static native void onNetworkStateChanged(boolean isConnected); public static native void onNetworkStateChanged(boolean isConnected);
public static void loadLibraries() { public static void loadLibraries() {

Loading…
Cancel
Save