diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..de77168d0816f3697c753b55f676d79a54344317 --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="net.i2p.router" + android:versionCode="1" + android:versionName="1.0.0"> + <uses-permission android:name="android.permission.INTERNET" /> + <!-- 3 = 1.5, 2 = 1.1, 1 = 1.0; would probably work with 1 but don't have a 1.0 SDK to test against --> + <uses-sdk android:minSdkVersion="2" /> + <application android:label="@string/app_name"> + <activity android:name=".I2PAndroid" + android:label="@string/app_name" + android:launchMode="singleTask" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/android/README.txt b/android/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..e8886a57988c11c4ef34f68456640a73d79a69dc --- /dev/null +++ b/android/README.txt @@ -0,0 +1,25 @@ +These instructions are for the 1.5 SDK. +The build file is not compatible with the 1.1 SDK any more. + +#Unzip the android SDK in ../../ +#So then the android tools will be in ../../android-sdk-linux_x86-1.5_r2/tools/ + +#then build the android apk file: +ant debug + +# Create the android 1.5 virtual device +# (don't make a custom hardware profile) +../../android-sdk-linux_x86-1.5_r2/tools/android create avd --name i2p --target 2 + +#then run the emulator: +../../android-sdk-linux_x86-1.5_r2/tools/emulator -avd i2p & + +#then wait a couple minutes until the emulator is up +#then install the I2P app +ant install + +#then run the debugger +../../android-sdk-linux_x86-1.5_r2/tools/ddms & + +#to rebuild and reinstall to emulator: +ant reinstall diff --git a/android/build.xml b/android/build.xml new file mode 100644 index 0000000000000000000000000000000000000000..2b8664dcaae331b04e90221f09c634746b851c70 --- /dev/null +++ b/android/build.xml @@ -0,0 +1,352 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name=".I2PAndroid" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contain the path to the SDK. It should *NOT* be checked in in Version + Control Systems. --> + <property file="local.properties"/> + + <!-- The build.properties file can be created by you and is never touched + by the 'android' tool. This is the place to change some of the default property values + used by the Ant rules. + Here are some properties you may want to change/update: + + application-package + the name of your application package as defined in the manifest. Used by the + 'uninstall' rule. + source-folder + the name of the source folder. Default is 'src'. + out-folder + the name of the output folder. Default is 'bin'. + + Properties related to the SDK location or the project target should be updated + using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your application and + should be checked in in Version Control Systems. + + --> + <property file="build.properties"/> + + <!-- The default.properties file is created and updated by the 'android' tool, as well + as ADT. + This file is an integral part of the build system for your application and + should be checked in in Version Control Systems. --> + <property file="default.properties"/> + + <!-- Custom Android task to deal with the project target, and import the proper rules. + This requires ant 1.6.0 or above. --> + <path id="android.antlibs"> + <pathelement path="${sdk-location}/tools/lib/anttasks.jar" /> + <pathelement path="${sdk-location}/tools/lib/sdklib.jar" /> + <pathelement path="${sdk-location}/tools/lib/androidprefs.jar" /> + <pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" /> + <pathelement path="${sdk-location}/tools/lib/jarutils.jar" /> + </path> + + <taskdef name="setup" + classname="com.android.ant.SetupTask" + classpathref="android.antlibs"/> + + <!-- Execute the Android Setup task that will setup some properties specific to the target, + and import the rules files. + To customize the rules, copy/paste them below the task, and disable import by setting + the import attribute to false: + <setup import="false" /> + + This will ensure that the properties are setup correctly but that your customized + targets are used. + --> + <setup import="false" /> + + <!-- + ================================================================================ + New I2P rules + ================================================================================ + --> + + <target name="buildrouter" depends="dirs" > + <!-- build router and core --> + <ant dir=".." target="buildrouter" /> + + <!-- router --> + <copy file="../build/router.jar" todir="${external-libs-folder}" /> + + <!-- core --> + <mkdir dir="tmp" /> + <unjar src="../build/i2p.jar" dest="tmp/" /> + <delete file="tmp/net/i2p/util/LogWriter.class" /> + <!-- org.bouncycastle.crypto already in android + but we need a little trickery because our HMac is incompatible... + and the libs aren't in the SDK to compile against??? --> + <jar destfile="${external-libs-folder}/crypto.jar" > + <fileset dir="tmp/" > + <include name="org/bouncycastle/crypto/Digest.class" /> + <include name="org/bouncycastle/crypto/Mac.class" /> + <include name="org/bouncycastle/crypto/digests/GeneralDigest.class" /> + <include name="org/bouncycastle/crypto/digests/MD5Digest.class" /> + </fileset> + </jar> + <delete> + <fileset dir="tmp/" > + <include name="org/bouncycastle/crypto/Digest.class" /> + <include name="org/bouncycastle/crypto/Mac.class" /> + <include name="org/bouncycastle/crypto/digests/GeneralDigest.class" /> + <include name="org/bouncycastle/crypto/digests/MD5Digest.class" /> + </fileset> + </delete> +<!-- + <delete dir="tmp/org/bouncycastle/" /> + <delete file="tmp/net/i2p/crypto/HMACGenerator.class" /> +--> + <delete file="tmp/org/bouncycastle/" /> + <!-- lots of unneeded stuff could be deleted here --> + <jar destfile="${external-libs-folder}/i2p.jar" basedir="tmp/" /> + + <!-- some resources --> + <mkdir dir="res/drawable/" /> + <copy file="../installer/resources/themes/console/images/i2plogo.png" todir="res/drawable/" /> + <copy file="../installer/resources/blocklist.txt" tofile="res/raw/blocklist_txt" /> + </target> + + <target name="hackcleanup"> + <delete file="${external-libs-folder}/crypto.jar" /> + </target> + + <!-- + ================================================================================ + From here down copied from SDK platforms/android-1.1/templates/android_rules.xml + and then modified + ================================================================================ + --> + + <!-- + This rules file is meant to be imported by the custom Ant task: + com.android.ant.AndroidInitTask + + The following properties are put in place by the importing task: + android-jar, android-aidl, aapt, aidl, and dx + + Additionnaly, the task sets up the following classpath reference: + android.target.classpath + This is used by the compiler task as the boot classpath. + --> + + <!-- Custom tasks --> + <taskdef name="aaptexec" + classname="com.android.ant.AaptExecLoopTask" + classpathref="android.antlibs"/> + + <taskdef name="apkbuilder" + classname="com.android.ant.ApkBuilderTask" + classpathref="android.antlibs"/> + + <!-- Properties --> + + <property name="android-tools" value="${sdk-location}/tools" /> + + <!-- Input directories --> + <property name="source-folder" value="src" /> + <property name="gen-folder" value="gen" /> + <property name="resource-folder" value="res" /> + <property name="asset-folder" value="assets" /> + <property name="source-location" value="${basedir}/${source-folder}" /> + + <!-- folder for the 3rd party java libraries --> + <property name="external-libs-folder" value="libs" /> + + <!-- folder for the native libraries --> + <property name="native-libs-folder" value="libs" /> + + <!-- Output directories --> + <property name="gen-folder" value="gen" /> + <property name="out-folder" value="bin" /> + <property name="out-classes" value="${out-folder}/classes" /> + <property name="out-classes-location" value="${basedir}/${out-classes}"/> + <!-- out folders for a parent project if this project is an instrumentation project --> + <property name="main-out-folder" value="../${out-folder}" /> + <property name="main-out-classes" value="${main-out-folder}/classes"/> + + <!-- Intermediate files --> + <property name="dex-file" value="classes.dex" /> + <property name="intermediate-dex" value="${out-folder}/${dex-file}" /> + <!-- dx does not properly support incorrect / or \ based on the platform + and Ant cannot convert them because the parameter is not a valid path. + Because of this we have to compute different paths depending on the platform. --> + <condition property="intermediate-dex-location" + value="${basedir}\${intermediate-dex}" + else="${basedir}/${intermediate-dex}" > + <os family="windows"/> + </condition> + + <!-- The final package file to generate --> + <property name="out-debug-package" value="${out-folder}/${ant.project.name}-debug.apk"/> + + <!-- Tools --> + <condition property="exe" value=".exe" else=""><os family="windows"/></condition> + <property name="adb" value="${android-tools}/adb${exe}"/> + + <!-- rules --> + + <!-- Create the output directories if they don't exist yet. --> + <target name="dirs"> + <echo>Creating output directories if needed...</echo> + <mkdir dir="${resource-folder}" /> + <mkdir dir="${external-libs-folder}" /> + <mkdir dir="${gen-folder}" /> + <mkdir dir="${out-folder}" /> + <mkdir dir="${out-classes}" /> + </target> + + <!-- Generate the R.java file for this project's resources. --> + <target name="resource-src" depends="dirs"> + <echo>Generating R.java / Manifest.java from the resources...</echo> + <exec executable="${aapt}" failonerror="true"> + <arg value="package" /> + <arg value="-m" /> + <arg value="-J" /> + <arg path="${gen-folder}" /> + <arg value="-M" /> + <arg path="AndroidManifest.xml" /> + <arg value="-S" /> + <arg path="${resource-folder}" /> + <arg value="-I" /> + <arg path="${android-jar}" /> + </exec> + </target> + + <!-- Generate java classes from .aidl files. --> + <target name="aidl" depends="dirs"> + <echo>Compiling aidl files into Java classes...</echo> + <apply executable="${aidl}" failonerror="true"> + <arg value="-p${android-aidl}" /> + <arg value="-I${source-folder}" /> + <arg value="-o${gen-folder}" /> + <fileset dir="${source-folder}"> + <include name="**/*.aidl"/> + </fileset> + </apply> + </target> + + <!-- Compile this project's .java files into .class files. --> + <!-- I2P add buildrouter --> + <target name="compile" depends="buildrouter, resource-src, aidl"> + <javac encoding="ascii" target="1.5" debug="true" extdirs="" + destdir="${out-classes}" + bootclasspathref="android.target.classpath"> + <src path="${source-folder}" /> + <src path="${gen-folder}" /> + <classpath> + <fileset dir="${external-libs-folder}" includes="*.jar"/> + <pathelement path="${main-out-classes}"/> + </classpath> + </javac> + </target> + + <!-- Convert this project's .class files into .dex files. --> + <!-- I2P add hackcleanup --> + <target name="dex" depends="compile, hackcleanup"> + <echo>Converting compiled files and external libraries into ${out-folder}/${dex-file}...</echo> + <apply executable="${dx}" failonerror="true" parallel="true"> + <!-- I2P this is a bad sign that we need this --> + <arg value="-JXmx256m" /> + <arg value="--dex" /> + <arg value="--output=${intermediate-dex-location}" /> + <arg path="${out-classes-location}" /> + <fileset dir="${external-libs-folder}" includes="*.jar"/> + </apply> + </target> + + <!-- Put the project's resources into the output package file + This actually can create multiple resource package in case + Some custom apk with specific configuration have been + declared in default.properties. + --> + <target name="package-resources"> + <echo>Packaging resources</echo> + <aaptexec executable="${aapt}" + command="package" + manifest="AndroidManifest.xml" + resources="${resource-folder}" + assets="${asset-folder}" + androidjar="${android-jar}" + outfolder="${out-folder}" + basename="${ant.project.name}" /> + </target> + + <!-- Package the application and sign it with a debug key. + This is the default target when building. It is used for debug. --> + <target name="debug" depends="dex, package-resources"> + <apkbuilder + outfolder="${out-folder}" + basename="${ant.project.name}" + signed="true" + verbose="false"> + <file path="${intermediate-dex}" /> + <sourcefolder path="${source-folder}" /> + <jarfolder path="${external-libs-folder}" /> + <nativefolder path="${native-libs-folder}" /> + </apkbuilder> + </target> + + <!-- Package the application without signing it. + This allows for the application to be signed later with an official publishing key. --> + <target name="release" depends="dex, package-resources"> + <apkbuilder + outfolder="${out-folder}" + basename="${ant.project.name}" + signed="false" + verbose="false"> + <file path="${intermediate-dex}" /> + <sourcefolder path="${source-folder}" /> + <jarfolder path="${external-libs-folder}" /> + <nativefolder path="${native-libs-folder}" /> + </apkbuilder> + <echo>All generated packages need to be signed with jarsigner before they are published.</echo> + </target> + + <!-- Install the package on the default emulator --> + <target name="install" depends="debug"> + <echo>Installing ${out-debug-package} onto default emulator...</echo> + <exec executable="${adb}" failonerror="true"> + <arg value="install" /> + <arg path="${out-debug-package}" /> + </exec> + </target> + + <target name="reinstall" depends="debug"> + <echo>Installing ${out-debug-package} onto default emulator...</echo> + <exec executable="${adb}" failonerror="true"> + <arg value="install" /> + <arg value="-r" /> + <arg path="${out-debug-package}" /> + </exec> + </target> + + <!-- Uinstall the package from the default emulator --> + <target name="uninstall"> + <echo>Uninstalling ${application-package} from the default emulator...</echo> + <exec executable="${adb}" failonerror="true"> + <arg value="uninstall" /> + <arg path="${application-package}" /> + </exec> + </target> + + <target name="help"> + <!-- displays starts at col 13 + |13 80| --> + <echo>Android Ant Build. Available targets:</echo> + <echo> help: Displays this help.</echo> + <echo> debug: Builds the application and sign it with a debug key.</echo> + <echo> release: Builds the application. The generated apk file must be</echo> + <echo> signed before it is published.</echo> + <echo> install: Installs the debug package onto a running emulator or</echo> + <echo> device. This can only be used if the application has </echo> + <echo> not yet been installed.</echo> + <echo> reinstall: Installs the debug package on a running emulator or</echo> + <echo> device that already has the application.</echo> + <echo> The signatures must match.</echo> + <echo> uninstall: uninstall the application from a running emulator or</echo> + <echo> device.</echo> + </target> +</project> diff --git a/android/default.properties b/android/default.properties new file mode 100644 index 0000000000000000000000000000000000000000..eba5c59ff571bffa59a08378be7cea9d22972eb4 --- /dev/null +++ b/android/default.properties @@ -0,0 +1,11 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "build.properties", and override values to adapt the script to your +# project structure. + +# Project target. +target=android-2 diff --git a/android/res/layout/main.xml b/android/res/layout/main.xml new file mode 100644 index 0000000000000000000000000000000000000000..d764115276c1b6c135b8093a48d4adcb1ee4d67d --- /dev/null +++ b/android/res/layout/main.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > +<TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Hello World, I2PAndroid" + /> +<ImageView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:src="@drawable/i2plogo" + /> +</LinearLayout> + diff --git a/android/res/raw/logger_config b/android/res/raw/logger_config new file mode 100644 index 0000000000000000000000000000000000000000..2aeabb9f6413cb523a3c58c735da755c24129580 --- /dev/null +++ b/android/res/raw/logger_config @@ -0,0 +1,3 @@ +logger.defaultLevel=INFO +logger.record.net.i2p.router.transport.FIFOBandwidthRefiller=ERROR +logger.record.net.i2p.stat.Rate=ERROR diff --git a/android/res/raw/router_config b/android/res/raw/router_config new file mode 100644 index 0000000000000000000000000000000000000000..cf63ed56a1055ae73bca780fb20a2f4302499d37 --- /dev/null +++ b/android/res/raw/router_config @@ -0,0 +1,16 @@ +# initial router.config +# temp directory +i2p.dir.temp=/data/data/net.i2p.router/files/tmp +i2p.dir.pid=/data/data/net.i2p.router/files/tmp +# save memory +router.prng.buffers=2 +router.decayingBloomFilterM=20 +stat.full=false +i2np.udp.maxConnections=30 +# no I2CP +i2p.dummyClientFacade=true +# for now +i2np.ntcp.enable=false +# not on android +i2np.upnp.enable=false +routerconsole.geoip.enable=false diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..983a304b91143c9280066744db4c5523523ae886 --- /dev/null +++ b/android/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="app_name">I2PAndroid</string> +</resources> diff --git a/android/src/net/i2p/router/I2PAndroid.java b/android/src/net/i2p/router/I2PAndroid.java new file mode 100644 index 0000000000000000000000000000000000000000..ed626639ceeee57d5ab0e08dbfa20c2dab7b252c --- /dev/null +++ b/android/src/net/i2p/router/I2PAndroid.java @@ -0,0 +1,142 @@ +package net.i2p.router; + +import android.app.Activity; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; +import android.os.Bundle; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.List; + +import net.i2p.router.Router; +import net.i2p.router.RouterLaunch; +// import net.i2p.util.NativeBigInteger; + +public class I2PAndroid extends Activity +{ + static Context _context; + private static final String DIR = "/data/data/net.i2p.router/files"; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + + _context = this; // Activity extends Context + debugStuff(); + initialize(); + // 300ms per run + // 5x slower than java on my server and 50x slower than native on my server + // NativeBigInteger.main(null); + } + + public void onRestart() + { + System.err.println("onRestart called"); + super.onRestart(); + } + + public void onStart() + { + System.err.println("onStart called"); + super.onStart(); + RouterLaunch.main(null); + System.err.println("Router.main finished"); + } + + public void onResume() + { + System.err.println("onResume called"); + super.onResume(); + } + + public void onPause() + { + System.err.println("onPause called"); + super.onPause(); + } + + public void onStop() + { + System.err.println("onStop called"); + super.onStop(); + + // from routerconsole ContextHelper + List contexts = RouterContext.listContexts(); + if ( (contexts == null) || (contexts.size() <= 0) ) + throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down."); + RouterContext ctx = (RouterContext)contexts.get(0); + + // shutdown() doesn't return so use shutdownGracefully() + ctx.router().shutdownGracefully(Router.EXIT_HARD); + System.err.println("shutdown complete"); + } + + public void onDestroy() + { + System.err.println("onDestroy called"); + super.onDestroy(); + } + + public static Context getContext() { + return _context; + } + + private void debugStuff() { + System.err.println("java.io.tmpdir" + ": " + System.getProperty("java.io.tmpdir")); + System.err.println("java.vendor" + ": " + System.getProperty("java.vendor")); + System.err.println("java.version" + ": " + System.getProperty("java.version")); + System.err.println("os.arch" + ": " + System.getProperty("os.arch")); + System.err.println("os.name" + ": " + System.getProperty("os.name")); + System.err.println("os.version" + ": " + System.getProperty("os.version")); + System.err.println("user.dir" + ": " + System.getProperty("user.dir")); + System.err.println("user.home" + ": " + System.getProperty("user.home")); + System.err.println("user.name" + ": " + System.getProperty("user.name")); + } + + private void initialize() { + // Until we can edit the router.config on the device, + // copy it from the resource every time. + // File f = new I2PFile("router.config"); + // if (!f.exists()) { + copyResourceToFile(R.raw.router_config, "router.config"); + copyResourceToFile(R.raw.logger_config, "logger.config"); + copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt"); + // } + + // Set up the locations so Router and WorkingDir can find them + System.setProperty("i2p.dir.base", DIR); + System.setProperty("i2p.dir.config", DIR); + System.setProperty("wrapper.logfile", DIR + "/wrapper.log"); + } + + private void copyResourceToFile(int resID, String f) { + InputStream in = null; + FileOutputStream out = null; + + System.err.println("Creating file " + f + " from resource"); + byte buf[] = new byte[4096]; + try { + // Context methods + in = getResources().openRawResource(resID); + out = openFileOutput(f, 0); + + int read = 0; + while ( (read = in.read(buf)) != -1) + out.write(buf, 0, read); + + } catch (IOException ioe) { + } catch (Resources.NotFoundException nfe) { + } finally { + if (in != null) try { in.close(); } catch (IOException ioe) {} + if (out != null) try { out.close(); } catch (IOException ioe) {} + } + } + +} diff --git a/android/src/net/i2p/util/LogWriter.java b/android/src/net/i2p/util/LogWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..0babfab37be87e8b6212c4833860d953dcb721d5 --- /dev/null +++ b/android/src/net/i2p/util/LogWriter.java @@ -0,0 +1,163 @@ +package net.i2p.util; + +/* + * public domain + * + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.List; + +/** + * bridge to android logging + * + * @author zzz + */ +class LogWriter implements Runnable { + private final static long CONFIG_READ_ITERVAL = 10 * 1000; + private long _lastReadConfig = 0; + private long _numBytesInCurrentFile = 0; + private OutputStream _currentOut; // = System.out + private int _rotationNum = -1; + private String _logFilenamePattern; + private File _currentFile; + private LogManager _manager; + + private boolean _write; + + private LogWriter() { // nop + } + + public LogWriter(LogManager manager) { + _manager = manager; + } + + public void stopWriting() { + _write = false; + } + + public void run() { + _write = true; + try { + while (_write) { + flushRecords(); + rereadConfig(); + } + System.err.println("Done writing"); + } catch (Exception e) { + System.err.println("Error writing the logs: " + e.getMessage()); + e.printStackTrace(); + } + } + + public void flushRecords() { flushRecords(true); } + public void flushRecords(boolean shouldWait) { + try { + List records = _manager._removeAll(); + if (records == null) return; + for (int i = 0; i < records.size(); i++) { + LogRecord rec = (LogRecord) records.get(i); + writeRecord(rec); + } + } catch (Throwable t) { + t.printStackTrace(); + } finally { + if (shouldWait) { + try { + synchronized (this) { + this.wait(10*1000); + } + } catch (InterruptedException ie) { // nop + } + } + } + } + + public String currentFile() { + return _currentFile != null ? _currentFile.getAbsolutePath() : "uninitialized"; + } + + private void rereadConfig() { + long now = Clock.getInstance().now(); + if (now - _lastReadConfig > CONFIG_READ_ITERVAL) { + _manager.rereadConfig(); + _lastReadConfig = now; + } + } + + private void writeRecord(LogRecord rec) { + if (rec.getThrowable() == null) + log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage()); + else + log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable()); + } + + public void log(int priority, Class src, String name, String threadName, String msg) { + if (src != null) { + String tag = src.getName(); + int dot = tag.lastIndexOf("."); + if (dot >= 0) + tag = tag.substring(dot + 1); + android.util.Log.println(toAndroidLevel(priority), + tag, + '[' + threadName + "] " + msg); + } else if (name != null) + android.util.Log.println(toAndroidLevel(priority), + name, + '[' + threadName + "] " + msg); + else + android.util.Log.println(toAndroidLevel(priority), + threadName, msg); + } + + public void log(int priority, Class src, String name, String threadName, String msg, Throwable t) { + if (src != null) { + String tag = src.getName(); + int dot = tag.lastIndexOf("."); + if (dot >= 0) + tag = tag.substring(dot + 1); + android.util.Log.println(toAndroidLevel(priority), + tag, + '[' + threadName + "] " + msg + + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t)); + } else if (name != null) + android.util.Log.println(toAndroidLevel(priority), + name, + '[' + threadName + "] " + msg + + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t)); + else + android.util.Log.println(toAndroidLevel(priority), + threadName, + msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t)); + } + + private static int toAndroidLevel(int level) { + switch (level) { + case Log.DEBUG: + return android.util.Log.DEBUG; + case Log.INFO: + return android.util.Log.INFO; + case Log.WARN: + return android.util.Log.WARN; + case Log.ERROR: + case Log.CRIT: + default: + return android.util.Log.ERROR; + } + } + + private static final String replace(String pattern, int num) { + char c[] = pattern.toCharArray(); + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < c.length; i++) { + if ( (c[i] != '#') && (c[i] != '@') ) + buf.append(c[i]); + else + buf.append(num); + } + return buf.toString(); + } +} diff --git a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java index 417d0fc7215588c29ac675492e1a7587ff73a046..504b87d76dbd89af876b40638fb84357a7a01389 100644 --- a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java +++ b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java @@ -12,10 +12,11 @@ import net.i2p.util.Log; * has been eaten) */ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnable { - private static final int BUFFERS = 16; + private static final int DEFAULT_BUFFERS = 16; private static final int BUFSIZE = 256*1024; - private final byte asyncBuffers[][] = new byte[BUFFERS][BUFSIZE]; - private final int status[] = new int[BUFFERS]; + private int _bufferCount; + private final byte asyncBuffers[][]; + private final int status[]; private int nextBuf = 0; private I2PAppContext _context; private Log _log; @@ -27,7 +28,10 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl public AsyncFortunaStandalone(I2PAppContext context) { super(); - for (int i = 0; i < BUFFERS; i++) + _bufferCount = context.getProperty("router.prng.buffers", DEFAULT_BUFFERS); + asyncBuffers = new byte[_bufferCount][BUFSIZE]; + status = new int[_bufferCount]; + for (int i = 0; i < _bufferCount; i++) status[i] = STATUS_NEED_FILL; _context = context; context.statManager().createRateStat("prng.bufferWaitTime", "", "Encryption", new long[] { 60*1000, 10*60*1000, 60*60*1000 } ); @@ -80,11 +84,11 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl status[nextBuf] = STATUS_LIVE; int prev=nextBuf-1; if (prev<0) - prev = BUFFERS-1; + prev = _bufferCount-1; if (status[prev] == STATUS_LIVE) status[prev] = STATUS_NEED_FILL; nextBuf++; - if (nextBuf >= BUFFERS) + if (nextBuf >= _bufferCount) nextBuf = 0; asyncBuffers.notify(); } @@ -95,7 +99,7 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl int toFill = -1; try { synchronized (asyncBuffers) { - for (int i = 0; i < BUFFERS; i++) { + for (int i = 0; i < _bufferCount; i++) { if (status[i] == STATUS_NEED_FILL) { status[i] = STATUS_FILLING; toFill = i; diff --git a/core/java/src/net/i2p/crypto/HMAC256Generator.java b/core/java/src/net/i2p/crypto/HMAC256Generator.java index 2fcaa7b5ed55fd927fdbe9898cf82e10e9935647..0335d1e7eb0ef6f3edfe96373847548dd4df1622 100644 --- a/core/java/src/net/i2p/crypto/HMAC256Generator.java +++ b/core/java/src/net/i2p/crypto/HMAC256Generator.java @@ -7,7 +7,8 @@ import net.i2p.data.Hash; import net.i2p.data.SessionKey; import org.bouncycastle.crypto.Digest; -import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.macs.I2PHMac; /** * Calculate the HMAC-SHA256 of a key+message. All the good stuff occurs @@ -19,15 +20,15 @@ public class HMAC256Generator extends HMACGenerator { public HMAC256Generator(I2PAppContext context) { super(context); } @Override - protected HMac acquire() { + protected I2PHMac acquire() { synchronized (_available) { if (_available.size() > 0) - return (HMac)_available.remove(0); + return (I2PHMac)_available.remove(0); } // the HMAC is hardcoded to use SHA256 digest size // for backwards compatability. next time we have a backwards // incompatible change, we should update this by removing ", 32" - return new HMac(new Sha256ForMAC()); + return new I2PHMac(new Sha256ForMAC()); } private class Sha256ForMAC extends Sha256Standalone implements Digest { diff --git a/core/java/src/net/i2p/crypto/HMACGenerator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java index 8388590a2944c686907605aa8d6dda2c1096b3a6..b549c88559ebe44b8e7054217a361f524a1f9ae4 100644 --- a/core/java/src/net/i2p/crypto/HMACGenerator.java +++ b/core/java/src/net/i2p/crypto/HMACGenerator.java @@ -10,7 +10,8 @@ import net.i2p.data.Hash; import net.i2p.data.SessionKey; import org.bouncycastle.crypto.digests.MD5Digest; -import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.macs.I2PHMac; /** * Calculate the HMAC-MD5 of a key+message. All the good stuff occurs @@ -49,7 +50,7 @@ public class HMACGenerator { if ((key == null) || (key.getData() == null) || (data == null)) throw new NullPointerException("Null arguments for HMAC"); - HMac mac = acquire(); + I2PHMac mac = acquire(); mac.init(key.getData()); mac.update(data, offset, length); //byte rv[] = new byte[Hash.HASH_LENGTH]; @@ -73,7 +74,7 @@ public class HMACGenerator { if ((key == null) || (key.getData() == null) || (curData == null)) throw new NullPointerException("Null arguments for HMAC"); - HMac mac = acquire(); + I2PHMac mac = acquire(); mac.init(key.getData()); mac.update(curData, curOffset, curLength); byte rv[] = acquireTmp(); @@ -86,17 +87,17 @@ public class HMACGenerator { return eq; } - protected HMac acquire() { + protected I2PHMac acquire() { synchronized (_available) { if (_available.size() > 0) - return (HMac)_available.remove(0); + return (I2PHMac)_available.remove(0); } // the HMAC is hardcoded to use SHA256 digest size // for backwards compatability. next time we have a backwards // incompatible change, we should update this by removing ", 32" - return new HMac(new MD5Digest(), 32); + return new I2PHMac(new MD5Digest(), 32); } - private void release(HMac mac) { + private void release(Mac mac) { synchronized (_available) { if (_available.size() < 64) _available.add(mac); @@ -122,4 +123,4 @@ public class HMACGenerator { _availableTmp.add((Object)tmp); } } -} \ No newline at end of file +} diff --git a/core/java/src/net/i2p/util/DecayingBloomFilter.java b/core/java/src/net/i2p/util/DecayingBloomFilter.java index 164c8e45345fbbcd398406d10707707041ad6a04..95da0a03bdd8e61593b9307c655427402ab73f49 100644 --- a/core/java/src/net/i2p/util/DecayingBloomFilter.java +++ b/core/java/src/net/i2p/util/DecayingBloomFilter.java @@ -30,6 +30,7 @@ public class DecayingBloomFilter { private boolean _keepDecaying; private DecayEvent _decayEvent; + private static final int DEFAULT_M = 23; private static final boolean ALWAYS_MISS = false; /** @@ -44,8 +45,12 @@ public class DecayingBloomFilter { _context = context; _log = context.logManager().getLog(DecayingBloomFilter.class); _entryBytes = entryBytes; - _current = new BloomSHA1(23, 11); //new BloomSHA1(23, 11); - _previous = new BloomSHA1(23, 11); //new BloomSHA1(23, 11); + // this is instantiated in four different places, they may have different + // requirements, but for now use this as a gross method of memory reduction. + // m == 23 => 1MB each BloomSHA1 (4 pairs = 8MB total) + int m = context.getProperty("router.decayingBloomFilterM", DEFAULT_M); + _current = new BloomSHA1(m, 11); //new BloomSHA1(23, 11); + _previous = new BloomSHA1(m, 11); //new BloomSHA1(23, 11); _durationMs = durationMs; int numExtenders = (32+ (entryBytes-1))/entryBytes - 1; if (numExtenders < 0) diff --git a/core/java/src/org/bouncycastle/crypto/macs/HMac.java b/core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java similarity index 95% rename from core/java/src/org/bouncycastle/crypto/macs/HMac.java rename to core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java index 7176c8acafbc61cd08706df1c7888e87e5ae955e..a566e8a79936b52bfe131e9d55478d15f5465d32 100644 --- a/core/java/src/org/bouncycastle/crypto/macs/HMac.java +++ b/core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java @@ -42,8 +42,12 @@ import org.bouncycastle.crypto.Mac; * a frequently used buffer (called on doFinal). changes released into the public * domain in 2005. * + * This is renamed from HMac because the constructor HMac(digest, sz) does not exist + * in the standard bouncycastle library, thus it conflicts in JVMs that contain the + * standard library (Android). + * */ -public class HMac +public class I2PHMac implements Mac { private final static int BLOCK_LENGTH = 64; @@ -56,12 +60,12 @@ implements Mac private byte[] inputPad = new byte[BLOCK_LENGTH]; private byte[] outputPad = new byte[BLOCK_LENGTH]; - public HMac( + public I2PHMac( Digest digest) { this(digest, digest.getDigestSize()); } - public HMac( + public I2PHMac( Digest digest, int sz) { this.digest = digest;