Browse Source
* Fix foreground notification * Trying to fix app quit * Remove unsupported UI items * Remove misleading exceptions * Set Unix exec bit on build scripts * Revamp processAssets point to be launched * Corrected logic of daemon status events * Fix double I2PActivity.onCreate call hangup * Fix exception processing @ processAssetspull/82/head
nonlin-lin-chaos-order-etc-etal
4 months ago
committed by
GitHub
18 changed files with 505 additions and 156 deletions
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
package org.purplei2p.i2pd; |
||||
|
||||
public interface AbstractProcess { |
||||
/** @param tr can be null |
||||
*/ |
||||
void kill(Throwable tr); |
||||
} |
@ -1,35 +0,0 @@
@@ -1,35 +0,0 @@
|
||||
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); |
||||
} |
@ -0,0 +1,154 @@
@@ -0,0 +1,154 @@
|
||||
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){} |
||||
} |
@ -0,0 +1,126 @@
@@ -0,0 +1,126 @@
|
||||
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); |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
export I2PD_DEBUG=1 |
||||
if [ -z "$ANDROID_NDK_HOME" -a "$ANDROID_NDK_HOME" == "" ]; then |
||||
echo -e "\033[31mFailed! ANDROID_NDK_HOME is empty. Run 'export ANDROID_NDK_HOME=[PATH_TO_NDK]'\033[0m" |
||||
exit 1 |
||||
fi |
||||
echo Building boost... |
||||
./build_boost.sh |
||||
echo Building miniupnpc... |
||||
./build_miniupnpc.sh |
||||
echo Building openssl... |
||||
./build_openssl.sh |
||||
echo Building i2pd... |
||||
pushd . |
||||
NDK_MODULE_PATH=`pwd` |
||||
cd .. |
||||
NDK_PROJECT_PATH=`pwd` |
||||
popd |
||||
if [ -z "$BUILD_SO" -a "$BUILD_SO" == "" ]; then |
||||
export NDK_MODULE_PATH=$NDK_MODULE_PATH && export NDK_PROJECT_PATH=$NDK_PROJECT_PATH && $ANDROID_NDK_HOME/ndk-build V=1 NDK_LOG=1 -j`nproc` NDK_DEBUG=1 |
||||
else |
||||
export NDK_MODULE_PATH=$NDK_MODULE_PATH && export NDK_PROJECT_PATH=$NDK_PROJECT_PATH && ./ndkbuild-wrapper.sh V=1 NDK_LOG=1 -j`nproc` NDK_DEBUG=1 |
||||
fi |
||||
echo "$0 completed." |
@ -0,0 +1,20 @@
@@ -0,0 +1,20 @@
|
||||
if [ -z "$ANDROID_NDK_HOME" -a "$ANDROID_NDK_HOME" == "" ]; then |
||||
echo -e "\033[31mFailed! ANDROID_NDK_HOME is empty. Run 'export ANDROID_NDK_HOME=[PATH_TO_NDK]'\033[0m" |
||||
exit 1 |
||||
fi |
||||
echo Building boost... |
||||
./build_boost.sh |
||||
echo Building miniupnpc... |
||||
./build_miniupnpc.sh |
||||
echo Building openssl... |
||||
./build_openssl.sh |
||||
echo Building i2pd... |
||||
NDK_MODULE_PATH=`pwd` |
||||
cd .. |
||||
NDK_PROJECT_PATH=`pwd` |
||||
if [ -z "$BUILD_SO" -a "$BUILD_SO" == "" ]; then |
||||
export NDK_MODULE_PATH=$NDK_MODULE_PATH && export NDK_PROJECT_PATH=$NDK_PROJECT_PATH && $ANDROID_NDK_HOME/ndk-build V=1 NDK_LOG=1 -j`nproc` |
||||
else |
||||
export NDK_MODULE_PATH=$NDK_MODULE_PATH && export NDK_PROJECT_PATH=$NDK_PROJECT_PATH && ./ndkbuild-wrapper.sh V=1 NDK_LOG=1 -j`nproc` |
||||
fi |
||||
echo "$0 completed." |
@ -0,0 +1,16 @@
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash |
||||
|
||||
cd $NDK_PROJECT_PATH/jni |
||||
$ANDROID_NDK_HOME/ndk-build $* |
||||
|
||||
# if it doesn't exist, then create |
||||
if [ ! -d $NDK_PROJECT_PATH/libs ]; then mkdir $NDK_PROJECT_PATH/libs; fi |
||||
|
||||
cd $NDK_PROJECT_PATH/libs |
||||
for f in $(ls .); |
||||
do |
||||
if [ -z "$I2PD_DEBUG" -a "$I2PD_DEBUG" == "" ]; then |
||||
strip $f/i2pd |
||||
fi |
||||
mv $f/i2pd $f/libi2pd.so |
||||
done |
Loading…
Reference in new issue