From b080ff9ad2332df44bfee30ef824da02df0284e0 Mon Sep 17 00:00:00 2001 From: Roelof Kemp Date: Wed, 21 Aug 2013 14:47:48 +0200 Subject: [PATCH] initial commit --- .classpath | 9 + .gitignore | 1 + .project | 28 + .settings/org.eclipse.jdt.core.prefs | 7 + OSGI-INF/.gitignore | 1 + OSGI-INF/l10n/.gitignore | 1 + OSGI-INF/l10n/bundle.properties | 2 + README.md | 4 - build.properties | 6 + icon.svg | 99 +++ icons/.gitignore | 1 + icons/cuckoo_project_add.png | Bin 0 -> 506 bytes icons/cuckoo_project_new.png | Bin 0 -> 351 bytes icons/cuckoo_project_remove.png | Bin 0 -> 631 bytes plugin.xml | 110 ++++ readme.txt | 16 + src/.gitignore | 1 + src/interdroid/.gitignore | 1 + src/interdroid/cuckoo/.gitignore | 1 + src/interdroid/cuckoo/eclipse/.gitignore | 1 + .../cuckoo/eclipse/plugin/.gitignore | 1 + .../eclipse/plugin/AddCuckooNature.java | 94 +++ .../plugin/AndroidServiceRewriter.java | 575 ++++++++++++++++++ .../eclipse/plugin/ClasspathContainer.java | 130 ++++ .../plugin/ClasspathContainerInitializer.java | 42 ++ .../cuckoo/eclipse/plugin/CuckooBuilder.java | 148 +++++ .../cuckoo/eclipse/plugin/CuckooNature.java | 135 ++++ .../cuckoo/eclipse/plugin/CuckooPlugin.java | 90 +++ .../eclipse/plugin/CuckooProcessor.java | 379 ++++++++++++ .../cuckoo/eclipse/plugin/ErrorReporter.java | 5 + .../eclipse/plugin/RemoveCuckooNature.java | 87 +++ .../cuckoo/eclipse/plugin/StubDeriver.java | 209 +++++++ .../cuckoo/eclipse/plugin/Util.java | 39 ++ .../eclipse/plugin/preferences/.gitignore | 1 + .../preferences/CuckooPreferencePage.java | 28 + .../preferences/PreferenceInitializer.java | 26 + 36 files changed, 2274 insertions(+), 4 deletions(-) create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100644 .settings/org.eclipse.jdt.core.prefs create mode 100644 OSGI-INF/.gitignore create mode 100644 OSGI-INF/l10n/.gitignore create mode 100755 OSGI-INF/l10n/bundle.properties delete mode 100644 README.md create mode 100644 build.properties create mode 100644 icon.svg create mode 100644 icons/.gitignore create mode 100644 icons/cuckoo_project_add.png create mode 100644 icons/cuckoo_project_new.png create mode 100644 icons/cuckoo_project_remove.png create mode 100755 plugin.xml create mode 100644 readme.txt create mode 100644 src/.gitignore create mode 100644 src/interdroid/.gitignore create mode 100644 src/interdroid/cuckoo/.gitignore create mode 100644 src/interdroid/cuckoo/eclipse/.gitignore create mode 100644 src/interdroid/cuckoo/eclipse/plugin/.gitignore create mode 100755 src/interdroid/cuckoo/eclipse/plugin/AddCuckooNature.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/AndroidServiceRewriter.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/ClasspathContainer.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/ClasspathContainerInitializer.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/CuckooBuilder.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/CuckooNature.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/CuckooPlugin.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/CuckooProcessor.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/ErrorReporter.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/RemoveCuckooNature.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/StubDeriver.java create mode 100644 src/interdroid/cuckoo/eclipse/plugin/Util.java create mode 100644 src/interdroid/cuckoo/eclipse/plugin/preferences/.gitignore create mode 100755 src/interdroid/cuckoo/eclipse/plugin/preferences/CuckooPreferencePage.java create mode 100755 src/interdroid/cuckoo/eclipse/plugin/preferences/PreferenceInitializer.java diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..fe2ed48 --- /dev/null +++ b/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e56e04 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/.project b/.project new file mode 100644 index 0000000..e540963 --- /dev/null +++ b/.project @@ -0,0 +1,28 @@ + + + cuckoo-plugin + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..c537b63 --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/OSGI-INF/.gitignore b/OSGI-INF/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/OSGI-INF/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/OSGI-INF/l10n/.gitignore b/OSGI-INF/l10n/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/OSGI-INF/l10n/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/OSGI-INF/l10n/bundle.properties b/OSGI-INF/l10n/bundle.properties new file mode 100755 index 0000000..f642165 --- /dev/null +++ b/OSGI-INF/l10n/bundle.properties @@ -0,0 +1,2 @@ +#Properties file for CuckooPlugin +Bundle-Name = CuckooPlugin diff --git a/README.md b/README.md deleted file mode 100644 index 6e4b227..0000000 --- a/README.md +++ /dev/null @@ -1,4 +0,0 @@ -cuckoo-plugin -============= - -Eclipse Plugin for Cuckoo diff --git a/build.properties b/build.properties new file mode 100644 index 0000000..be6f54d --- /dev/null +++ b/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = tmp-eclipse/ +bin.includes = plugin.xml,\ + icons/,\ + .,\ + OSGI-INF/, diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..24d3fd8 --- /dev/null +++ b/icon.svg @@ -0,0 +1,99 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/icons/.gitignore b/icons/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/icons/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/icons/cuckoo_project_add.png b/icons/cuckoo_project_add.png new file mode 100644 index 0000000000000000000000000000000000000000..063d2dd38adcaffeef4cacc79b5d1f817cee523f GIT binary patch literal 506 zcmVhWFx&=W;o`bH49;-{szu zBEqyttEmaG5}&4Gssz%rw5aB(D`vn~BSVklQM~*I91*2$-I7iFGBIA6uxa1ArAd6r zL29S#8a{ZSp;q|I7T%*SlerbG*ga{@lbIOrf537c$QefOX9_MaT+^qm#z$3ZS55iEBhjaDG}zd16s2LwR|*US?i)adKios$PCk`s{Z$Qb0v_JY5_^ zB&OP4*r?Z>$l!4CbA4{qto~dM6 zxzRvk)&|anw=TH-mh5=AE`5h*PvEAxJzlbst4{qiDOsAUdo9^~qpF9g&y3GHH;y#t ztG_Ef!(RFNRGO>f5%FcIp=VCqJ|Ptt9QvhEt;@n8Qfs*w%VfO?$BpiN>?lr|(zLLL z%}>zaUpOnrqHs>GjvYt2#0)-&eR(tE(&iRv8Rer(`}W;kkbb}0+W%M7{x#XmzPh&6 rC;zW7Y!~X@<;8Vw%i3dAZ~if;i@Wc()~etK`jf%a)z4*}Q$iB}pdp81 literal 0 HcmV?d00001 diff --git a/icons/cuckoo_project_remove.png b/icons/cuckoo_project_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..e8712ebe3e37d97fb1716ca8f15bde911025e959 GIT binary patch literal 631 zcmV--0*L*IP)~p zPlz#wTPl@G?*YIx&2P7SLe~JbTCGC}`JBmQ?f_uB-Tw4_|I>6j{rXpcq9`9zsZ_Vs zY6%?20RSka7z_rk<2b#^Wb!5Ge-|{0#o|5B^AGKI`y9OA@4;~#+U>T$^ZY}xSiHXp z5Coy8s%nZ5g5RY>(=<>@K?s4WswqJbdN%<8)O?s$G#UW_ve|41z=x}V zQmOPhkw}~yV%s)Ws}-WrC}y)67K;URU5Dp+30aokTmXFEf0s-q!=C4zvqvHkbUGcx z<8cg!Lu@u1h@$x8cs#zn05HZPmSw%tbsfv)66^IEl}ZJoD5BA5000z4K{}m22A@Dq zhj2Lj#Btn + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..f93b858 --- /dev/null +++ b/readme.txt @@ -0,0 +1,16 @@ +** Cuckoo README ** + +Cuckoo is an open source computation offloading project of the Computer +Systems group of the Computer Science department of the Faculty of +Sciences at the VU University, Amsterdam, The Netherlands. The +main goal of the Cuckoo project is to simplify computation offloading +for Android apps. + +Cuckoo is free software. See the file "LICENSE" for copying permissions. + +The manual in the docs directory of the library project ("docs/manual.pdf") explains +how to build and run your Cuckoo application. + +The current Cuckoo source repository tree is accessible through Github at +https://github.com/interdroid/cuckoo-library and https://github.com/interdroid/cuckoo-plugin.. + diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/src/interdroid/.gitignore b/src/interdroid/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/src/interdroid/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/src/interdroid/cuckoo/.gitignore b/src/interdroid/cuckoo/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/src/interdroid/cuckoo/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/src/interdroid/cuckoo/eclipse/.gitignore b/src/interdroid/cuckoo/eclipse/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/src/interdroid/cuckoo/eclipse/plugin/.gitignore b/src/interdroid/cuckoo/eclipse/plugin/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/src/interdroid/cuckoo/eclipse/plugin/AddCuckooNature.java b/src/interdroid/cuckoo/eclipse/plugin/AddCuckooNature.java new file mode 100755 index 0000000..e13d656 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/AddCuckooNature.java @@ -0,0 +1,94 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.window.ApplicationWindow; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; + +import com.android.ide.eclipse.adt.AdtPlugin; + +@SuppressWarnings("restriction") +public class AddCuckooNature implements IObjectActionDelegate { + + private IJavaProject currentProject; + + @Override + public void run(IAction arg0) { + if (currentProject == null) { + AdtPlugin.printErrorToConsole("error", + "No current project! Cuckoo nature not added"); + return; + } + + try { + AdtPlugin.printToConsole(currentProject.getProject(), + "Adding Cuckoo nature...");//$NON-NLS-1$ + + IProjectDescription description = currentProject.getProject() + .getDescription(); + String[] natures = description.getNatureIds(); + String[] newNatures = new String[natures.length + 1]; + System.arraycopy(natures, 0, newNatures, 1, natures.length); + + // Insert CuckooNature in front for proper use of logo. + newNatures[0] = CuckooNature.NATURE_ID; + description.setNatureIds(newNatures); + currentProject.getProject().setDescription(description, null); + + IClasspathEntry[] rawClasspath = currentProject.getRawClasspath(); + + List newEntries = new ArrayList(); + for (IClasspathEntry e : rawClasspath) { + newEntries.add(e); + } + + newEntries.add(JavaCore.newContainerEntry(ClasspathContainer.ID)); + + currentProject.setRawClasspath( + newEntries.toArray(new IClasspathEntry[newEntries.size()]), + null); + + // Refresh project to rewrite AIDL files again. + currentProject.getProject().refreshLocal(IResource.DEPTH_INFINITE, + null); + AdtPlugin.printToConsole(currentProject.getProject(), + "Cuckoo nature added!");//$NON-NLS-1$ + } catch (Throwable e) { + AdtPlugin.printToConsole(currentProject.getProject(), + "Cuckoo nature addition failed! " + e);//$NON-NLS-1$ + AdtPlugin.logAndPrintError(e, + "AddCuckooNature", "failed to finish.");//$NON-NLS-1$ + } + } + + @Override + public void selectionChanged(IAction arg0, ISelection selection) { + if (selection instanceof IStructuredSelection) { + IStructuredSelection ss = (IStructuredSelection) selection; + Object obj = ss.getFirstElement(); + if (obj instanceof IJavaProject) { + currentProject = (IJavaProject) obj; + } + } + } + + @Override + public void setActivePart(IAction arg0, IWorkbenchPart arg1) { + // nothing + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/AndroidServiceRewriter.java b/src/interdroid/cuckoo/eclipse/plugin/AndroidServiceRewriter.java new file mode 100755 index 0000000..e64de3c --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/AndroidServiceRewriter.java @@ -0,0 +1,575 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.regex.Pattern; + +public class AndroidServiceRewriter { + + private final ErrorReporter reporter; + + public AndroidServiceRewriter(ErrorReporter reporter) { + this.reporter = reporter; + } + + public void androidServiceRewrite(String file, Properties aidlProperties) { + List lines = Util.getFileAsStringList(file, reporter); + + if (lines == null) { + return; + } + + // skip this file if we already modified it + if (lines.get(2).equals(" * MODIFIED BY CUCKOO")) {//$NON-NLS-1$ + reporter.error(file + ": was already rewritten."); + return; + } + lines.add(2, " * MODIFIED BY CUCKOO");//$NON-NLS-1$ + + String abstractGetContextMethod = "\n"//$NON-NLS-1$ + + "/************* START INSERTED CODE *************/\n"//$NON-NLS-1$ + + "public final android.content.Context getContext() {\n"//$NON-NLS-1$ + + " try {\n"//$NON-NLS-1$ + + " java.lang.reflect.Field field = this.getClass().getDeclaredField(\"this$0\");\n"//$NON-NLS-1$ + + " field.setAccessible(true);\n"//$NON-NLS-1$ + + " return (android.app.Service) field.get(this);\n"//$NON-NLS-1$ + + " } catch (Exception e) {\n"//$NON-NLS-1$ + + " // will never happen\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " return null;\n"//$NON-NLS-1$ + + "}\n";//$NON-NLS-1$ + + // add the final getContext method + lines.add( + findLine("this.attachInterface(this, DESCRIPTOR);", lines) + 2,//$NON-NLS-1$ + abstractGetContextMethod); + + // now find all the method invocations that need to be rewritten + List methodTransactions = findLines("case TRANSACTION_",//$NON-NLS-1$ + lines, findLine("@Override public boolean onTransact", lines));//$NON-NLS-1$ + + // rewrite the onTransact method to following (add final) + lines.set( + findLine("@Override public boolean onTransact", lines),//$NON-NLS-1$ + "@Override public boolean onTransact(int code, android.os.Parcel data, final android.os.Parcel reply, int flags) throws android.os.RemoteException");//$NON-NLS-1$ + + // rewrite all the methods (in reverse, so that we don't mess up the + // linenumbers we just found by inserting code). + for (int pos = methodTransactions.size() - 1; pos >= 0; pos--) { + int startLine = methodTransactions.get(pos); + int offset = 0; + String serviceName = getServiceName(lines); + + List parameterTypes = new ArrayList(); + String line = null; + // read until we find the line that contains "this.xxx" where "xxx" + // is the method + do { + line = lines.get(startLine + offset++); + // in the meantime we store the parameter types + if (line.endsWith("_arg" + parameterTypes.size() + ";")) {//$NON-NLS-1$//$NON-NLS-2$ + lines.set(startLine + offset - 1, "final " + line);//$NON-NLS-1$ + parameterTypes.add(line.split(" ")[0]);//$NON-NLS-1$ + } + } while (!(line.contains("this.") && !line.contains("this.getClass()")));//$NON-NLS-1$//$NON-NLS-2$ + // parse the method name + String methodName = parseMethod(line); + // now retrieve the strategy from the properties + String strategy = aidlProperties.getProperty(methodName); + // parse the return type + String returnType = parseReturnType(line); + // parse write type + String writeType = parseWriteType( + lines.get(startLine + offset + 1), returnType); + // see whether the writeType is a parcelable + boolean parcelableWriteType = isParcelable( + lines.get(startLine + offset + 1), returnType); + String localCode = getLocalCode(lines, startLine + offset - 1); + + String insertedMethodCode = null; + if (strategy.equals("parallel")) { + insertedMethodCode = "\n"//$NON-NLS-1$ + + "/************* START INSERTED CODE *************/\n"//$NON-NLS-1$ + + " // cuckoo.strategy=" + strategy + "\n"//$NON-NLS-1$ + + " final boolean[] done = new boolean[]{false};\n"//$NON-NLS-1$ + + " Object lock = new Object();\n"//$NON-NLS-1$ + + " final float weight = weight_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final long returnSize = returnSize_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final boolean screenOn = hasScreenOn_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final long inputSize = data.dataSize();\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.StatusThread remote = new interdroid.cuckoo.client.StatusThread(lock) {\n"//$NON-NLS-1$ + + " public boolean invoke() {\n" + + " try {\n"//$NON-NLS-1$//$NON-NLS-2$ + + " statistics.weight = weight;\n"//$NON-NLS-1$ + + " "//$NON-NLS-1$ + + (returnType == null ? "" : returnType//$NON-NLS-1$ + + " _remoteResult = (" + asObject(returnType)//$NON-NLS-1$ + + ") ")//$NON-NLS-1$ + + "interdroid.cuckoo.client.Cuckoo.invokeMethod(getContext(), statistics, \""//$NON-NLS-1$ + + serviceName + + "\", \""//$NON-NLS-1$ + + methodName + + "\", new Class[] {\n"//$NON-NLS-1$ + + getParametersAsString(parameterTypes) + + " }, new boolean[] {\n"//$NON-NLS-1$ + + getOutParametersAsString(localCode, + parameterTypes.size()) + + " }, new Object[] {\n"//$NON-NLS-1$ + + getObjectsAsString(parameterTypes.size()) + + " }, \"" + strategy + "\", weight, inputSize, returnSize, screenOn);\n"//$NON-NLS-1$ + + " synchronized (done) {\n"//$NON-NLS-1$ + + " if (!done[0]) {\n"//$NON-NLS-1$ + + " reply.writeNoException();\n"//$NON-NLS-1$ + + (parcelableWriteType ? " if ((_remoteResult != null)) {\n"//$NON-NLS-1$ + + " reply.writeInt(1);\n"//$NON-NLS-1$ + + " _remoteResult.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);\n"//$NON-NLS-1$ + + " } else {\n"//$NON-NLS-1$ + + " reply.writeInt(0);\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + : (writeType == null) ? ""//$NON-NLS-1$ + : " reply.write" + writeType//$NON-NLS-1$ + + "(_remoteResult);\n")//$NON-NLS-1$ + + " done[0] = true;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.Oracle.storeStatistics(getContext(), \"" + serviceName + "." + methodName + "\", statistics);\n"//$NON-NLS-1$ + + " return true;\n"//$NON-NLS-1$ + + getOutParameterLines(localCode) + + " } catch (Exception e) {\n"//$NON-NLS-1$ + + " e.printStackTrace();\n"//$NON-NLS-1$ + + " return false;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " };\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.StatusThread local = new interdroid.cuckoo.client.StatusThread(lock) {\n"//$NON-NLS-1$ + + " public boolean invoke() {\n"//$NON-NLS-1$ + + " statistics.weight = weight;\n"//$NON-NLS-1$ + + " statistics.inputSize = inputSize;\n"//$NON-NLS-1$ + + " long start = System.currentTimeMillis();\n"//$NON-NLS-1$ + + protectParcel(localCode) + + "\n"//$NON-NLS-1$ + + " statistics.resource = new interdroid.cuckoo.client.Cuckoo.Resource();\n"//$NON-NLS-1$ + + " statistics.executionTime = System.currentTimeMillis() - start;\n"//$NON-NLS-1$ + + " statistics.returnSize = reply.dataSize();\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.Oracle.storeStatistics(getContext(), \"" + serviceName + "." + methodName + "\", statistics);\n"//$NON-NLS-1$ + + " return true;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " };\n"//$NON-NLS-1$ + + " remote.start();\n"//$NON-NLS-1$ + + " local.start();\n"//$NON-NLS-1$ + + " synchronized (lock) {\n"//$NON-NLS-1$ + + " try {\n"//$NON-NLS-1$ + + " lock.wait();\n"//$NON-NLS-1$ + + " } catch (InterruptedException e) {}\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " // if the finished one failed, wait for the other\n"//$NON-NLS-1$ + + " if (remote.hasFailed() || local.hasFailed()) {\n"//$NON-NLS-1$ + + " synchronized (lock) {\n"//$NON-NLS-1$ + + " try {\n"//$NON-NLS-1$ + + " lock.wait();\n"//$NON-NLS-1$ + + " } catch (InterruptedException e) {}\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " // stop throws an Exception, so we can't stop the thread.\n"//$NON-NLS-1$ + + " // if (local.isAlive()) {\n"//$NON-NLS-1$ + + " // local.stop();\n"//$NON-NLS-1$ + + " // }\n"//$NON-NLS-1$ + + "/************* END INSERTED CODE *************/\n\n";//$NON-NLS-1$ + } else if (strategy.equals("remote")) { + insertedMethodCode = "\n"//$NON-NLS-1$ + + "/************* START INSERTED CODE *************/\n"//$NON-NLS-1$ + + " // cuckoo.strategy=" + strategy + "\n"//$NON-NLS-1$ + + " Object lock = new Object();\n"//$NON-NLS-1$ + + " final float weight = weight_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final long returnSize = returnSize_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final boolean screenOn = hasScreenOn_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final long inputSize = data.dataSize();\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.StatusThread remote = new interdroid.cuckoo.client.StatusThread(lock) {\n"//$NON-NLS-1$ + + " public boolean invoke() {\n" + + " try {\n"//$NON-NLS-1$//$NON-NLS-2$ + + " statistics.weight = weight;\n"//$NON-NLS-1$ + + " "//$NON-NLS-1$ + + (returnType == null ? "" : returnType//$NON-NLS-1$ + + " _remoteResult = (" + asObject(returnType)//$NON-NLS-1$ + + ") ")//$NON-NLS-1$ + + "interdroid.cuckoo.client.Cuckoo.invokeMethod(getContext(), statistics, \""//$NON-NLS-1$ + + serviceName + + "\", \""//$NON-NLS-1$ + + methodName + + "\", new Class[] {\n"//$NON-NLS-1$ + + getParametersAsString(parameterTypes) + + " }, new boolean[] {\n"//$NON-NLS-1$ + + getOutParametersAsString(localCode, + parameterTypes.size()) + + " }, new Object[] {\n"//$NON-NLS-1$ + + getObjectsAsString(parameterTypes.size()) + + " }, \"" + strategy + "\", weight, inputSize, returnSize, screenOn);\n"//$NON-NLS-1$ + + " reply.writeNoException();\n"//$NON-NLS-1$ + + (parcelableWriteType ? " if ((_remoteResult != null)) {\n"//$NON-NLS-1$ + + " reply.writeInt(1);\n"//$NON-NLS-1$ + + " _remoteResult.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);\n"//$NON-NLS-1$ + + " } else {\n"//$NON-NLS-1$ + + " reply.writeInt(0);\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + : (writeType == null) ? ""//$NON-NLS-1$ + : " reply.write" + writeType//$NON-NLS-1$ + + "(_remoteResult);\n")//$NON-NLS-1$ + + " interdroid.cuckoo.client.Oracle.storeStatistics(getContext(), \"" + serviceName + "." + methodName + "\", statistics);\n"//$NON-NLS-1$ + + " return true;\n"//$NON-NLS-1$ + + getOutParameterLines(localCode) + + " } catch (Exception e) {\n"//$NON-NLS-1$ + + " e.printStackTrace();\n"//$NON-NLS-1$ + + " return false;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " };\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.StatusThread local = new interdroid.cuckoo.client.StatusThread(lock) {\n"//$NON-NLS-1$ + + " public boolean invoke() {\n"//$NON-NLS-1$ + + " long start = System.currentTimeMillis();\n"//$NON-NLS-1$ + + localCode + + "\n"//$NON-NLS-1$ + + " statistics.resource = new interdroid.cuckoo.client.Cuckoo.Resource();\n"//$NON-NLS-1$ + + " statistics.executionTime = System.currentTimeMillis() - start;\n"//$NON-NLS-1$ + + " statistics.weight = 1;\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.Oracle.storeStatistics(getContext(), \"" + serviceName + "." + methodName + "\", statistics);\n"//$NON-NLS-1$ + + " return true;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " };\n"//$NON-NLS-1$ + + " if (!remote.invoke()) {\n"//$NON-NLS-1$ + + " local.invoke();\n"//$NON-NLS-1$ + + " }\n" //$NON-NLS-1$ + + "/************* END INSERTED CODE *************/\n\n";//$NON-NLS-1$ + } else if (strategy.equals("local")) { + insertedMethodCode = localCode; + } else { + // strategy is "energy", "speed", "energy/speed", "speed/energy" + insertedMethodCode = "\n"//$NON-NLS-1$ + + "/************* START INSERTED CODE *************/\n"//$NON-NLS-1$ + + " // cuckoo.strategy=" + strategy + "\n"//$NON-NLS-1$ + + " final boolean[] done = new boolean[]{false};\n"//$NON-NLS-1$ + + " Object lock = new Object();\n"//$NON-NLS-1$ + + " final float weight = weight_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final long returnSize = returnSize_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final boolean screenOn = hasScreenOn_" + methodName + "(\n" + getObjectsAsString(parameterTypes.size()) + " );\n"//$NON-NLS-1$ + + " final long inputSize = data.dataSize();\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.StatusThread remote = new interdroid.cuckoo.client.StatusThread(lock) {\n"//$NON-NLS-1$ + + " public boolean invoke() {\n" + + " try {\n"//$NON-NLS-1$//$NON-NLS-2$ + + " statistics.weight = weight;\n"//$NON-NLS-1$ + + " "//$NON-NLS-1$ + + (returnType == null ? "" : returnType//$NON-NLS-1$ + + " _remoteResult = (" + asObject(returnType)//$NON-NLS-1$ + + ") ")//$NON-NLS-1$ + + "interdroid.cuckoo.client.Cuckoo.invokeMethod(getContext(), statistics, \""//$NON-NLS-1$ + + serviceName + + "\", \""//$NON-NLS-1$ + + methodName + + "\", new Class[] {\n"//$NON-NLS-1$ + + getParametersAsString(parameterTypes) + + " }, new boolean[] {\n"//$NON-NLS-1$ + + getOutParametersAsString(localCode, + parameterTypes.size()) + + " }, new Object[] {\n"//$NON-NLS-1$ + + getObjectsAsString(parameterTypes.size()) + + " }, \"" + strategy + "\", weight, inputSize, returnSize, screenOn);\n"//$NON-NLS-1$ + + " synchronized (done) {\n"//$NON-NLS-1$ + + " if (!done[0]) {\n"//$NON-NLS-1$ + + " reply.writeNoException();\n"//$NON-NLS-1$ + + (parcelableWriteType ? " if ((_remoteResult != null)) {\n"//$NON-NLS-1$ + + " reply.writeInt(1);\n"//$NON-NLS-1$ + + " _remoteResult.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);\n"//$NON-NLS-1$ + + " } else {\n"//$NON-NLS-1$ + + " reply.writeInt(0);\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + : (writeType == null) ? ""//$NON-NLS-1$ + : " reply.write" + writeType//$NON-NLS-1$ + + "(_remoteResult);\n")//$NON-NLS-1$ + + " done[0] = true;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.Oracle.storeStatistics(getContext(), \"" + serviceName + "." + methodName + "\", statistics);\n"//$NON-NLS-1$ + + " return true;\n"//$NON-NLS-1$ + + getOutParameterLines(localCode) + + " } catch (Exception e) {\n"//$NON-NLS-1$ + + " e.printStackTrace();\n"//$NON-NLS-1$ + + " return false;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " };\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.StatusThread local = new interdroid.cuckoo.client.StatusThread(lock) {\n"//$NON-NLS-1$ + + " public boolean invoke() {\n"//$NON-NLS-1$ + + " statistics.weight = weight;\n"//$NON-NLS-1$ + + " statistics.inputSize = inputSize;\n"//$NON-NLS-1$ + + " long start = System.currentTimeMillis();\n"//$NON-NLS-1$ + + protectParcel(localCode) + + "\n"//$NON-NLS-1$ + + " statistics.resource = new interdroid.cuckoo.client.Cuckoo.Resource();\n"//$NON-NLS-1$ + + " statistics.executionTime = System.currentTimeMillis() - start;\n"//$NON-NLS-1$ + + " statistics.returnSize = reply.dataSize();\n"//$NON-NLS-1$ + + " interdroid.cuckoo.client.Oracle.storeStatistics(getContext(), \"" + serviceName + "." + methodName + "\", statistics);\n"//$NON-NLS-1$ + + " return true;\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " };\n"//$NON-NLS-1$ + + " if (interdroid.cuckoo.client.Oracle.emptyHistory(getContext(), \"" + serviceName + "." + methodName + "\")) {\n"//$NON-NLS-1$ + + " remote.start();\n"//$NON-NLS-1$ + + " local.start();\n"//$NON-NLS-1$ + + " synchronized (lock) {\n"//$NON-NLS-1$ + + " try {\n"//$NON-NLS-1$ + + " lock.wait();\n"//$NON-NLS-1$ + + " } catch (InterruptedException e) {}\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " // if the finished one failed, wait for the other\n"//$NON-NLS-1$ + + " if (remote.hasFailed() || local.hasFailed()) {\n"//$NON-NLS-1$ + + " synchronized (lock) {\n"//$NON-NLS-1$ + + " try {\n"//$NON-NLS-1$ + + " lock.wait();\n"//$NON-NLS-1$ + + " } catch (InterruptedException e) {}\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " } else {\n"//$NON-NLS-1$ + + " if (!remote.invoke()) {\n"//$NON-NLS-1$ + + " local.invoke();\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + " }\n"//$NON-NLS-1$ + + "/************* END INSERTED CODE *************/\n\n";//$NON-NLS-1$ + } + + lines.add(startLine + offset - 1, insertedMethodCode); + } + + // now generate the weight_ and returnSize_ and hasScreenOn_ methods + + // find the position where the method declarations start + int methodsFound = 0; + int pos = lines.size() - 1; + do { + if (lines.get(--pos).startsWith("public")) { + methodsFound++; + } + } while (methodsFound < methodTransactions.size()); + + int insertLine = findLine("this.attachInterface(this, DESCRIPTOR);", + lines) + 3; + + for (int i = 0; i < methodTransactions.size(); i++) { + String[] tmp = lines.get(pos) + .substring(0, lines.get(pos).indexOf('(')).split(" "); + String method = tmp[tmp.length - 1]; + String returnType = lines.get(pos).split(" ")[1]; + String weightMethod = lines.get(pos) + .replace(method, "weight_" + method) + .replaceFirst(Pattern.quote(returnType), "float") + .replace(';', '{') + + "\n" + " return 1;\n}\n"; + String returnSizeMethod = lines.get(pos) + .replace(method, "returnSize_" + method) + .replaceFirst(Pattern.quote(returnType), "long") + .replace(';', '{') + + "\n" + " return 1;\n}\n"; + String screenMethod = lines.get(pos) + .replace(method, "hasScreenOn_" + method) + .replaceFirst(Pattern.quote(returnType), "boolean") + .replace(';', '{') + + "\n" + " return true;\n}\n"; + lines.add(insertLine, weightMethod); + lines.add(insertLine, returnSizeMethod); + lines.add(insertLine, screenMethod); + pos += 3; + while (!lines.get(++pos).startsWith("public") + && pos < lines.size() - 1) { + } + } + + lines.add(insertLine + 3 * methodTransactions.size(), + "/************* END INSERTED CODE *************/\n\n");//$NON-NLS-1$ + + try { + RandomAccessFile out = new RandomAccessFile(file, "rw");//$NON-NLS-1$ + for (String line : lines) { + out.write((line + "\n").getBytes());//$NON-NLS-1$ + } + out.close(); + } catch (Exception e) { + reporter.error(file + ": got exception while writing"); + } + } + + private int findLine(String prefix, List lines) { + for (int i = 0; i < lines.size(); i++) { + if (lines.get(i).startsWith(prefix)) { + return i; + } + } + return -1; + } + + private List findLines(String prefix, List lines, + int startPos) { + List result = new ArrayList(); + for (int i = startPos; i < lines.size(); i++) { + if (lines.get(i).startsWith(prefix)) { + result.add(i); + } + } + return result; + } + + private String getOutParametersAsString(String localCode, int nrParameters) { + boolean[] tmp = new boolean[nrParameters]; + for (int i = 0; i < tmp.length; i++) { + tmp[i] = false; + } + String[] lines = localCode.split("\n");//$NON-NLS-1$ + for (String line : lines) { + if (line.trim().startsWith("reply.write") && line.contains("_arg")) {//$NON-NLS-1$//$NON-NLS-2$ + tmp[Integer.parseInt(line.substring(line.indexOf("_arg") + 4,//$NON-NLS-1$ + line.lastIndexOf(")")))] = true;//$NON-NLS-1$ + } + } + String result = "";//$NON-NLS-1$ + for (int i = 0; i < tmp.length; i++) { + result += " " + tmp[i] + ",\n";//$NON-NLS-1$//$NON-NLS-2$ + } + return result; + } + + private String getOutParameterLines(String localCode) { + String result = "";//$NON-NLS-1$ + String[] lines = localCode.split("\n");//$NON-NLS-1$ + for (String line : lines) { + if (line.trim().startsWith("reply.write") && line.contains("_arg")) {//$NON-NLS-1$//$NON-NLS-2$ + result += " " + line.trim() + "\n";//$NON-NLS-1$//$NON-NLS-2$ + } + } + return result; + } + + private String getLocalCode(List lines, int position) { + String result = " try {\n" + " "//$NON-NLS-1$//$NON-NLS-2$ + + lines.remove(position).replace("this.", "") + "\n";//$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + do { + // System.out.println("moving: " + lines.get(position)); + result += " " + lines.remove(position) + "\n";//$NON-NLS-1$//$NON-NLS-2$ + } while (!lines.get(position).startsWith("return true;"));//$NON-NLS-1$ + result += " } catch (android.os.RemoteException e) {}\n";//$NON-NLS-1$ + return result; + } + + private String getParametersAsString(List parameterTypes) { + String result = "";//$NON-NLS-1$ + for (String parameterType : parameterTypes) { + result += " " + stripGenerics(parameterType)//$NON-NLS-1$ + + ".class,\n";//$NON-NLS-1$ + } + return result; + } + + private String getObjectsAsString(int size) { + String result = "";//$NON-NLS-1$ + for (int i = 0; i < size - 1; i++) { + result += " _arg" + i + ",\n";//$NON-NLS-1$//$NON-NLS-2$ + } + result += " _arg" + (size - 1) + "\n";//$NON-NLS-1$//$NON-NLS-2$ + return result; + } + + private String stripGenerics(String parameterType) { + if (parameterType.indexOf("<") > 0) {//$NON-NLS-1$ + return parameterType.substring(0, parameterType.indexOf("<"));//$NON-NLS-1$ + } else { + return parameterType; + } + } + + private String parseMethod(String line) { + // System.out.println("parsing method: " + line); + return (line.substring(line.indexOf("this.") + 5, line.indexOf('(')));//$NON-NLS-1$ + } + + private String getServiceName(List lines) { + for (String line : lines) { + if (line.startsWith("private static final java.lang.String DESCRIPTOR = ")) {//$NON-NLS-1$ + String temp = line.split(" ")[6].substring(1,//$NON-NLS-1$ + line.split(" ")[6].indexOf("\";"));//$NON-NLS-1$//$NON-NLS-2$ + return temp.replace(temp.substring(temp.lastIndexOf(".")),//$NON-NLS-1$ + ".remote" + temp.substring(temp.lastIndexOf(".")));//$NON-NLS-1$//$NON-NLS-2$ + + } + } + return null; + } + + private String parseWriteType(String line, String returnType) { + // System.out.println("parsing writeType: " + line); + if (returnType == null) { + return null; + } + try { + return line.substring(line.indexOf(".") + 6, line.indexOf("("));//$NON-NLS-1$//$NON-NLS-2$ + } catch (Exception e) { + return null; + } + } + + private boolean isParcelable(String line, String returnType) { + // System.out.println("isParcelable: " + line); + if (returnType == null) { + return false; + } + try { + line.substring(line.indexOf(".") + 6, line.indexOf("("));//$NON-NLS-1$//$NON-NLS-2$ + return false; + } catch (Exception e) { + return true; + } + } + + private String parseReturnType(String line) { + // System.out.println("parsing return type: " + line); + if (line.startsWith("this.")) {//$NON-NLS-1$ + return null; + } + return line.substring(0, line.indexOf(" "));//$NON-NLS-1$ + } + + private String asObject(String type) { + if (type.equals("int")) {//$NON-NLS-1$ + return "Integer";//$NON-NLS-1$ + } + if (type.equals("long")) {//$NON-NLS-1$ + return "Long";//$NON-NLS-1$ + } + if (type.equals("boolean")) {//$NON-NLS-1$ + return "Boolean";//$NON-NLS-1$ + } + if (type.equals("short")) {//$NON-NLS-1$ + return "Short";//$NON-NLS-1$ + } + if (type.equals("byte")) {//$NON-NLS-1$ + return "Byte";//$NON-NLS-1$ + } + if (type.equals("float")) {//$NON-NLS-1$ + return "Float";//$NON-NLS-1$ + } + if (type.equals("double")) {//$NON-NLS-1$ + return "Double";//$NON-NLS-1$ + } + if (type.equals("char")) {//$NON-NLS-1$ + return "Char";//$NON-NLS-1$ + } + return type; + } + + private String protectParcel(String localCode) { + return localCode + .replace( + "reply.writeNoException", + "synchronized (done) {\n if (!(done[0])) {\n reply.writeNoException") + .replace( + "} catch", + " }\n done[0] = true;\n }\n } catch"); + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/ClasspathContainer.java b/src/interdroid/cuckoo/eclipse/plugin/ClasspathContainer.java new file mode 100755 index 0000000..518907b --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/ClasspathContainer.java @@ -0,0 +1,130 @@ +package interdroid.cuckoo.eclipse.plugin; + +import interdroid.cuckoo.eclipse.plugin.preferences.CuckooPreferencePage; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.util.ArrayList; + +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.jdt.core.IClasspathContainer; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jface.preference.IPreferenceStore; + +import com.android.ide.eclipse.adt.AdtPlugin; + +// import com.android.ide.eclipse.adt.AdtPlugin; + +public class ClasspathContainer implements IClasspathContainer { + + public static final IPath ID = new Path("CuckooPlugin.ClasspathContainer"); + + private final FilenameFilter fileFilter = new FilenameFilter() { + public boolean accept(File dir, String name) { + // if the file extension is .jar return true, else false + return name.endsWith(".jar"); + } + }; + + private IJavaProject project; + + public ClasspathContainer() { + } + + public void setProject(IJavaProject project) { + this.project = project; + } + + @Override + public IClasspathEntry[] getClasspathEntries() { + + IPreferenceStore store = CuckooPlugin.getDefault().getPreferenceStore(); + + String path = store.getString(CuckooPreferencePage.CUCKOO_LOCATION); + + ArrayList list = new ArrayList(); + + File directory = new File(path + File.separator + "lib/client"); + + if (!directory.exists() || !directory.isDirectory()) { + AdtPlugin.printToConsole(project.getProject(), "Warning: " + + directory.getName() + + " does not exist or is not a directory; Check your " + + CuckooPreferencePage.CUCKOO_LOCATION + " preference."); + return new IClasspathEntry[0]; + } + IFolder libsDir = project.getProject().getFolder("libs"); + if (!libsDir.exists()) { + try { + mkdir(libsDir); + } catch (CoreException e) { + AdtPlugin.printToConsole(project.getProject(), + "Warning: Could not create libs directory"); + return new IClasspathEntry[0]; + } + } + + try { + File[] files = directory.listFiles(fileFilter); + if (files != null) { + for (File f : files) { + if (!"android.jar".equals(f.getName())) { + IFile target = libsDir.getFile(f.getName()); + copyFile(f, target); + IClasspathEntry entry = JavaCore.newLibraryEntry( + target.getFullPath(), null, null); + if (entry != null) { + list.add(entry); + } + } + } + } + } catch (Exception e) { + AdtPlugin.printToConsole(project.getProject(), + "Warning: got exception " + e); + return new IClasspathEntry[0]; + } + return list.toArray(new IClasspathEntry[list.size()]); + } + + private void copyFile(File source, IFile dest) throws CoreException, + FileNotFoundException { + if (dest.exists()) { + return; + } + dest.create(new BufferedInputStream(new FileInputStream(source)), + false, null); + } + + private void mkdir(IFolder folder) throws CoreException { + if (folder.exists()) { + return; + } + folder.create(false, true, null); + } + + @Override + public String getDescription() { + return "Cuckoo client library path"; + } + + @Override + public int getKind() { + return K_APPLICATION; + } + + @Override + public IPath getPath() { + return ID; + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/ClasspathContainerInitializer.java b/src/interdroid/cuckoo/eclipse/plugin/ClasspathContainerInitializer.java new file mode 100755 index 0000000..e259cd7 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/ClasspathContainerInitializer.java @@ -0,0 +1,42 @@ +package interdroid.cuckoo.eclipse.plugin; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jdt.core.IClasspathContainer; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; + +import com.android.ide.eclipse.adt.AdtPlugin; + +public class ClasspathContainerInitializer extends + org.eclipse.jdt.core.ClasspathContainerInitializer { + + public ClasspathContainerInitializer() { + // nothing + } + + @Override + public void initialize(IPath path, IJavaProject project) throws CoreException { + AdtPlugin.printToConsole(project.getProject(), "ClasspathContainerInitializer.initialize()");//$NON-NLS-1$ + ClasspathContainer container = new ClasspathContainer(); + container.setProject(project); + JavaCore.setClasspathContainer(path, new IJavaProject[] {project}, new IClasspathContainer[] {container}, null); + } + + public static void updateProjects(IJavaProject[] projects) { + ClasspathContainer[] containers = new ClasspathContainer[projects.length]; + for (int i = 0; i < projects.length; i++) { + containers[i] = new ClasspathContainer(); + containers[i].setProject(projects[i]); + + } + try { + JavaCore.setClasspathContainer( + ClasspathContainer.ID, projects, containers, null); + } catch (JavaModelException e) { + // ?? + } + + } +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/CuckooBuilder.java b/src/interdroid/cuckoo/eclipse/plugin/CuckooBuilder.java new file mode 100755 index 0000000..cc791c1 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/CuckooBuilder.java @@ -0,0 +1,148 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.io.File; +import java.lang.reflect.Field; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.IncrementalProjectBuilder; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.build.AidlProcessor; +import com.android.ide.eclipse.adt.internal.build.RenderScriptProcessor; +import com.android.ide.eclipse.adt.internal.build.SourceProcessor; +import com.android.ide.eclipse.adt.internal.build.builders.PreCompilerBuilder; + +@SuppressWarnings("restriction") +public class CuckooBuilder extends PreCompilerBuilder { + + public static final String ID = "CuckooPlugin.CuckooBuilder";//$NON-NLS-1$ + + private static final String PREFIX = "CuckooBuilder: ";//$NON-NLS-1$ + + private static Field mProcessorsField = null; + + private static Field mAidlProcessorField = null; + private static Field mRenderScriptProcessorField = null; + + private IProject project; + + // Make the field "mProcessors" of the PreCompilerBuilder visible, so that + // we can replace AidlProcessor with CuckooProcessor. + + // update August 2013, things have changed with the new ADT, the list is + // only filled at the first "build", but only when mAidlProcessor is null. + // Therefore we initialize mAidlProcessor, but then we also have to do this + // for the mRenderScript processor and put both of them in the mProcessor + // list, which would otherwise be done during the first build. + static { + try { + Class cl = Class + .forName("com.android.ide.eclipse.adt.internal.build.builders.PreCompilerBuilder");//$NON-NLS-1$ + mProcessorsField = cl.getDeclaredField("mProcessors");//$NON-NLS-1$ + mProcessorsField.setAccessible(true); + mAidlProcessorField = cl.getDeclaredField("mAidlProcessor"); + mAidlProcessorField.setAccessible(true); + mRenderScriptProcessorField = cl + .getDeclaredField("mRenderScriptProcessor"); + mRenderScriptProcessorField.setAccessible(true); + } catch (Throwable e) { + // ignore. + } + + } + + @SuppressWarnings({ "unchecked" }) + protected void startupOnInitialize() { + super.startupOnInitialize(); + project = getProject(); + AdtPlugin.printToConsole(project, PREFIX + "initializing...");//$NON-NLS-1$ + + IFolder mGenFolder = project + .getFolder(com.android.SdkConstants.FD_GEN_SOURCES); + + IJavaProject javaProject = JavaCore.create(project); + + AidlProcessor cuckooProcessor = new CuckooProcessor(javaProject, + mBuildToolInfo, mGenFolder); + RenderScriptProcessor renderScriptProcessor = new RenderScriptProcessor( + javaProject, mBuildToolInfo, mGenFolder); + + try { + mAidlProcessorField.set(this, cuckooProcessor); + mRenderScriptProcessorField.set(this, renderScriptProcessor); + List mProcessors = (List) mProcessorsField + .get(this); + mProcessors.add(cuckooProcessor); + mProcessors.add(renderScriptProcessor); + AdtPlugin.printToConsole(project, PREFIX + + "Successfully inserted Cuckoo Builder"); + } catch (Exception e) { + AdtPlugin + .printToConsole( + project, + PREFIX + + "Failed to insert Cuckoo Builder, check /path/to/workspace/.metadata/.log for details"); + throw new RuntimeException(e); + } + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + protected IProject[] build(int kind, Map args, IProgressMonitor monitor) + throws CoreException { + IProject[] retval = super.build(kind, args, monitor); + if (kind == IncrementalProjectBuilder.FULL_BUILD) { + fullBuild(monitor); + } else { + IResourceDelta delta = getDelta(project); + if (delta == null) { + fullBuild(monitor); + } else { + incrementalBuild(delta, monitor); + } + } + return retval; + } + + private void incrementalBuild(IResourceDelta delta, IProgressMonitor monitor) + throws CoreException { + IPath path = project.getProjectRelativePath().append( + File.separatorChar + "remote"); + IResourceDelta modifiedDelta = delta.findMember(path); + if (modifiedDelta == null) + return; + + IResourceDeltaVisitor visitor = new IResourceDeltaVisitor() { + public boolean visit(IResourceDelta delta) throws CoreException { + // only interested in content changes + if ((delta.getFlags() & IResourceDelta.CONTENT) == 0) + return true; + IResource resource = delta.getResource(); + // only interested in files with the "java" extension + if (resource.getType() == IResource.FILE + && "java".equalsIgnoreCase(resource.getFileExtension())) { + CuckooProcessor.runAnt(project); + return false; + } + return true; + } + }; + modifiedDelta.accept(visitor); + } + + private void fullBuild(IProgressMonitor monitor) throws CoreException { + CuckooProcessor.writeBuildFile(project); + CuckooProcessor.runAnt(project); + } +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/CuckooNature.java b/src/interdroid/cuckoo/eclipse/plugin/CuckooNature.java new file mode 100755 index 0000000..82e8a02 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/CuckooNature.java @@ -0,0 +1,135 @@ +package interdroid.cuckoo.eclipse.plugin; + +import org.eclipse.core.resources.ICommand; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IProjectNature; +import org.eclipse.core.runtime.CoreException; + +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.build.builders.PreCompilerBuilder; +// import com.android.ide.eclipse.adt.internal.project.AndroidNature; + +@SuppressWarnings("restriction") +public class CuckooNature /*extends AndroidNature*/ implements IProjectNature { + + /** + * ID of this project nature. + */ + public static final String NATURE_ID = "CuckooPlugin.CuckooNature";//$NON-NLS-1$ + + private IProject project; + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.resources.IProjectNature#configure() + */ + public void configure() throws CoreException { + // First, configure the Android nature. + AdtPlugin.printToConsole(project, "CuckooNature: configure()");//$NON-NLS-1$ + // super.configure(); + // Then, remove the PreCompilerBuilder. We'll replace that with our own. + // removeBuilder(project, PreCompilerBuilder.ID); + // Insert Cuckoo builder. + configureCuckooBuilder(); + } + + /** + * Adds the CuckooBuilder if its not already there. It will check for + * the presence of a PreCompilerBuilder, and replace that. If not present, + * it will just return. + * @param project + * @throws CoreException + */ + private void configureCuckooBuilder() throws CoreException { + // get the builder list + IProjectDescription desc = project.getDescription(); + ICommand[] commands = desc.getBuildSpec(); + + // look for the builder in case it's already there. + for (int i = 0; i < commands.length; ++i) { + if (CuckooBuilder.ID.equals(commands[i].getBuilderName())) { + AdtPlugin.printToConsole(project, "CuckooNature: builder present");//$NON-NLS-1$ + return; + } + } + + // we need to replace the precompiler builder. + // Let's look for it. + + for (int i = 0; i < commands.length; i++) { + if (PreCompilerBuilder.ID.equals(commands[i].getBuilderName())) { + AdtPlugin.printToConsole(project, "CuckooNature: replacing PreCompilerBuilder");//$NON-NLS-1$ + ICommand command = desc.newCommand(); + command.setBuilderName(CuckooBuilder.ID); + commands[i] = command; + + // set the new builders in the project + desc.setBuildSpec(commands); + project.setDescription(desc, null); + return; + } + } + AdtPlugin.printErrorToConsole(project, "CuckooNature: PreCompilerBuilder not found");//$NON-NLS-1$ + } + + /** + * Replaces the CuckooBuilder with the PreCompilerBuilder. + * @param project + * @throws CoreException + */ + private void configurePreCompilerBuilder() throws CoreException { + // get the builder list + IProjectDescription desc = project.getDescription(); + ICommand[] commands = desc.getBuildSpec(); + + // look for the builder in case it's already there. + for (int i = 0; i < commands.length; i++) { + if (CuckooBuilder.ID.equals(commands[i].getBuilderName())) { + ICommand command = desc.newCommand(); + command.setBuilderName(PreCompilerBuilder.ID); + commands[i] = command; + desc.setBuildSpec(commands); + project.setDescription(desc, null); + return; + } + } + + AdtPlugin.printErrorToConsole(project, "CuckooNature: CuckooBuilder not found");//$NON-NLS-1$ + } + + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.resources.IProjectNature#deconfigure() + */ + public void deconfigure() throws CoreException { + configurePreCompilerBuilder(); + // super.deconfigure(); + AdtPlugin.printToConsole(project, "CuckooNature: deconfigure");//$NON-NLS-1$ + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.resources.IProjectNature#getProject() + */ + public IProject getProject() { + return project; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.core.resources.IProjectNature#setProject(org.eclipse.core + * .resources.IProject) + */ + public void setProject(IProject project) { + // super.setProject(project); + this.project = project; + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/CuckooPlugin.java b/src/interdroid/cuckoo/eclipse/plugin/CuckooPlugin.java new file mode 100755 index 0000000..2b5be15 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/CuckooPlugin.java @@ -0,0 +1,90 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.util.ArrayList; + +import interdroid.cuckoo.eclipse.plugin.preferences.CuckooPreferencePage; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jdt.core.IJavaModel; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class CuckooPlugin extends AbstractUIPlugin { + + private static CuckooPlugin plugin; + + public CuckooPlugin() { + super(); + plugin = this; + } + + public void start(BundleContext context) throws Exception { + super.start(context); + IPreferenceStore store = getPreferenceStore(); + store.addPropertyChangeListener(new IPropertyChangeListener() { + public void propertyChange(PropertyChangeEvent event) { + if (CuckooPreferencePage.CUCKOO_LOCATION.equals(event + .getProperty())) { + FixCuckooProjects(); + } + } + }); + } + + protected void FixCuckooProjects() { + IJavaProject[] projects = getCuckooProjects(); + ClasspathContainerInitializer.updateProjects(projects); + + } + + public static IJavaProject[] getCuckooProjects() { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + IJavaModel javaModel = JavaCore.create(workspaceRoot); + + IJavaProject[] javaProjectList; + try { + javaProjectList = javaModel.getJavaProjects(); + } catch (JavaModelException jme) { + return new IJavaProject[0]; + } + + ArrayList list = new ArrayList(); + + for (IJavaProject javaProject : javaProjectList) { + IProject project = javaProject.getProject(); + if (isCuckooProject(project)) { + list.add(javaProject); + } + } + + return list.toArray(new IJavaProject[list.size()]); + } + + public static boolean isCuckooProject(IProject project) { + try { + return project.hasNature(CuckooNature.NATURE_ID); + } catch (CoreException e) { + // ignore, just return false; + } + + return false; + } + + public void stop(BundleContext context) throws Exception { + super.stop(context); + } + + public static CuckooPlugin getDefault() { + return plugin; + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/CuckooProcessor.java b/src/interdroid/cuckoo/eclipse/plugin/CuckooProcessor.java new file mode 100755 index 0000000..f12bd73 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/CuckooProcessor.java @@ -0,0 +1,379 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileFilter; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.eclipse.ant.core.AntRunner; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.jdt.core.IJavaProject; + +import com.android.SdkConstants; +import com.android.ide.eclipse.adt.AdtConstants; +import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.build.AidlProcessor; +import com.android.ide.eclipse.adt.internal.build.builders.BaseBuilder; +import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; +import com.android.sdklib.BuildToolInfo; +import com.android.sdklib.IAndroidTarget; + +@SuppressWarnings("restriction") +public class CuckooProcessor extends AidlProcessor { + + public static final String PREFIX = "CuckooProcessor: ";//$NON-NLS-1$ + + private IFolder myGenFolder; + + public class Reporter implements ErrorReporter { + + private final IProject project; + + public Reporter(IProject project) { + this.project = project; + } + + @Override + public void error(String message) { + AdtPlugin.printErrorToConsole(project, PREFIX + message); + } + + } + + public CuckooProcessor(IJavaProject javaProject, BuildToolInfo info, + IFolder genFolder) { + super(javaProject, info, genFolder); + this.myGenFolder = genFolder; + } + + @Override + protected void doCompileFiles(List sources, BaseBuilder builder, + IProject project, IAndroidTarget projectTarget, + List sourceFolders, List notCompiledOut, + List libraryProjectsOut, IProgressMonitor monitor) + throws CoreException { + + Reporter reporter = new Reporter(project); + + AdtPlugin.printToConsole(project, PREFIX + "doCompileFiles()");//$NON-NLS-1$ + super.doCompileFiles(sources, builder, project, projectTarget, + sourceFolders, notCompiledOut, libraryProjectsOut, monitor); + + // Create list of AIDL files that need to be dealt with. + List sourceList = new ArrayList(); + for (IFile sourceFile : sources) { + String aidlFile = sourceFile.getLocation().toOSString(); + BufferedReader in = null; + String line = null; + boolean isEnabled = true; + boolean enabledSet = false; + try { + in = new BufferedReader(new FileReader(aidlFile)); + while (true) { + line = in.readLine(); + if (line == null) + break; + if (line.trim().startsWith("//")) { + if (line.contains("cuckoo:enabled=")) { + enabledSet = true; + if (line.contains("cuckoo:enabled=false")) { + isEnabled = false; + break; + } else if (line.contains("cuckoo:enabled=true")) { + isEnabled = true; + break; + } + } + } + } + } catch (IOException e) { + AdtPlugin.printErrorToConsole(project, PREFIX + aidlFile + + ": could not read."); + } finally { + try { + in.close(); + } catch (Throwable e) { + // ignore + } + } + if (!isEnabled) {//$NON-NLS-1$ + AdtPlugin + .printToConsole( + project, + PREFIX + + aidlFile + + ": explicitly skipped (cuckoo:enabled set to false)."); + } else { + if (!enabledSet) { + AdtPlugin + .printToConsole( + project, + PREFIX + + aidlFile + + ": implicitly enabled (cuckoo:enabled not set, insert the line \"//cuckoo:enabled=false\" between the package declaration and the interface declaration to disable offloading)."); + } else { + AdtPlugin + .printToConsole( + project, + PREFIX + + aidlFile + + ": explicitly enabled (cuckoo:enabled set to true)."); + } + + sourceList.add(sourceFile); + } + } + + // Loop until we've rewritten them all. + + AndroidServiceRewriter rewriter = new AndroidServiceRewriter(reporter); + StubDeriver stubDeriver = new StubDeriver(reporter); + + for (IFile sourceFile : sourceList) { + + // Obtain output file (which is present, probably just created). + IFile aidlOutput = getAidlOutputFile(sourceFile); + if (aidlOutput.exists()) { + Properties aidlProperties = parseProperties(sourceFile, + reporter, project); + AdtPlugin.printToConsole(project, PREFIX + aidlOutput.getName() + + ": rewriting."); + rewriter.androidServiceRewrite(aidlOutput.getLocation() + .toOSString(), aidlProperties); + stubDeriver.deriveStubFrom(aidlOutput.getLocation() + .toOSString(), project.getLocation().toOSString()); + } + } + + AdtPlugin.printToConsole(project, PREFIX + "generating build.xml."); + writeBuildFile(project); + runAnt(project); + } + + public static Properties parseProperties(IFile sourceFile, + ErrorReporter reporter, IProject project) { + Properties properties = new Properties(); + List lines = Util.getFileAsStringList(sourceFile.getLocation() + .toOSString(), reporter); + String strategy = "speed/energy"; + for (int i = 0; i < lines.size(); i++) { + String line = lines.get(i); + if (line.trim().startsWith("//")) { + // comment line + String keyValue = line.trim().substring(2).trim() + .replace(" ", ""); + if (keyValue.startsWith("cuckoo:strategy=") + || keyValue.startsWith("cuckoo.strategy=")) { + String value = keyValue + .substring(keyValue.indexOf('=') + 1).trim(); + if (validStrategy(value)) { + strategy = value; + } else { + AdtPlugin.printToConsole(project, PREFIX + + "Encountered invalid strategy '" + value + + "' at line: " + i + " in file: " + + sourceFile.getLocation().toOSString()); + // invalid strategy + } + } else { + // skip the comment + } + } else if (line.trim().endsWith(";")) { + // is this a method declaration? + if (line.contains("(") && line.contains(")")) { + String tmp = line.substring(0, line.indexOf("(")); + String method = tmp.substring(tmp.lastIndexOf(' ')).trim(); + if (properties.contains(method)) { + AdtPlugin + .printErrorToConsole( + project, + "Cuckoo cannot handle duplicate method names, please make all method names in the AIDL specification unique: duplicate name '" + + method + "'"); + } + properties.put(method, strategy); + strategy = "speed/energy"; + } else { + // skip the line + } + } + } + return properties; + } + + private static boolean validStrategy(String strategy) { + return strategy.equalsIgnoreCase("local") + || strategy.equalsIgnoreCase("remote") + || strategy.equalsIgnoreCase("parallel") + || strategy.equalsIgnoreCase("speed") + || strategy.equalsIgnoreCase("energy") + || strategy.equalsIgnoreCase("speed/energy") + || strategy.equalsIgnoreCase("energy/speed"); + } + + public static void runAnt(IProject project) throws CoreException { + AntRunner runner = new AntRunner(); + String dir = project.getLocation().toOSString() + File.separator + + "remote";//$NON-NLS-1$ + runner.setAntHome(dir); + runner.setBuildFileLocation(dir + File.separator + "build.xml");//$NON-NLS-1$ + runner.run(); + } + + private IFile getAidlOutputFile(IFile sourceFile) throws CoreException { + + IPath sourceFolderPath = getSourceFolderFor(sourceFile); + + if (sourceFolderPath != null) { + // make a path to the source file relative to the source folder. + IPath relative = sourceFile.getFullPath().makeRelativeTo( + sourceFolderPath); + // remove the file name. This is now the destination folder inside + // the gen folder. + relative = relative.removeLastSegments(1); + + // get an IFolder for this path. + IFolder destinationFolder = myGenFolder.getFolder(relative); + + // Build the Java file name from the aidl name. + String javaName = sourceFile.getName().replaceAll( + AdtConstants.RE_AIDL_EXT, SdkConstants.DOT_JAVA); + + // get the resource for the java file. + return destinationFolder.getFile(javaName); + } + + return null; + } + + public static void writeBuildFile(IProject project) { + FileWriter out = null; + File buildFile = new File(project.getLocation().toOSString() + + File.separator + "remote" + File.separator + "build.xml");//$NON-NLS-1$//$NON-NLS-2$ + if (buildFile.exists()) { + buildFile.delete(); + } + try { + out = new FileWriter(buildFile); + out.write("\n");//$NON-NLS-1$ + out.write("Cuckoo description\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + File[] dirs = new File(project.getLocation().toOSString() + + File.separator + "modified").listFiles(new FileFilter() {//$NON-NLS-1$ + + @Override + public boolean accept(File file) { + return file.isDirectory() + && !file.getName().equals("tmp")//$NON-NLS-1$ + && !file.getName().equals(".svn");//$NON-NLS-1$ + } + }); + + String depends = "clean";//$NON-NLS-1$ + for (File dir : dirs) { + depends += "," + dir.getName();//$NON-NLS-1$ + } + // write the main target, this depends on all the other services + out.write("\n");//$NON-NLS-1$ + + // now write a target per service + for (File serviceDir : dirs) { + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + // external jars! + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + // include the android jar too! + String sdkDir = AdtPlugin.getDefault().getPreferenceStore() + .getString(AdtPrefs.PREFS_SDK_DIR); + String androidTarget = "android-10"; // default + try { + Properties projectProperties = new Properties(); + projectProperties.load(new FileInputStream(project + .getLocation().toOSString() + + File.separator + + "project.properties")); + + androidTarget = projectProperties.getProperty("target"); + } catch (Throwable t) { + } + + String androidJar = sdkDir + File.separator + "platforms" + + File.separator + androidTarget + File.separator + + "android.jar"; + + out.write("\n");//$NON-NLS-1$ + + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + // copy the external jars to the lib dir + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + // now jar this compiled classes + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + } + + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.write("\n");//$NON-NLS-1$ + out.flush(); + } catch (Exception e) { + AdtPlugin.printErrorToConsole(project, PREFIX + buildFile.getName() + + ": could not write."); + } finally { + try { + out.close(); + } catch (Throwable e) { + // ignore + } + } + } +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/ErrorReporter.java b/src/interdroid/cuckoo/eclipse/plugin/ErrorReporter.java new file mode 100755 index 0000000..099c395 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/ErrorReporter.java @@ -0,0 +1,5 @@ +package interdroid.cuckoo.eclipse.plugin; + +public interface ErrorReporter { + public void error(String message); +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/RemoveCuckooNature.java b/src/interdroid/cuckoo/eclipse/plugin/RemoveCuckooNature.java new file mode 100755 index 0000000..6be1c56 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/RemoveCuckooNature.java @@ -0,0 +1,87 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.IResource; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IObjectActionDelegate; +import org.eclipse.ui.IWorkbenchPart; + +import com.android.ide.eclipse.adt.AdtPlugin; + +public class RemoveCuckooNature implements IObjectActionDelegate { + + private IJavaProject currentProject; + + @Override + public void run(IAction arg0) { + if (currentProject == null) { + AdtPlugin.printErrorToConsole("error", + "No current project! Cuckoo nature not removed"); + return; + } + AdtPlugin.printToConsole(currentProject.getProject(), + "Removing Cuckoo nature...");//$NON-NLS-1$ + try { + IClasspathEntry[] rawClasspath = currentProject.getRawClasspath(); + List newEntries = new ArrayList(); + for (IClasspathEntry e : rawClasspath) { + if (!e.getPath().equals(ClasspathContainer.ID)) { + newEntries.add(e); + } + } + + currentProject.setRawClasspath( + newEntries.toArray(new IClasspathEntry[newEntries.size()]), + null); + + IProjectDescription description = currentProject.getProject() + .getDescription(); + String[] natures = description.getNatureIds(); + description.setNatureIds(removeCuckooNature(natures)); + currentProject.getProject().setDescription(description, null); + // refresh project so user sees changes + currentProject.getProject().refreshLocal(IResource.DEPTH_INFINITE, + null); + AdtPlugin.printToConsole(currentProject.getProject(), + "Cuckoo nature removed");//$NON-NLS-1$ + } catch (Throwable e) { + AdtPlugin.printErrorToConsole(currentProject.getProject(), + "Cuckoo nature removal failed! " + e);//$NON-NLS-1$ + } + } + + private String[] removeCuckooNature(String[] natures) { + ArrayList list = new ArrayList(); + for (String nature : natures) { + if (!nature.equalsIgnoreCase(CuckooNature.NATURE_ID)) { + list.add(nature); + } + } + return list.toArray(new String[list.size()]); + } + + @Override + public void selectionChanged(IAction arg0, ISelection selection) { + if (selection instanceof IStructuredSelection) { + IStructuredSelection ss = (IStructuredSelection) selection; + Object obj = ss.getFirstElement(); + if (obj instanceof IJavaProject) { + currentProject = (IJavaProject) obj; + } + } + + } + + @Override + public void setActivePart(IAction arg0, IWorkbenchPart arg1) { + // nothing + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/StubDeriver.java b/src/interdroid/cuckoo/eclipse/plugin/StubDeriver.java new file mode 100755 index 0000000..c9da7a2 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/StubDeriver.java @@ -0,0 +1,209 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +public class StubDeriver { + + private final ErrorReporter reporter; + + public StubDeriver(ErrorReporter reporter) { + this.reporter = reporter; + } + + public void deriveStubFrom(String fileName, String projectLocation) { + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(new FileInputStream( + fileName))); + } catch (FileNotFoundException e) { + reporter.error(fileName + ": not found."); + } + + String packageName = null; + String interfaceName = null; + List methods = new ArrayList(); + try { + boolean localOnly = false; + while (true) { + String line = in.readLine(); + if (line == null) + break; + if (line.startsWith("package ")) {//$NON-NLS-1$ + packageName = line.substring("package ".length(), line//$NON-NLS-1$ + .indexOf(';')); + } + if (line.startsWith("public interface ")) {//$NON-NLS-1$ + interfaceName = line.substring( + "public interface ".length(), line//$NON-NLS-1$ + .indexOf(" extends"));//$NON-NLS-1$ + } + if (line.startsWith("public ")//$NON-NLS-1$ + && line.endsWith(" throws android.os.RemoteException;")) {//$NON-NLS-1$ + if (!localOnly) { + methods.add(line + .substring( + "public ".length(), line//$NON-NLS-1$ + .indexOf(" throws android.os.RemoteException;")));//$NON-NLS-1$ + } + localOnly = false; + } + if (line.trim().startsWith("//") + && (line.trim().substring(2).trim() + .startsWith("cuckoo.strategy") || line.trim() + .substring(2).trim() + .startsWith("cuckoo:strategy"))) { + try { + if ("local".equals(line.trim().substring(2).trim() + .split("=", 2)[1])) { + localOnly = true; + } + } catch (Throwable t) { + // ignore + } + } + if (line.endsWith("}")) { + localOnly = false; + } + + if (line.startsWith("public static abstract class Stub extends android.os.Binder implements")) {//$NON-NLS-1$ + } + } + in.close(); + } catch (IOException e) { + reporter.error(fileName + ": could not read."); + return; + } finally { + try { + in.close(); + } catch (Throwable e) { + // ignored + } + } + + File file = new File(fileName); + // create dir and files + File derivedDirectory = new File( + (file.getParent() + File.separator + "remote").replace("gen",//$NON-NLS-1$//$NON-NLS-2$ + "remote" + File.separator + packageName + ".remote."//$NON-NLS-1//$NON-NLS-2$ + + interfaceName)); + String derivedPath = derivedDirectory.getPath(); + if (!derivedDirectory.exists()) { + if (!derivedDirectory.mkdirs()) { + reporter.error("unable to create derived directory: " + + derivedPath); + return; + } + } + File derivedInterfaceFile = new File(derivedPath + File.separator + + interfaceName + ".java");//$NON-NLS-1$ + writeInterface(derivedInterfaceFile, packageName + ".remote",//$NON-NLS-1$ + interfaceName, methods); + File derivedImplementationFile = new File(derivedPath + File.separator + + interfaceName + "Impl.java");//$NON-NLS-1$//$NON-NLS-2$ + if (derivedImplementationFile.exists()) { + // derivedImplementationFile.renameTo(new File(derivedPath + // + File.separator + interfaceName + "Impl.java.saved"));//$NON-NLS-1$//$NON-NLS-2$ + } else { + writeImpl(derivedImplementationFile, packageName + ".remote",//$NON-NLS-1$ + interfaceName, methods); + } + File derivedExternalJarDirectory = new File(projectLocation + + File.separator + + "remote"//$NON-NLS-1$ + + File.separator + packageName + + ".remote." + interfaceName + File.separator + "external");//$NON-NLS-1$//$NON-NLS-2$ + if (!derivedExternalJarDirectory.exists()) { + derivedExternalJarDirectory.mkdirs(); + } + } + + private void writeInterface(File file, String packageName, + String interfaceName, List methods) { + FileWriter out = null; + try { + out = new FileWriter(file); + out.write("package " + packageName + ";\n");//$NON-NLS-1$//$NON-NLS-2$ + out.write("interface " + interfaceName + " {\n");//$NON-NLS-1$//$NON-NLS-2$ + for (String method : methods) { + out.write("public " + method + " throws Exception;\n");//$NON-NLS-1$//$NON-NLS-2$ + } + out.write("}\n");//$NON-NLS-1$ + out.flush(); + } catch (IOException e) { + reporter.error(file.getName() + ": could not write."); + } finally { + try { + out.close(); + } catch (Throwable e) { + // ignore + } + } + } + + private void writeImpl(File file, String packageName, String interfaceName, + List methods) { + FileWriter out = null; + try { + out = new FileWriter(file); + out.write("package " + packageName + ";\n");//$NON-NLS-1$//$NON-NLS-2$ + out.write("public class " + interfaceName + "Impl"//$NON-NLS-1$//$NON-NLS-2$ + // + " extends interdroid.cuckoo.CuckooService implements "//$NON-NLS-1$ + + " extends Object implements " + packageName + "."//$NON-NLS-1$//$NON-NLS-2$ + + interfaceName + " {\n");//$NON-NLS-1$ + for (String method : methods) { + out.write("public " + method + " throws Exception {\n");//$NON-NLS-1$//$NON-NLS-2$ + out.write(" return " + getDefaultReturnValue(method)//$NON-NLS-1$ + + ";\n");//$NON-NLS-1$ + out.write("}\n");//$NON-NLS-1$ + } + out.write("}\n");//$NON-NLS-1$ + out.flush(); + out.close(); + } catch (IOException e) { + reporter.error(file.getName() + ": could not write."); + } + } + + private String getDefaultReturnValue(String method) { + if (method.startsWith("void")) {//$NON-NLS-1$ + return "";//$NON-NLS-1$ + } + if (method.split(" ")[0].endsWith("[]")) {//$NON-NLS-1$ + return "null";//$NON-NLS-1$ + } + if (method.startsWith("int ")) {//$NON-NLS-1$ + return "0";//$NON-NLS-1$ + } + if (method.startsWith("boolean ")) {//$NON-NLS-1$ + return "true";//$NON-NLS-1$ + } + if (method.startsWith("char ")) {//$NON-NLS-1$ + return "0";//$NON-NLS-1$ + } + if (method.startsWith("long ")) {//$NON-NLS-1$ + return "0";//$NON-NLS-1$ + } + if (method.startsWith("byte ")) {//$NON-NLS-1$ + return "0";//$NON-NLS-1$ + } + if (method.startsWith("float ")) {//$NON-NLS-1$ + return "0";//$NON-NLS-1$ + } + if (method.startsWith("double ")) {//$NON-NLS-1$ + return "0";//$NON-NLS-1$ + } + if (method.startsWith("short ")) {//$NON-NLS-1$ + return "0";//$NON-NLS-1$ + } + return "null";//$NON-NLS-1$ + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/Util.java b/src/interdroid/cuckoo/eclipse/plugin/Util.java new file mode 100644 index 0000000..19140f5 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/Util.java @@ -0,0 +1,39 @@ +package interdroid.cuckoo.eclipse.plugin; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +public class Util { + + public static List getFileAsStringList(String file, ErrorReporter reporter) { + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader(new FileInputStream( + file))); + } catch (FileNotFoundException e) { + // won't happen + reporter.error(file + ": could not open for reading"); + return null; + } + List lines = new ArrayList(); + try { + while (true) { + String line = in.readLine(); + if (line == null) + break; + lines.add(line); + } + in.close(); + } catch (IOException e) { + reporter.error(file + ": got exception while reading"); + return null; + } + return lines; + } + +} diff --git a/src/interdroid/cuckoo/eclipse/plugin/preferences/.gitignore b/src/interdroid/cuckoo/eclipse/plugin/preferences/.gitignore new file mode 100644 index 0000000..9bb88d3 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/preferences/.gitignore @@ -0,0 +1 @@ +/.DS_Store diff --git a/src/interdroid/cuckoo/eclipse/plugin/preferences/CuckooPreferencePage.java b/src/interdroid/cuckoo/eclipse/plugin/preferences/CuckooPreferencePage.java new file mode 100755 index 0000000..03ccdc7 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/preferences/CuckooPreferencePage.java @@ -0,0 +1,28 @@ +package interdroid.cuckoo.eclipse.plugin.preferences; + +import org.eclipse.jface.preference.*; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.IWorkbench; +import interdroid.cuckoo.eclipse.plugin.CuckooPlugin; + +public class CuckooPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + + public static String CUCKOO_LOCATION = "interdroid.cuckoo.location";//$NON-NLS-1$ + + public CuckooPreferencePage() { + super(GRID); + setPreferenceStore(CuckooPlugin.getDefault().getPreferenceStore()); + setDescription("Cuckoo preferences"); + } + + public void createFieldEditors() { + addField(new DirectoryFieldEditor(CUCKOO_LOCATION, "Cuckoo Library Location", getFieldEditorParent())); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + public void init(IWorkbench workbench) { + } + +} \ No newline at end of file diff --git a/src/interdroid/cuckoo/eclipse/plugin/preferences/PreferenceInitializer.java b/src/interdroid/cuckoo/eclipse/plugin/preferences/PreferenceInitializer.java new file mode 100755 index 0000000..75d5ec3 --- /dev/null +++ b/src/interdroid/cuckoo/eclipse/plugin/preferences/PreferenceInitializer.java @@ -0,0 +1,26 @@ +package interdroid.cuckoo.eclipse.plugin.preferences; + +import java.io.File; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.jface.preference.IPreferenceStore; + +import interdroid.cuckoo.eclipse.plugin.CuckooPlugin; + +/** + * Class used to initialize default preference values. + */ +public class PreferenceInitializer extends AbstractPreferenceInitializer { + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() + */ + public void initializeDefaultPreferences() { + IPreferenceStore store = CuckooPlugin.getDefault().getPreferenceStore(); + store.setDefault(CuckooPreferencePage.CUCKOO_LOCATION, System.getProperty("user.home") + + File.separator + "cuckoo-library"); + } + +}