summaryrefslogtreecommitdiffstats
path: root/dalvik
diff options
context:
space:
mode:
Diffstat (limited to 'dalvik')
-rw-r--r--dalvik/MODULE_LICENSE_APACHE20
-rw-r--r--dalvik/src/main/java/dalvik/annotation/AnnotationDefault.java27
-rw-r--r--dalvik/src/main/java/dalvik/annotation/EnclosingClass.java27
-rw-r--r--dalvik/src/main/java/dalvik/annotation/EnclosingMethod.java27
-rw-r--r--dalvik/src/main/java/dalvik/annotation/InnerClass.java27
-rw-r--r--dalvik/src/main/java/dalvik/annotation/MemberClasses.java27
-rw-r--r--dalvik/src/main/java/dalvik/annotation/Signature.java27
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestInfo.java50
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestStatus.java44
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestTarget.java44
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestTargetClass.java39
-rw-r--r--dalvik/src/main/java/dalvik/annotation/Throws.java27
-rw-r--r--dalvik/src/main/java/dalvik/bytecode/Opcodes.java316
-rw-r--r--dalvik/src/main/java/dalvik/system/AllocationLimitError.java37
-rw-r--r--dalvik/src/main/java/dalvik/system/DexFile.java161
-rw-r--r--dalvik/src/main/java/dalvik/system/NativeStart.java40
-rw-r--r--dalvik/src/main/java/dalvik/system/PathClassLoader.java403
-rw-r--r--dalvik/src/main/java/dalvik/system/PotentialDeadlockError.java37
-rw-r--r--dalvik/src/main/java/dalvik/system/StaleDexCacheError.java37
-rw-r--r--dalvik/src/main/java/dalvik/system/TemporaryDirectory.java97
-rw-r--r--dalvik/src/main/java/dalvik/system/TouchDex.java150
-rw-r--r--dalvik/src/main/java/dalvik/system/TouchDexLoader.java340
-rw-r--r--dalvik/src/main/java/dalvik/system/VMDebug.java227
-rw-r--r--dalvik/src/main/java/dalvik/system/VMRuntime.java178
-rw-r--r--dalvik/src/main/java/dalvik/system/VMStack.java67
-rw-r--r--dalvik/src/main/java/dalvik/system/Zygote.java70
-rw-r--r--dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java68
-rw-r--r--dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java64
-rw-r--r--dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java142
-rw-r--r--dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java177
-rw-r--r--dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java84
-rw-r--r--dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/README.txt1
-rw-r--r--dalvik/src/main/native/dalvik_system_TouchDex.cpp278
-rw-r--r--dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.c78
-rw-r--r--dalvik/src/main/native/sub.mk18
35 files changed, 3436 insertions, 0 deletions
diff --git a/dalvik/MODULE_LICENSE_APACHE2 b/dalvik/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dalvik/MODULE_LICENSE_APACHE2
diff --git a/dalvik/src/main/java/dalvik/annotation/AnnotationDefault.java b/dalvik/src/main/java/dalvik/annotation/AnnotationDefault.java
new file mode 100644
index 0000000..91b5d15
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/AnnotationDefault.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * A "system annotation" used to provide the AnnotationDefault attribute.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface AnnotationDefault {}
+
diff --git a/dalvik/src/main/java/dalvik/annotation/EnclosingClass.java b/dalvik/src/main/java/dalvik/annotation/EnclosingClass.java
new file mode 100644
index 0000000..a15993a
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/EnclosingClass.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * A "system annotation" used to provide part of the InnerClasses attribute.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface EnclosingClass {}
+
diff --git a/dalvik/src/main/java/dalvik/annotation/EnclosingMethod.java b/dalvik/src/main/java/dalvik/annotation/EnclosingMethod.java
new file mode 100644
index 0000000..88d5e52
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/EnclosingMethod.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * A "system annotation" used to provide the EnclosingMethod attribute.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface EnclosingMethod {}
+
diff --git a/dalvik/src/main/java/dalvik/annotation/InnerClass.java b/dalvik/src/main/java/dalvik/annotation/InnerClass.java
new file mode 100644
index 0000000..02cf704
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/InnerClass.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * A "system annotation" used to provide part of the InnerClasses attribute.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface InnerClass {}
+
diff --git a/dalvik/src/main/java/dalvik/annotation/MemberClasses.java b/dalvik/src/main/java/dalvik/annotation/MemberClasses.java
new file mode 100644
index 0000000..5b201da
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/MemberClasses.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * A "system annotation" used to provide the MemberClasses list.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface MemberClasses {}
+
diff --git a/dalvik/src/main/java/dalvik/annotation/Signature.java b/dalvik/src/main/java/dalvik/annotation/Signature.java
new file mode 100644
index 0000000..86b22de
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/Signature.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * A "system annotation" used to provide the Signature attribute.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface Signature {}
+
diff --git a/dalvik/src/main/java/dalvik/annotation/TestInfo.java b/dalvik/src/main/java/dalvik/annotation/TestInfo.java
new file mode 100644
index 0000000..e9c2128
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/TestInfo.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Defines an annotation for test methods that allow, among other things, to
+ * link the test to the method that is being tested.
+ *
+ * {@hide}
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+public @interface TestInfo {
+
+ /**
+ * Specifies the current status of the test, as determined by a reviewer.
+ */
+ TestStatus status() default TestStatus.TBR;
+
+ /**
+ * Specifies noteworthy plain-text information about the test, like whether
+ * it is testing a specific parameter combination or something.
+ */
+ String notes() default "";
+
+ /**
+ * Specifies an array of target methods.
+ */
+ TestTarget[] targets();
+
+}
diff --git a/dalvik/src/main/java/dalvik/annotation/TestStatus.java b/dalvik/src/main/java/dalvik/annotation/TestStatus.java
new file mode 100644
index 0000000..d5aad12
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/TestStatus.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+/**
+ * Defines an enumeration of possible states a test case can be in.
+ *
+ * {@hide}
+ *
+ */
+public enum TestStatus {
+
+ /**
+ * Status is "to be reviewed", which is the initial state when a test method
+ * has been annotated.
+ */
+ TBR,
+
+ /**
+ * Status is "to do", meaning a reviewer has determined that additional work
+ * is needed.
+ */
+ TODO,
+
+ /**
+ * Status is "looks good to me", meaning the test is okay.
+ */
+ LGTM
+
+}
diff --git a/dalvik/src/main/java/dalvik/annotation/TestTarget.java b/dalvik/src/main/java/dalvik/annotation/TestTarget.java
new file mode 100644
index 0000000..feefa05
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/TestTarget.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Defines an annotation used be used within the TestInfo annotation. It
+ * specifies a single method target for the test (but can be used multiple
+ * times).
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.ANNOTATION_TYPE })
+public @interface TestTarget {
+
+ /**
+ * Specifies the name of the method that is being tested.
+ */
+ String methodName();
+
+ /**
+ * Specifies the signature of the method that is being tested, in terms of
+ * Java classes.
+ */
+ Class<?>[] methodArgs() default {};
+
+}
diff --git a/dalvik/src/main/java/dalvik/annotation/TestTargetClass.java b/dalvik/src/main/java/dalvik/annotation/TestTargetClass.java
new file mode 100644
index 0000000..59d104a
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/TestTargetClass.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Defines an annotation for test classes that allows to link them to the class
+ * that is being tested. The current assumption is that the test are somewhat
+ * organized according to the API classes they test. Might be too strict for
+ * some cases.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE })
+public @interface TestTargetClass {
+
+ /**
+ * Specifies the class being tested.
+ */
+ Class<?> value();
+
+}
diff --git a/dalvik/src/main/java/dalvik/annotation/Throws.java b/dalvik/src/main/java/dalvik/annotation/Throws.java
new file mode 100644
index 0000000..342d890
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/annotation/Throws.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * A "system annotation" used to provide the Exceptions attribute.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.ANNOTATION_TYPE)
+@interface Throws {}
+
diff --git a/dalvik/src/main/java/dalvik/bytecode/Opcodes.java b/dalvik/src/main/java/dalvik/bytecode/Opcodes.java
new file mode 100644
index 0000000..4d5602d
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/bytecode/Opcodes.java
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.bytecode;
+
+/**
+ * This is a list of Dalvik opcodes.
+ *
+ * (This was converted from //device/dalvik/libdex/OpCode.h)
+ */
+public interface Opcodes {
+ int OP_NOP = 0x00;
+
+ int OP_MOVE = 0x01;
+ int OP_MOVE_FROM16 = 0x02;
+ int OP_MOVE_16 = 0x03;
+ int OP_MOVE_WIDE = 0x04;
+ int OP_MOVE_WIDE_FROM16 = 0x05;
+ int OP_MOVE_WIDE_16 = 0x06;
+ int OP_MOVE_OBJECT = 0x07;
+ int OP_MOVE_OBJECT_FROM16 = 0x08;
+ int OP_MOVE_OBJECT_16 = 0x09;
+
+ int OP_MOVE_RESULT = 0x0a;
+ int OP_MOVE_RESULT_WIDE = 0x0b;
+ int OP_MOVE_RESULT_OBJECT = 0x0c;
+ int OP_MOVE_EXCEPTION = 0x0d;
+
+ int OP_RETURN_VOID = 0x0e;
+ int OP_RETURN = 0x0f;
+ int OP_RETURN_WIDE = 0x10;
+ int OP_RETURN_OBJECT = 0x11;
+
+ int OP_CONST_4 = 0x12;
+ int OP_CONST_16 = 0x13;
+ int OP_CONST = 0x14;
+ int OP_CONST_HIGH16 = 0x15;
+ int OP_CONST_WIDE_16 = 0x16;
+ int OP_CONST_WIDE_32 = 0x17;
+ int OP_CONST_WIDE = 0x18;
+ int OP_CONST_WIDE_HIGH16 = 0x19;
+ int OP_CONST_STRING = 0x1a;
+ int OP_CONST_STRING_JUMBO = 0x1b;
+ int OP_CONST_CLASS = 0x1c;
+
+ int OP_MONITOR_ENTER = 0x1d;
+ int OP_MONITOR_EXIT = 0x1e;
+
+ int OP_CHECK_CAST = 0x1f;
+ int OP_INSTANCE_OF = 0x20;
+
+ int OP_ARRAY_LENGTH = 0x21;
+
+ int OP_NEW_INSTANCE = 0x22;
+ int OP_NEW_ARRAY = 0x23;
+
+ int OP_FILLED_NEW_ARRAY = 0x24;
+ int OP_FILLED_NEW_ARRAY_RANGE = 0x25;
+ int OP_FILL_ARRAY_DATA = 0x26;
+
+ int OP_THROW = 0x27;
+ int OP_GOTO = 0x28;
+ int OP_GOTO_16 = 0x29;
+ int OP_GOTO_32 = 0x2a;
+ int OP_PACKED_SWITCH = 0x2b;
+ int OP_SPARSE_SWITCH = 0x2c;
+
+ int OP_CMPL_FLOAT = 0x2d;
+ int OP_CMPG_FLOAT = 0x2e;
+ int OP_CMPL_DOUBLE = 0x2f;
+ int OP_CMPG_DOUBLE = 0x30;
+ int OP_CMP_LONG = 0x31;
+
+ int OP_IF_EQ = 0x32;
+ int OP_IF_NE = 0x33;
+ int OP_IF_LT = 0x34;
+ int OP_IF_GE = 0x35;
+ int OP_IF_GT = 0x36;
+ int OP_IF_LE = 0x37;
+ int OP_IF_EQZ = 0x38;
+ int OP_IF_NEZ = 0x39;
+ int OP_IF_LTZ = 0x3a;
+ int OP_IF_GEZ = 0x3b;
+ int OP_IF_GTZ = 0x3c;
+ int OP_IF_LEZ = 0x3d;
+
+ int OP_UNUSED_3e = 0x3e;
+ int OP_UNUSED_3f = 0x3f;
+ int OP_UNUSED_40 = 0x40;
+ int OP_UNUSED_41 = 0x41;
+ int OP_UNUSED_42 = 0x42;
+ int OP_UNUSED_43 = 0x43;
+
+ int OP_AGET = 0x44;
+ int OP_AGET_WIDE = 0x45;
+ int OP_AGET_OBJECT = 0x46;
+ int OP_AGET_BOOLEAN = 0x47;
+ int OP_AGET_BYTE = 0x48;
+ int OP_AGET_CHAR = 0x49;
+ int OP_AGET_SHORT = 0x4a;
+ int OP_APUT = 0x4b;
+ int OP_APUT_WIDE = 0x4c;
+ int OP_APUT_OBJECT = 0x4d;
+ int OP_APUT_BOOLEAN = 0x4e;
+ int OP_APUT_BYTE = 0x4f;
+ int OP_APUT_CHAR = 0x50;
+ int OP_APUT_SHORT = 0x51;
+
+ int OP_IGET = 0x52;
+ int OP_IGET_WIDE = 0x53;
+ int OP_IGET_OBJECT = 0x54;
+ int OP_IGET_BOOLEAN = 0x55;
+ int OP_IGET_BYTE = 0x56;
+ int OP_IGET_CHAR = 0x57;
+ int OP_IGET_SHORT = 0x58;
+ int OP_IPUT = 0x59;
+ int OP_IPUT_WIDE = 0x5a;
+ int OP_IPUT_OBJECT = 0x5b;
+ int OP_IPUT_BOOLEAN = 0x5c;
+ int OP_IPUT_BYTE = 0x5d;
+ int OP_IPUT_CHAR = 0x5e;
+ int OP_IPUT_SHORT = 0x5f;
+
+ int OP_SGET = 0x60;
+ int OP_SGET_WIDE = 0x61;
+ int OP_SGET_OBJECT = 0x62;
+ int OP_SGET_BOOLEAN = 0x63;
+ int OP_SGET_BYTE = 0x64;
+ int OP_SGET_CHAR = 0x65;
+ int OP_SGET_SHORT = 0x66;
+ int OP_SPUT = 0x67;
+ int OP_SPUT_WIDE = 0x68;
+ int OP_SPUT_OBJECT = 0x69;
+ int OP_SPUT_BOOLEAN = 0x6a;
+ int OP_SPUT_BYTE = 0x6b;
+ int OP_SPUT_CHAR = 0x6c;
+ int OP_SPUT_SHORT = 0x6d;
+
+ int OP_INVOKE_VIRTUAL = 0x6e;
+ int OP_INVOKE_SUPER = 0x6f;
+ int OP_INVOKE_DIRECT = 0x70;
+ int OP_INVOKE_STATIC = 0x71;
+ int OP_INVOKE_INTERFACE = 0x72;
+
+ int OP_UNUSED_73 = 0x73;
+
+ int OP_INVOKE_VIRTUAL_RANGE = 0x74;
+ int OP_INVOKE_SUPER_RANGE = 0x75;
+ int OP_INVOKE_DIRECT_RANGE = 0x76;
+ int OP_INVOKE_STATIC_RANGE = 0x77;
+ int OP_INVOKE_INTERFACE_RANGE = 0x78;
+
+ int OP_UNUSED_79 = 0x79;
+ int OP_UNUSED_7A = 0x7a;
+
+ int OP_NEG_INT = 0x7b;
+ int OP_NOT_INT = 0x7c;
+ int OP_NEG_LONG = 0x7d;
+ int OP_NOT_LONG = 0x7e;
+ int OP_NEG_FLOAT = 0x7f;
+ int OP_NEG_DOUBLE = 0x80;
+ int OP_INT_TO_LONG = 0x81;
+ int OP_INT_TO_FLOAT = 0x82;
+ int OP_INT_TO_DOUBLE = 0x83;
+ int OP_LONG_TO_INT = 0x84;
+ int OP_LONG_TO_FLOAT = 0x85;
+ int OP_LONG_TO_DOUBLE = 0x86;
+ int OP_FLOAT_TO_INT = 0x87;
+ int OP_FLOAT_TO_LONG = 0x88;
+ int OP_FLOAT_TO_DOUBLE = 0x89;
+ int OP_DOUBLE_TO_INT = 0x8a;
+ int OP_DOUBLE_TO_LONG = 0x8b;
+ int OP_DOUBLE_TO_FLOAT = 0x8c;
+ int OP_INT_TO_BYTE = 0x8d;
+ int OP_INT_TO_CHAR = 0x8e;
+ int OP_INT_TO_SHORT = 0x8f;
+
+ int OP_ADD_INT = 0x90;
+ int OP_SUB_INT = 0x91;
+ int OP_MUL_INT = 0x92;
+ int OP_DIV_INT = 0x93;
+ int OP_REM_INT = 0x94;
+ int OP_AND_INT = 0x95;
+ int OP_OR_INT = 0x96;
+ int OP_XOR_INT = 0x97;
+ int OP_SHL_INT = 0x98;
+ int OP_SHR_INT = 0x99;
+ int OP_USHR_INT = 0x9a;
+
+ int OP_ADD_LONG = 0x9b;
+ int OP_SUB_LONG = 0x9c;
+ int OP_MUL_LONG = 0x9d;
+ int OP_DIV_LONG = 0x9e;
+ int OP_REM_LONG = 0x9f;
+ int OP_AND_LONG = 0xa0;
+ int OP_OR_LONG = 0xa1;
+ int OP_XOR_LONG = 0xa2;
+ int OP_SHL_LONG = 0xa3;
+ int OP_SHR_LONG = 0xa4;
+ int OP_USHR_LONG = 0xa5;
+
+ int OP_ADD_FLOAT = 0xa6;
+ int OP_SUB_FLOAT = 0xa7;
+ int OP_MUL_FLOAT = 0xa8;
+ int OP_DIV_FLOAT = 0xa9;
+ int OP_REM_FLOAT = 0xaa;
+ int OP_ADD_DOUBLE = 0xab;
+ int OP_SUB_DOUBLE = 0xac;
+ int OP_MUL_DOUBLE = 0xad;
+ int OP_DIV_DOUBLE = 0xae;
+ int OP_REM_DOUBLE = 0xaf;
+
+ int OP_ADD_INT_2ADDR = 0xb0;
+ int OP_SUB_INT_2ADDR = 0xb1;
+ int OP_MUL_INT_2ADDR = 0xb2;
+ int OP_DIV_INT_2ADDR = 0xb3;
+ int OP_REM_INT_2ADDR = 0xb4;
+ int OP_AND_INT_2ADDR = 0xb5;
+ int OP_OR_INT_2ADDR = 0xb6;
+ int OP_XOR_INT_2ADDR = 0xb7;
+ int OP_SHL_INT_2ADDR = 0xb8;
+ int OP_SHR_INT_2ADDR = 0xb9;
+ int OP_USHR_INT_2ADDR = 0xba;
+
+ int OP_ADD_LONG_2ADDR = 0xbb;
+ int OP_SUB_LONG_2ADDR = 0xbc;
+ int OP_MUL_LONG_2ADDR = 0xbd;
+ int OP_DIV_LONG_2ADDR = 0xbe;
+ int OP_REM_LONG_2ADDR = 0xbf;
+ int OP_AND_LONG_2ADDR = 0xc0;
+ int OP_OR_LONG_2ADDR = 0xc1;
+ int OP_XOR_LONG_2ADDR = 0xc2;
+ int OP_SHL_LONG_2ADDR = 0xc3;
+ int OP_SHR_LONG_2ADDR = 0xc4;
+ int OP_USHR_LONG_2ADDR = 0xc5;
+
+ int OP_ADD_FLOAT_2ADDR = 0xc6;
+ int OP_SUB_FLOAT_2ADDR = 0xc7;
+ int OP_MUL_FLOAT_2ADDR = 0xc8;
+ int OP_DIV_FLOAT_2ADDR = 0xc9;
+ int OP_REM_FLOAT_2ADDR = 0xca;
+ int OP_ADD_DOUBLE_2ADDR = 0xcb;
+ int OP_SUB_DOUBLE_2ADDR = 0xcc;
+ int OP_MUL_DOUBLE_2ADDR = 0xcd;
+ int OP_DIV_DOUBLE_2ADDR = 0xce;
+ int OP_REM_DOUBLE_2ADDR = 0xcf;
+
+ int OP_ADD_INT_LIT16 = 0xd0;
+ int OP_RSUB_INT = 0xd1; /* no _LIT16 suffix for this */
+ int OP_MUL_INT_LIT16 = 0xd2;
+ int OP_DIV_INT_LIT16 = 0xd3;
+ int OP_REM_INT_LIT16 = 0xd4;
+ int OP_AND_INT_LIT16 = 0xd5;
+ int OP_OR_INT_LIT16 = 0xd6;
+ int OP_XOR_INT_LIT16 = 0xd7;
+
+ int OP_ADD_INT_LIT8 = 0xd8;
+ int OP_RSUB_INT_LIT8 = 0xd9;
+ int OP_MUL_INT_LIT8 = 0xda;
+ int OP_DIV_INT_LIT8 = 0xdb;
+ int OP_REM_INT_LIT8 = 0xdc;
+ int OP_AND_INT_LIT8 = 0xdd;
+ int OP_OR_INT_LIT8 = 0xde;
+ int OP_XOR_INT_LIT8 = 0xdf;
+ int OP_SHL_INT_LIT8 = 0xe0;
+ int OP_SHR_INT_LIT8 = 0xe1;
+ int OP_USHR_INT_LIT8 = 0xe2;
+
+ int OP_UNUSED_E3 = 0xe3;
+ int OP_UNUSED_E4 = 0xe4;
+ int OP_UNUSED_E5 = 0xe5;
+ int OP_UNUSED_E6 = 0xe6;
+ int OP_UNUSED_E7 = 0xe7;
+ int OP_UNUSED_E8 = 0xe8;
+ int OP_UNUSED_E9 = 0xe9;
+ int OP_UNUSED_EA = 0xea;
+ int OP_UNUSED_EB = 0xeb;
+ int OP_UNUSED_EC = 0xec;
+ int OP_UNUSED_ED = 0xed;
+
+ /* optimizer output -- these are never generated by "dx" */
+ int OP_EXECUTE_INLINE = 0xee;
+ int OP_UNUSED_EF = 0xef; /* OP_EXECUTE_INLINE_RANGE? */
+
+ int OP_INVOKE_DIRECT_EMPTY = 0xf0;
+ int OP_UNUSED_F1 = 0xf1; /* OP_INVOKE_DIRECT_EMPTY_RANGE? */
+ int OP_IGET_QUICK = 0xf2;
+ int OP_IGET_WIDE_QUICK = 0xf3;
+ int OP_IGET_OBJECT_QUICK = 0xf4;
+ int OP_IPUT_QUICK = 0xf5;
+ int OP_IPUT_WIDE_QUICK = 0xf6;
+ int OP_IPUT_OBJECT_QUICK = 0xf7;
+
+ int OP_INVOKE_VIRTUAL_QUICK = 0xf8;
+ int OP_INVOKE_VIRTUAL_QUICK_RANGE = 0xf9;
+ int OP_INVOKE_SUPER_QUICK = 0xfa;
+ int OP_INVOKE_SUPER_QUICK_RANGE = 0xfb;
+ int OP_UNUSED_FC = 0xfc; /* OP_INVOKE_DIRECT_QUICK? */
+ int OP_UNUSED_FD = 0xfd; /* OP_INVOKE_DIRECT_QUICK_RANGE? */
+ int OP_UNUSED_FE = 0xfe; /* OP_INVOKE_INTERFACE_QUICK? */
+ int OP_UNUSED_FF = 0xff; /* OP_INVOKE_INTERFACE_QUICK_RANGE*/
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/AllocationLimitError.java b/dalvik/src/main/java/dalvik/system/AllocationLimitError.java
new file mode 100644
index 0000000..9747578
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/AllocationLimitError.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * This is thrown when an allocation limit is exceeded.
+ */
+public class AllocationLimitError extends VirtualMachineError {
+ /**
+ * Initialize exception with default values.
+ */
+ public AllocationLimitError() {
+ super();
+ }
+
+ /**
+ * Initialize exception with the supplied message string.
+ */
+ public AllocationLimitError(String detailMessage) {
+ super(detailMessage);
+ }
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
new file mode 100644
index 0000000..8fa1062
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.security.ProtectionDomain;
+import java.util.Enumeration;
+
+
+/**
+ * Manipulate DEX files. Similar in principle to java.util.zip.ZipFile.
+ * Used primarily by class loaders.
+ *
+ * We don't directly open and read the DEX file here. They're mapped read-only
+ * by the VM.
+ */
+public final class DexFile {
+ private final int mCookie;
+ private String mFileName;
+
+ /**
+ * Open a DEX file from a File object.
+ */
+ public DexFile(File file) throws IOException {
+ this(file.getPath());
+ }
+
+ /**
+ * Open a DEX file from a filename (preferrably a full path).
+ *
+ * This will usually be a Zip/Jar with a "classes.dex" inside. Do not
+ * specify the "dalvik-cache" version directly.
+ */
+ public DexFile(String fileName) throws IOException {
+ String wantDex = System.getProperty("android.vm.dexfile", "false");
+ if (!wantDex.equals("true"))
+ throw new UnsupportedOperationException("No dex in this VM");
+
+ mCookie = openDexFile(fileName);
+ mFileName = fileName;
+ //System.out.println("DEX FILE cookie is " + mCookie);
+ }
+
+ /**
+ * Get the name of the open file.
+ */
+ public String getName() {
+ return mFileName;
+ }
+
+ /**
+ * Close a DEX file.
+ *
+ * This may not be able to release any resources. If classes have
+ * been loaded, the underlying storage can't be discarded.
+ */
+ public void close() throws IOException {
+ closeDexFile(mCookie);
+ }
+
+ /**
+ * Load a class. Returns the class on success, or a null reference
+ * on failure.
+ *
+ * If you are not calling this from a class loader, this is most likely
+ * not going to do what you want. Use Class.forName() instead.
+ *
+ * "name" should look like "java/lang/String".
+ *
+ * I'm not throwing an exception if the class isn't found because I
+ * don't want to be throwing exceptions wildly every time we load a
+ * class that isn't in the first DEX file we look at. This method
+ * *will* throw exceptions for anything that isn't ClassNotFoundException.
+ */
+ public Class loadClass(String name, ClassLoader loader) {
+ return defineClass(name, loader, mCookie,
+ null);
+ //new ProtectionDomain(name) /*DEBUG ONLY*/);
+ }
+ native private static Class defineClass(String name, ClassLoader loader,
+ int cookie, ProtectionDomain pd);
+
+ /**
+ * Enumerate the names of the classes in this DEX file.
+ */
+ public Enumeration<String> entries() {
+ return new DFEnum(this);
+ }
+
+ /*
+ * Helper class.
+ */
+ private class DFEnum implements Enumeration<String> {
+ private int mIndex;
+ private String[] mNameList;
+
+ DFEnum(DexFile df) {
+ mIndex = 0;
+ mNameList = getClassNameList(mCookie);
+ }
+
+ public boolean hasMoreElements() {
+ return (mIndex < mNameList.length);
+ }
+
+ public String nextElement() {
+ return mNameList[mIndex++];
+ }
+ }
+
+ /* return a String array with class names */
+ native private static String[] getClassNameList(int cookie);
+
+ /**
+ * GC helper.
+ */
+ protected void finalize() throws IOException {
+ close();
+ }
+
+ /*
+ * Open a DEX file. The value returned is a magic VM cookie. On
+ * failure, an IOException is thrown.
+ */
+ native private static int openDexFile(String fileName) throws IOException;
+ native private static void closeDexFile(int cookie);
+
+ /**
+ * Returns true if the VM believes that the apk/jar file is out of date
+ * and should be passed through "dexopt" again.
+ *
+ * @param fileName the absolute path to the apk/jar file to examine.
+ * @return true if dexopt should be called on the file, false otherwise.
+ * @throws java.io.FileNotFoundException if fileName is not readable,
+ * not a file, or not present.
+ * @throws java.io.IOException if fileName is not a valid apk/jar file or
+ * if problems occur while parsing it.
+ * @throws java.lang.NullPointerException if fileName is null.
+ * @throws dalvik.system.StaleDexCacheError if the optimized dex file
+ * is stale but exists on a read-only partition.
+ */
+ native public static boolean isDexOptNeeded(String fileName)
+ throws FileNotFoundException, IOException;
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/NativeStart.java b/dalvik/src/main/java/dalvik/system/NativeStart.java
new file mode 100644
index 0000000..ee360ff
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/NativeStart.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * Dummy class used during JNI initialization. The JNI functions want
+ * to be able to create objects, and the VM needs to discard the references
+ * when the function returns. That gets a little weird when we're
+ * calling JNI functions from the C main(), and there's no Java stack frame
+ * to hitch the references onto.
+ *
+ * Rather than having some special-case code, we create this simple little
+ * class and pretend that it called the C main().
+ *
+ * This also comes in handy when a native thread attaches itself with the
+ * JNI AttachCurrentThread call. If they attach the thread and start
+ * creating objects, we need a fake frame to store stuff in.
+ */
+class NativeStart implements Runnable {
+ private NativeStart() {}
+
+ private static native void main(String[] dummy);
+
+ public native void run();
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/PathClassLoader.java b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
new file mode 100644
index 0000000..4dacf3f
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.net.MalformedURLException;
+
+import dalvik.system.DexFile;
+
+/**
+ * Simple ClassLoader implementation.
+ *
+ * This loads classes from a colon-separated list.
+ */
+public class PathClassLoader extends ClassLoader {
+
+ private final String path;
+ private final String libPath;
+
+ private boolean initialized;
+
+ private String[] mPaths;
+ private File[] mFiles;
+ private ZipFile[] mZips;
+ private DexFile[] mDexs;
+ private String[] mLibPaths;
+
+ /**
+ * Create a ClassLoader that finds files in the specified path.
+ */
+ public PathClassLoader(String path, ClassLoader parent) {
+ this(path, null, parent);
+ }
+
+ /**
+ * Create a ClassLoader that finds files in the specified path.
+ *
+ * The path is a colon-separated list of files and directories. For
+ * Dalvik, this is usually a list of .jar and .apk filenames.
+ *
+ * @param path A colon-separated class path.
+ * @param libPath A colon-separated list of directories where native
+ * libraries can be found.
+ * @param parent The parent class loader.
+ */
+ public PathClassLoader(String path, String libPath, ClassLoader parent) {
+ super(parent);
+
+ if (path == null)
+ throw new NullPointerException();
+
+ this.path = path;
+ this.libPath = libPath;
+ }
+
+ private void ensureInit() {
+ if (initialized) {
+ return;
+ }
+
+ initialized = true;
+
+ mPaths = path.split(":");
+ int length = mPaths.length;
+
+ //System.out.println("PathClassLoader: " + mPaths);
+ mFiles = new File[length];
+ mZips = new ZipFile[length];
+ mDexs = new DexFile[length];
+
+ boolean wantDex =
+ System.getProperty("android.vm.dexfile", "").equals("true");
+
+ /* open all Zip and DEX files up front */
+ for (int i = 0; i < length; i++) {
+ //System.out.println("My path is: " + mPaths[i]);
+ File pathFile = new File(mPaths[i]);
+ mFiles[i] = pathFile;
+
+ if (pathFile.isFile()) {
+ try {
+ mZips[i] = new ZipFile(pathFile);
+ }
+ catch (IOException ioex) {
+ // expecting IOException and ZipException
+ //System.out.println("Failed opening '" + archive + "': " + ioex);
+ //ioex.printStackTrace();
+ }
+ if (wantDex) {
+ /* we need both DEX and Zip, because dex has no resources */
+ try {
+ mDexs[i] = new DexFile(pathFile);
+ }
+ catch (IOException ioex) {}
+ }
+ }
+ }
+
+ /*
+ * Prep for native library loading.
+ */
+ String pathList = System.getProperty("java.library.path", ".");
+ String pathSep = System.getProperty("path.separator", ":");
+ String fileSep = System.getProperty("file.separator", "/");
+
+ if (libPath != null) {
+ if (pathList.length() > 0) {
+ pathList += pathSep + libPath;
+ }
+ else {
+ pathList = libPath;
+ }
+ }
+
+ mLibPaths = pathList.split(pathSep);
+ length = mLibPaths.length;
+
+ // Add a '/' to the end so we don't have to do the property lookup
+ // and concatenation later.
+ for (int i = 0; i < length; i++) {
+ if (!mLibPaths[i].endsWith(fileSep))
+ mLibPaths[i] += fileSep;
+ if (false)
+ System.out.println("Native lib path: " + mLibPaths[i]);
+ }
+ }
+
+ /**
+ * Find the class with the specified name. None of our ancestors were
+ * able to find it, so it's up to us now.
+ *
+ * "name" is a "binary name", e.g. "java.lang.String" or
+ * "java.net.URLClassLoader$3$1".
+ *
+ * This method will either return a valid Class object or throw an
+ * exception. Does not return null.
+ */
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ ensureInit();
+
+ //System.out.println("PathClassLoader " + this + ": findClass '" + name + "'");
+
+ byte[] data = null;
+ int length = mPaths.length;
+
+ for (int i = 0; i < length; i++) {
+ //System.out.println("My path is: " + mPaths[i]);
+
+ if (mDexs[i] != null) {
+ String slashName = name.replace('.', '/');
+ Class clazz = mDexs[i].loadClass(slashName, this);
+ if (clazz != null)
+ return clazz;
+ } else if (mZips[i] != null) {
+ String fileName = name.replace('.', '/') + ".class";
+ data = loadFromArchive(mZips[i], fileName);
+ } else {
+ File pathFile = mFiles[i];
+ if (pathFile.isDirectory()) {
+ String fileName =
+ mPaths[i] + "/" + name.replace('.', '/') + ".class";
+ data = loadFromDirectory(fileName);
+ } else {
+ //System.out.println("PathClassLoader: can't find '"
+ // + mPaths[i] + "'");
+ }
+
+ }
+
+ /* --this doesn't work in current version of Dalvik--
+ if (data != null) {
+ System.out.println("--- Found class " + name
+ + " in zip[" + i + "] '" + mZips[i].getName() + "'");
+ int dotIndex = name.lastIndexOf('.');
+ if (dotIndex != -1) {
+ String packageName = name.substring(0, dotIndex);
+ synchronized (this) {
+ Package packageObj = getPackage(packageName);
+ if (packageObj == null) {
+ definePackage(packageName, null, null,
+ null, null, null, null, null);
+ }
+ }
+ }
+
+ return defineClass(name, data, 0, data.length);
+ }
+ */
+ }
+
+ throw new ClassNotFoundException(name + " in loader " + this);
+ }
+
+ /*
+ * Find a resource by name. This could be in a directory or in an
+ * archive.
+ */
+ protected URL findResource(String name) {
+ ensureInit();
+
+ //java.util.logging.Logger.global.severe("findResource: " + name);
+
+ int length = mPaths.length;
+
+ for (int i = 0; i < length; i++) {
+ File pathFile = mFiles[i];
+ ZipFile zip = mZips[i];
+ if (zip != null) {
+ if (isInArchive(zip, name)) {
+ //System.out.println(" found " + name + " in " + pathFile);
+ try {
+ // File.toURL() is compliant with RFC 1738 in always
+ // creating absolute path names. If we construct the
+ // URL by concatenating strings, we might end up with
+ // illegal URLs for relative names.
+ return new URL("jar:" + pathFile.toURL() + "!/" + name);
+ }
+ catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ } else if (pathFile.isDirectory()) {
+ File dataFile = new File(mPaths[i] + "/" + name);
+ if (dataFile.exists()) {
+ //System.out.println(" found resource " + name);
+ try {
+ // Same as archive case regarding URL construction.
+ return dataFile.toURL();
+ }
+ catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ } else if (pathFile.isFile()) {
+ } else {
+ System.err.println("PathClassLoader: can't find '"
+ + mPaths[i] + "'");
+ }
+ }
+
+ return null;
+ }
+
+
+ /*
+ * Load the contents of a file from a file in a directory.
+ *
+ * Returns null if the class wasn't found.
+ */
+ private byte[] loadFromDirectory(String path) {
+ RandomAccessFile raf;
+ byte[] fileData;
+
+ //System.out.println("Trying to load from " + path);
+ try {
+ raf = new RandomAccessFile(path, "r");
+ }
+ catch (FileNotFoundException fnfe) {
+ //System.out.println(" Not found: " + path);
+ return null;
+ }
+
+ try {
+ fileData = new byte[(int) raf.length()];
+ raf.read(fileData);
+ raf.close();
+ }
+ catch (IOException ioe) {
+ System.err.println("Error reading from " + path);
+ // swallow it, return null instead
+ fileData = null;
+ }
+
+ return fileData;
+ }
+
+ /*
+ * Load a class from a file in an archive. We currently assume that
+ * the file is a Zip archive.
+ *
+ * Returns null if the class wasn't found.
+ */
+ private byte[] loadFromArchive(ZipFile zip, String name) {
+ ZipEntry entry;
+
+ entry = zip.getEntry(name);
+ if (entry == null)
+ return null;
+
+ ByteArrayOutputStream byteStream;
+ InputStream stream;
+ int count;
+
+ /*
+ * Copy the data out of the stream. Because we got the ZipEntry
+ * from a ZipFile, the uncompressed size is known, and we can set
+ * the initial size of the ByteArrayOutputStream appropriately.
+ */
+ try {
+ stream = zip.getInputStream(entry);
+ byteStream = new ByteArrayOutputStream((int) entry.getSize());
+ byte[] buf = new byte[4096];
+ while ((count = stream.read(buf)) > 0)
+ byteStream.write(buf, 0, count);
+
+ stream.close();
+ }
+ catch (IOException ioex) {
+ //System.out.println("Failed extracting '" + archive + "': " +ioex);
+ return null;
+ }
+
+ //System.out.println(" loaded from Zip");
+ return byteStream.toByteArray();
+ }
+
+ /*
+ * Figure out if "name" is a member of "archive".
+ */
+ private boolean isInArchive(ZipFile zip, String name) {
+ return zip.getEntry(name) != null;
+ }
+
+ /**
+ * Find a native library.
+ *
+ * Return the full pathname of the first appropriate-looking file
+ * we find.
+ */
+ protected String findLibrary(String libname) {
+ ensureInit();
+
+ String fileName = System.mapLibraryName(libname);
+ for (int i = 0; i < mLibPaths.length; i++) {
+ String pathName = mLibPaths[i] + fileName;
+ File test = new File(pathName);
+
+ if (test.exists())
+ return pathName;
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns package information for the given package. Unfortunately, the
+ * PathClassLoader doesn't really have this information, and as a
+ * non-secure ClassLoader, it isn't even required to, according to the spec.
+ * Yet, we want to provide it, in order to make all those hopeful callers of
+ * <code>myClass.getPackage().getName()</code> happy. Thus we construct a
+ * Package object the first time it is being requested and fill most of the
+ * fields with dummy values. The Package object is then put into the
+ * ClassLoader's Package cache, so we see the same one next time. We don't
+ * create Package objects for null arguments or for the default package.
+ * <p>
+ * There a limited chance that we end up with multiple Package objects
+ * representing the same package: It can happen when when a package is
+ * scattered across different JAR files being loaded by different
+ * ClassLoaders. Rather unlikely, and given that this whole thing is more or
+ * less a workaround, probably not worth the effort.
+ */
+ @Override
+ protected Package getPackage(String name) {
+ if (name != null && !"".equals(name)) {
+ synchronized(this) {
+ Package pack = super.getPackage(name);
+
+ if (pack == null) {
+ pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", "Unknown", null);
+ }
+
+ return pack;
+ }
+ }
+
+ return null;
+ }
+
+}
diff --git a/dalvik/src/main/java/dalvik/system/PotentialDeadlockError.java b/dalvik/src/main/java/dalvik/system/PotentialDeadlockError.java
new file mode 100644
index 0000000..defa182
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/PotentialDeadlockError.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * This is thrown when the VM identifies a potential deadlock.
+ */
+public class PotentialDeadlockError extends VirtualMachineError {
+ /**
+ * Initialize exception with default values.
+ */
+ public PotentialDeadlockError() {
+ super();
+ }
+
+ /**
+ * Initialize exception with the supplied message string.
+ */
+ public PotentialDeadlockError(String detailMessage) {
+ super(detailMessage);
+ }
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/StaleDexCacheError.java b/dalvik/src/main/java/dalvik/system/StaleDexCacheError.java
new file mode 100644
index 0000000..a124058
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/StaleDexCacheError.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * This is thrown when the VM determines that a dex file's cache
+ * is out of date, and that there is no way to recreate it.
+ */
+public class StaleDexCacheError extends VirtualMachineError {
+ /**
+ * Initialize exception with default values.
+ */
+ public StaleDexCacheError() {
+ super();
+ }
+
+ /**
+ * Initialize exception with the supplied message string.
+ */
+ public StaleDexCacheError(String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/TemporaryDirectory.java b/dalvik/src/main/java/dalvik/system/TemporaryDirectory.java
new file mode 100644
index 0000000..ae0ecb2
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/TemporaryDirectory.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+import java.io.File;
+import java.util.logging.Logger;
+
+/**
+ * Utility class to handle the setup of the core library's concept of
+ * what the "default temporary directory" is. Application code may
+ * call into this class with an appropriate base directory during its
+ * startup, as a reasonably easy way to get the standard property
+ * <code>java.io.tmpdir</code> to point at something useful.
+ */
+public class TemporaryDirectory {
+ /** system property name for the temporary directory */
+ private static final String PROPERTY = "java.io.tmpdir";
+
+ /** final path component name for the temporary directory */
+ private static final String PATH_NAME = "tmp";
+
+ /** whether a temporary directory has been configured yet */
+ private static boolean configured = false;
+
+ /**
+ * Convenience method which is equivalent to
+ * <code>setupDirectory(new File(baseDir))</code>.
+ *
+ * @param baseDir the base directory of the temporary directory
+ */
+ public static void setUpDirectory(String baseDir) {
+ setUpDirectory(new File(baseDir));
+ }
+
+ /**
+ * Sets up the temporary directory, but only if one isn't already
+ * defined for this process, and only if it is possible (e.g., the
+ * directory already exists and is read-write, or the directory
+ * can be created). This call will do one of three things:
+ *
+ * <ul>
+ * <li>return without error and without doing anything, if a
+ * previous call to this method succeeded</li>
+ * <li>return without error, having either created a temporary
+ * directory under the given base or verified that such a directory
+ * already exists</li>
+ * <li>throw <code>UnsupportedOperationException</code> if the
+ * directory could not be created or accessed</li>
+ * </ul>
+ *
+ * @param baseDir the base directory of the temporary directory
+ */
+ public static synchronized void setUpDirectory(File baseDir) {
+ if (configured) {
+ Logger.global.info("Already set to: " +
+ System.getProperty(PROPERTY));
+ return;
+ }
+
+ File dir = new File(baseDir, PATH_NAME);
+ String absolute = dir.getAbsolutePath();
+
+ if (dir.exists()) {
+ if (!dir.isDirectory()) {
+ throw new UnsupportedOperationException(
+ "Name is used by a non-directory file: " +
+ absolute);
+ } else if (!(dir.canRead() && dir.canWrite())) {
+ throw new UnsupportedOperationException(
+ "Existing directory is not readable and writable: " +
+ absolute);
+ }
+ } else {
+ if (!dir.mkdirs()) {
+ throw new UnsupportedOperationException(
+ "Failed to create directory: " + absolute);
+ }
+ }
+
+ System.setProperty(PROPERTY, absolute);
+ configured = true;
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/TouchDex.java b/dalvik/src/main/java/dalvik/system/TouchDex.java
new file mode 100644
index 0000000..5aedbf5
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/TouchDex.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.File;
+import java.io.FilenameFilter;
+
+/**
+ * Induce optimization/verification of a set of DEX files.
+ *
+ * TODO: This class is public, so SystemServer can access it. This is NOT
+ * the correct long-term solution; once we have a real installer and/or
+ * dalvik-cache manager, this class should be removed.
+ */
+public class TouchDex {
+
+ /**
+ * Fork a process, make sure the DEX files are prepped, and return
+ * when everything is finished.
+ *
+ * The filenames must be the same as will be used when the files are
+ * actually opened, because the dalvik-cache filename is based upon
+ * this filename. (The absolute path to the jar/apk should work.)
+ *
+ * @param dexFiles Colon-separated list of DEX files.
+ * @return zero on success
+ */
+ public static int start(String dexFiles) {
+ return trampoline(dexFiles, System.getProperty("java.boot.class.path"));
+ }
+
+ /**
+ * This calls fork() and then, in the child, calls cont(dexFiles).
+ *
+ * @param dexFiles Colon-separated list of DEX files.
+ * @return zero on success
+ */
+ native private static int trampoline(String dexFiles, String bcp);
+
+ /**
+ * We continue here in the child process. args[0] can be a colon-separated
+ * path list, or "-" to read from stdin.
+ *
+ * Alternatively, if we're invoked directly from the command line we
+ * just start here (skipping the fork/exec stuff).
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+
+ if ("-".equals(args[0])) {
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(System.in), 256);
+
+ String line;
+ try {
+ while ((line = in.readLine()) != null) {
+ prepFiles(line);
+ }
+ } catch (IOException ex) {
+ throw new RuntimeException ("Error processing stdin");
+ }
+ } else {
+ prepFiles(args[0]);
+ }
+
+ System.out.println(" Prep complete");
+ }
+
+
+ private static String expandDirectories(String dexPath) {
+ String[] parts = dexPath.split(":");
+ StringBuilder outPath = new StringBuilder(dexPath.length());
+
+ // A filename filter accepting *.jar and *.apk
+ FilenameFilter filter = new FilenameFilter() {
+ public boolean accept(File dir, String name) {
+ return name.endsWith(".jar") || name.endsWith(".apk");
+ }
+ };
+
+ for (String part: parts) {
+ File f = new File(part);
+
+ if (f.isFile()) {
+ outPath.append(part);
+ outPath.append(':');
+ } else if (f.isDirectory()) {
+ String[] filenames = f.list(filter);
+
+ if (filenames == null) {
+ System.err.println("I/O error with directory: " + part);
+ continue;
+ }
+
+ for (String filename: filenames) {
+ outPath.append(part);
+ outPath.append(File.separatorChar);
+ outPath.append(filename);
+ outPath.append(':');
+ }
+ } else {
+ System.err.println("File not found: " + part);
+ }
+ }
+
+
+ return outPath.toString();
+ }
+
+ private static void prepFiles(String dexPath) {
+
+ System.out.println(" Prepping: " + dexPath);
+
+ TouchDexLoader loader
+ = new TouchDexLoader(expandDirectories(dexPath), null);
+
+ try {
+ /* By looking for a nonexistent class, we'll trick TouchDexLoader
+ * into trying to load something from every file on dexPath,
+ * optimizing all of them as a side-effect.
+ *
+ * The optimization happens implicitly in the VM the first time
+ * someone tries to load a class from an unoptimized dex file.
+ */
+ loader.loadClass("com.google.NonexistentClassNeverFound");
+ throw new RuntimeException("nonexistent class loaded?!");
+ } catch (ClassNotFoundException cnfe) {
+ //System.out.println("got expected dnfe");
+ }
+ }
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/TouchDexLoader.java b/dalvik/src/main/java/dalvik/system/TouchDexLoader.java
new file mode 100644
index 0000000..18669c5
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/TouchDexLoader.java
@@ -0,0 +1,340 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.net.URL;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.net.MalformedURLException;
+
+import dalvik.system.DexFile;
+
+/**
+ * Cloned out of PathClassLoader for TouchDex. This could be made
+ * substantially smaller, since we don't need most of this.
+ */
+class TouchDexLoader extends ClassLoader {
+
+ private String path;
+
+ private boolean initialized;
+
+ /**
+ * Create a ClassLoader that finds files in the specified path.
+ */
+ public TouchDexLoader(String path, ClassLoader parent) {
+ super(parent);
+
+ if (path == null)
+ throw new NullPointerException();
+
+ this.path = path;
+ }
+
+ private void ensureInit() {
+ if (initialized) {
+ return;
+ }
+
+ initialized = true;
+
+ mPaths = path.split(":");
+ //System.out.println("TouchDexLoader: " + mPaths);
+ mFiles = new File[mPaths.length];
+ mZips = new ZipFile[mPaths.length];
+ mDexs = new DexFile[mPaths.length];
+
+ boolean wantDex =
+ System.getProperty("android.vm.dexfile", "").equals("true");
+
+ /* open all Zip and DEX files up front */
+ for (int i = 0; i < mPaths.length; i++) {
+ //System.out.println("My path is: " + mPaths[i]);
+ File pathFile = new File(mPaths[i]);
+ mFiles[i] = pathFile;
+
+ if (pathFile.isFile()) {
+ if (false) { //--------------------
+ try {
+ mZips[i] = new ZipFile(pathFile);
+ }
+ catch (IOException ioex) {
+ // expecting IOException and ZipException
+ //System.out.println("Failed opening '" + archive + "': " + ioex);
+ //ioex.printStackTrace();
+ }
+ } //--------------------
+ if (wantDex) {
+ /* we need both DEX and Zip, because dex has no resources */
+ try {
+ mDexs[i] = new DexFile(pathFile);
+ }
+ catch (IOException ioex) {
+ System.err.println("Couldn't open " + mPaths[i]
+ + " as DEX");
+ }
+ }
+ } else {
+ System.err.println("File not found: " + mPaths[i]);
+ }
+ }
+
+ /*
+ * Prep for native library loading.
+ */
+ String pathList = System.getProperty("java.library.path", ".");
+ String pathSep = System.getProperty("path.separator", ":");
+ String fileSep = System.getProperty("file.separator", "/");
+
+ mLibPaths = pathList.split(pathSep);
+
+ // Add a '/' to the end so we don't have to do the property lookup
+ // and concatenation later.
+ for (int i = 0; i < mLibPaths.length; i++) {
+ if (!mLibPaths[i].endsWith(fileSep))
+ mLibPaths[i] += fileSep;
+ if (false)
+ System.out.println("Native lib path: " + mLibPaths[i]);
+ }
+ }
+
+ /**
+ * Find the class with the specified name. None of our ancestors were
+ * able to find it, so it's up to us now.
+ *
+ * "name" is a "binary name", e.g. "java.lang.String" or
+ * "java.net.URLClassLoader$3$1".
+ *
+ * This method will either return a valid Class object or throw an
+ * exception. Does not return null.
+ */
+ protected Class<?> findClass(String name) throws ClassNotFoundException
+ {
+ ensureInit();
+
+ byte[] data = null;
+ int i;
+
+ //System.out.println("TouchDexLoader " + this + ": findClass '" + name + "'");
+
+ for (i = 0; i < mPaths.length; i++) {
+ //System.out.println("My path is: " + mPaths[i]);
+
+ if (mDexs[i] != null) {
+ String slashName = name.replace('.', '/');
+ Class clazz = mDexs[i].loadClass(slashName, this);
+ if (clazz != null)
+ return clazz;
+ } else if (mZips[i] != null) {
+ String fileName = name.replace('.', '/') + ".class";
+ data = loadFromArchive(mZips[i], fileName);
+ } else {
+ File pathFile = mFiles[i];
+ if (pathFile.isDirectory()) {
+ String fileName =
+ mPaths[i] + "/" + name.replace('.', '/') + ".class";
+ data = loadFromDirectory(fileName);
+ } else {
+ //System.out.println("TouchDexLoader: can't find '"
+ // + mPaths[i] + "'");
+ }
+
+ }
+
+ if (data != null) {
+ //System.out.println(" found class " + name);
+ int dotIndex = name.lastIndexOf('.');
+ if (dotIndex != -1) {
+ String packageName = name.substring(0, dotIndex);
+ synchronized (this) {
+ Package packageObj = getPackage(packageName);
+ if (packageObj == null) {
+ definePackage(packageName, null, null,
+ null, null, null, null, null);
+ }
+ }
+ }
+
+ return defineClass(name, data, 0, data.length);
+ }
+ }
+
+ throw new ClassNotFoundException(name + " in loader " + this);
+ }
+
+ /*
+ * Find a resource by name. This could be in a directory or in an
+ * archive.
+ */
+ protected URL findResource(String name) {
+ ensureInit();
+
+ byte[] data = null;
+ int i;
+
+ //System.out.println("TouchDexLoader: findResource '" + name + "'");
+
+ for (i = 0; i < mPaths.length; i++) {
+ File pathFile = mFiles[i];
+ ZipFile zip = mZips[i];
+ if (zip != null) {
+ if (isInArchive(zip, name)) {
+ //System.out.println(" found " + name + " in " + pathFile);
+ // Create URL correctly - was XXX, new code should be ok.
+ try {
+ return new URL("jar:file://" + pathFile + "!/" + name);
+ }
+ catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ } else if (pathFile.isDirectory()) {
+ File dataFile = new File(mPaths[i] + "/" + name);
+ if (dataFile.exists()) {
+ //System.out.println(" found resource " + name);
+ // Create URL correctly - was XXX, new code should be ok.
+ try {
+ return new URL("file:" + name);
+ }
+ catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ } else if (pathFile.isFile()) {
+ } else {
+ System.err.println("TouchDexLoader: can't find '"
+ + mPaths[i] + "'");
+ }
+ }
+
+ return null;
+ }
+
+
+ /*
+ * Load the contents of a file from a file in a directory.
+ *
+ * Returns null if the class wasn't found.
+ */
+ private byte[] loadFromDirectory(String path) {
+ RandomAccessFile raf;
+ byte[] fileData;
+
+ //System.out.println("Trying to load from " + path);
+ try {
+ raf = new RandomAccessFile(path, "r");
+ }
+ catch (FileNotFoundException fnfe) {
+ //System.out.println(" Not found: " + path);
+ return null;
+ }
+
+ try {
+ fileData = new byte[(int) raf.length()];
+ raf.read(fileData);
+ raf.close();
+ }
+ catch (IOException ioe) {
+ System.err.println("Error reading from " + path);
+ // swallow it, return null instead
+ fileData = null;
+ }
+
+ return fileData;
+ }
+
+ /*
+ * Load a class from a file in an archive. We currently assume that
+ * the file is a Zip archive.
+ *
+ * Returns null if the class wasn't found.
+ */
+ private byte[] loadFromArchive(ZipFile zip, String name) {
+ ZipEntry entry;
+
+ entry = zip.getEntry(name);
+ if (entry == null)
+ return null;
+
+ ByteArrayOutputStream byteStream;
+ InputStream stream;
+ int count;
+
+ /*
+ * Copy the data out of the stream. Because we got the ZipEntry
+ * from a ZipFile, the uncompressed size is known, and we can set
+ * the initial size of the ByteArrayOutputStream appropriately.
+ */
+ try {
+ stream = zip.getInputStream(entry);
+ byteStream = new ByteArrayOutputStream((int) entry.getSize());
+ byte[] buf = new byte[4096];
+ while ((count = stream.read(buf)) > 0)
+ byteStream.write(buf, 0, count);
+
+ stream.close();
+ }
+ catch (IOException ioex) {
+ //System.out.println("Failed extracting '" + archive + "': " +ioex);
+ return null;
+ }
+
+ //System.out.println(" loaded from Zip");
+ return byteStream.toByteArray();
+ }
+
+ /*
+ * Figure out if "name" is a member of "archive".
+ */
+ private boolean isInArchive(ZipFile zip, String name) {
+ return zip.getEntry(name) != null;
+ }
+
+ /**
+ * Find a native library.
+ *
+ * Return the full pathname of the first appropriate-looking file
+ * we find.
+ */
+ protected String findLibrary(String libname) {
+ ensureInit();
+
+ String fileName = System.mapLibraryName(libname);
+ for (int i = 0; i < mLibPaths.length; i++) {
+ String pathName = mLibPaths[i] + fileName;
+ File test = new File(pathName);
+
+ if (test.exists())
+ return pathName;
+ }
+
+ return null;
+ }
+
+ private String[] mPaths;
+ private File[] mFiles;
+ private ZipFile[] mZips;
+ private DexFile[] mDexs;
+ private String[] mLibPaths;
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/VMDebug.java b/dalvik/src/main/java/dalvik/system/VMDebug.java
new file mode 100644
index 0000000..64a8321
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * VM-specific debug features. Though this class and many of its members
+ * are public, this class is meant to be wrapped in a more friendly way
+ * for use by application developers. On the Android platform, the
+ * recommended way to access this functionality is through the class
+ * <code>android.os.Debug</code>.
+ */
+public final class VMDebug {
+ /** default method trace data file name */
+ static public final String DEFAULT_METHOD_TRACE_FILE_NAME = "/sdcard/dmtrace.trace";
+
+ /**
+ * flag for startMethodTracing(), which adds the results from
+ * startAllocCounting to the trace key file.
+ */
+ public static final int TRACE_COUNT_ALLOCS = 1;
+
+ /* constants for getAllocCount */
+ private static final int KIND_ALLOCATED_OBJECTS = 1<<0;
+ private static final int KIND_ALLOCATED_BYTES = 1<<1;
+ private static final int KIND_FREED_OBJECTS = 1<<2;
+ private static final int KIND_FREED_BYTES = 1<<3;
+ private static final int KIND_GC_INVOCATIONS = 1<<4;
+ private static final int KIND_EXT_ALLOCATED_OBJECTS = 1<<12;
+ private static final int KIND_EXT_ALLOCATED_BYTES = 1<<13;
+ private static final int KIND_EXT_FREED_OBJECTS = 1<<14;
+ private static final int KIND_EXT_FREED_BYTES = 1<<15;
+
+ public static final int KIND_GLOBAL_ALLOCATED_OBJECTS =
+ KIND_ALLOCATED_OBJECTS;
+ public static final int KIND_GLOBAL_ALLOCATED_BYTES =
+ KIND_ALLOCATED_BYTES;
+ public static final int KIND_GLOBAL_FREED_OBJECTS =
+ KIND_FREED_OBJECTS;
+ public static final int KIND_GLOBAL_FREED_BYTES =
+ KIND_FREED_BYTES;
+ public static final int KIND_GLOBAL_GC_INVOCATIONS =
+ KIND_GC_INVOCATIONS;
+ public static final int KIND_GLOBAL_EXT_ALLOCATED_OBJECTS =
+ KIND_EXT_ALLOCATED_OBJECTS;
+ public static final int KIND_GLOBAL_EXT_ALLOCATED_BYTES =
+ KIND_EXT_ALLOCATED_BYTES;
+ public static final int KIND_GLOBAL_EXT_FREED_OBJECTS =
+ KIND_EXT_FREED_OBJECTS;
+ public static final int KIND_GLOBAL_EXT_FREED_BYTES =
+ KIND_EXT_FREED_BYTES;
+
+ public static final int KIND_THREAD_ALLOCATED_OBJECTS =
+ KIND_ALLOCATED_OBJECTS << 16;
+ public static final int KIND_THREAD_ALLOCATED_BYTES =
+ KIND_ALLOCATED_BYTES << 16;
+ public static final int KIND_THREAD_FREED_OBJECTS =
+ KIND_FREED_OBJECTS << 16;
+ public static final int KIND_THREAD_FREED_BYTES =
+ KIND_FREED_BYTES << 16;
+ public static final int KIND_THREAD_GC_INVOCATIONS =
+ KIND_GC_INVOCATIONS << 16;
+ public static final int KIND_THREAD_EXT_ALLOCATED_OBJECTS =
+ KIND_EXT_ALLOCATED_OBJECTS << 16;
+ public static final int KIND_THREAD_EXT_ALLOCATED_BYTES =
+ KIND_EXT_ALLOCATED_BYTES << 16;
+ public static final int KIND_THREAD_EXT_FREED_OBJECTS =
+ KIND_EXT_FREED_OBJECTS << 16;
+ public static final int KIND_THREAD_EXT_FREED_BYTES =
+ KIND_EXT_FREED_BYTES << 16;
+
+ public static final int KIND_ALL_COUNTS = 0xffffffff;
+
+ /* all methods are static */
+ private VMDebug() {}
+
+ /**
+ * Time, in msec, since the last debugger activity. -1 if debugger is
+ * not connected.
+ */
+ public static native long lastDebuggerActivity();
+
+ /**
+ * Determine if a debugger is currently attached.
+ */
+ public static native boolean isDebuggerConnected();
+
+ /**
+ * Enable object allocation count logging and reporting. Call with
+ * a depth of zero to disable. This produces "top N" lists on every GC.
+ */
+ //public static native void enableTopAllocCounts(int depth);
+
+ /**
+ * Start method tracing with default name, size, and with <code>0</code>
+ * flags.
+ */
+ public static void startMethodTracing() {
+ startMethodTracing(DEFAULT_METHOD_TRACE_FILE_NAME, 0, 0);
+ }
+
+ /**
+ * Start method tracing, specifying a file name as well as a default
+ * buffer size. See <a
+ * href="{@docRoot}reference/traceview.html"> Running the
+ * Traceview Debugging Program</a> for information about reading
+ * trace files.
+ *
+ * <p>You can use either a fully qualified path and
+ * name, or just a name. If only a name is specified, the file will
+ * be created under the /sdcard/ directory. If a name is not given,
+ * the default is /sdcard/dmtrace.trace.</p>
+ *
+ * @param traceFileName name to give the trace file
+ * @param bufferSize the maximum size of both files combined. If passed
+ * as <code>0</code>, it defaults to 8MB.
+ * @param flags flags to control method tracing. The only one that
+ * is currently defined is {@link #TRACE_COUNT_ALLOCS}.
+ */
+ public static native void startMethodTracing(String traceFileName,
+ int bufferSize, int flags);
+
+ /**
+ * Stop method tracing.
+ */
+ public static native void stopMethodTracing();
+
+ /**
+ * Start sending Dalvik method trace info to the emulator.
+ */
+ public static native void startEmulatorTracing();
+
+ /**
+ * Stop sending Dalvik method trace info to the emulator.
+ */
+ public static native void stopEmulatorTracing();
+
+ /**
+ * Get an indication of thread CPU usage. The value returned
+ * indicates the amount of time that the current thread has spent
+ * executing code or waiting for certain types of I/O.
+ *
+ * The time is expressed in nanoseconds, and is only meaningful
+ * when compared to the result from an earlier call. Note that
+ * nanosecond resolution does not imply nanosecond accuracy.
+ *
+ * On system which don't support this operation, the call returns -1.
+ */
+ public static native long threadCpuTimeNanos();
+
+ /**
+ * Count the number and aggregate size of memory allocations between
+ * two points.
+ */
+ public static native void startAllocCounting();
+ public static native void stopAllocCounting();
+ public static native int getAllocCount(int kind);
+ public static native void resetAllocCount(int kinds);
+
+ /**
+ * Establish an object allocation limit in the current thread. Useful
+ * for catching regressions in code that is expected to operate
+ * without causing any allocations.
+ *
+ * Use -1 to disable the limit.
+ *
+ * Returns the previous limit.
+ */
+ public static native int setAllocationLimit(int limit);
+
+ /**
+ * Establish an object allocation limit for the entire VM. Very much
+ * like setAllocationLimit().
+ *
+ * Use -1 to disable the limit.
+ *
+ * Returns the previous limit.
+ */
+ public static native int setGlobalAllocationLimit(int limit);
+
+ /**
+ * Count the number of instructions executed between two points.
+ */
+ public static native void startInstructionCounting();
+ public static native void stopInstructionCounting();
+ public static native void getInstructionCount(int[] counts);
+ public static native void resetInstructionCount();
+
+ /**
+ * Dump a list of loaded class to the log file.
+ */
+ public static native void printLoadedClasses(int flags);
+
+ /**
+ * Get the number of loaded classes.
+ */
+ public static native int getLoadedClassCount();
+
+ /* don't ask */
+ static native void printThis(Object thisThing, int count, int thing);
+
+ /*
+ * Fake method, inserted into dmtrace output when the garbage collector
+ * runs. Not actually called.
+ */
+ private static void startGC() {}
+
+ /*
+ * Fake method, inserted into dmtrace output during class preparation
+ * (loading and linking, but not verification or initialization). Not
+ * actually called.
+ */
+ private static void startClassPrep() {}
+}
diff --git a/dalvik/src/main/java/dalvik/system/VMRuntime.java b/dalvik/src/main/java/dalvik/system/VMRuntime.java
new file mode 100644
index 0000000..615d301
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/VMRuntime.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * Provides an interface to VM-global, Dalvik-specific features.
+ * An application cannot create its own Runtime instance, and must obtain
+ * one from the getRuntime method.
+ */
+public final class VMRuntime {
+
+ /**
+ * Holds the VMRuntime singleton.
+ */
+ private static final VMRuntime THE_ONE = new VMRuntime();
+
+ /**
+ * Prevents this class from being instantiated.
+ */
+ private VMRuntime() {
+ }
+
+ /**
+ * Returns the object that represents the VM instance's Dalvik-specific
+ * runtime environment.
+ *
+ * @return the runtime object
+ */
+ public static VMRuntime getRuntime() {
+ return THE_ONE;
+ }
+
+ /**
+ * Gets the current ideal heap utilization, represented as a number
+ * between zero and one. After a GC happens, the Dalvik heap may
+ * be resized so that (size of live objects) / (size of heap) is
+ * equal to this number.
+ *
+ * @return the current ideal heap utilization
+ */
+ public native float getTargetHeapUtilization();
+
+ /**
+ * Sets the current ideal heap utilization, represented as a number
+ * between zero and one. After a GC happens, the Dalvik heap may
+ * be resized so that (size of live objects) / (size of heap) is
+ * equal to this number.
+ *
+ * @param newTarget the new suggested ideal heap utilization.
+ * This value may be adjusted internally.
+ * @return the previous ideal heap utilization
+ * @throws IllegalArgumentException if newTarget is &lt;= 0.0 or &gt;= 1.0
+ */
+ public float setTargetHeapUtilization(float newTarget) {
+ if (newTarget <= 0.0 || newTarget >= 1.0) {
+ throw new IllegalArgumentException(newTarget +
+ " out of range (0,1)");
+ }
+ /* Synchronize to make sure that only one thread gets
+ * a given "old" value if both update at the same time.
+ * Allows for reliable save-and-restore semantics.
+ */
+ synchronized (this) {
+ float oldTarget = getTargetHeapUtilization();
+ nativeSetTargetHeapUtilization(newTarget);
+ return oldTarget;
+ }
+ }
+
+ /**
+ * Returns the minimum heap size, or zero if no minimum is in effect.
+ *
+ * @return the minimum heap size value
+ */
+ public long getMinimumHeapSize() {
+ return nativeMinimumHeapSize(0, false);
+ }
+
+ /**
+ * Sets the desired minimum heap size, and returns the
+ * old minimum size. If size is larger than the maximum
+ * size, the maximum size will be used. If size is zero
+ * or negative, the minimum size constraint will be removed.
+ *
+ * Synchronized to make the order of the exchange reliable.
+ *
+ * @param size the new suggested minimum heap size, in bytes
+ * @return the old minimum heap size value
+ */
+ public synchronized long setMinimumHeapSize(long size) {
+ return nativeMinimumHeapSize(size, true);
+ }
+
+ /**
+ * If set is true, sets the new minimum heap size to size; always
+ * returns the current (or previous) size.
+ *
+ * @param size the new suggested minimum heap size, in bytes
+ * @param set if true, set the size based on the size parameter,
+ * otherwise ignore it
+ * @return the old or current minimum heap size value
+ */
+ private native long nativeMinimumHeapSize(long size, boolean set);
+
+ /**
+ * Requests that the virtual machine collect available memory,
+ * and collects any SoftReferences that are not strongly-reachable.
+ */
+ public native void gcSoftReferences();
+
+ /**
+ * Does not return until any pending finalizers have been called.
+ * This may or may not happen in the context of the calling thread.
+ * No exceptions will escape.
+ */
+ public native void runFinalizationSync();
+
+ /**
+ * Implements setTargetHeapUtilization().
+ *
+ * @param newTarget the new suggested ideal heap utilization.
+ * This value may be adjusted internally.
+ */
+ private native void nativeSetTargetHeapUtilization(float newTarget);
+
+ /**
+ * Asks the VM if &lt;size&gt; bytes can be allocated in an external heap.
+ * This information may be used to limit the amount of memory available
+ * to Dalvik threads. Returns false if the VM would rather that the caller
+ * did not allocate that much memory. If the call returns false, the VM
+ * will not update its internal counts. May cause one or more GCs as a
+ * side-effect.
+ *
+ * Called by JNI code.
+ *
+ * {@hide}
+ *
+ * @param size The number of bytes that have been allocated.
+ * @return true if the VM thinks there's enough process memory
+ * to satisfy this request, or false if not.
+ */
+ public native boolean trackExternalAllocation(long size);
+
+ /**
+ * Tells the VM that &lt;size&gt; bytes have been freed in an external
+ * heap. This information may be used to control the amount of memory
+ * available to Dalvik threads.
+ *
+ * Called by JNI code.
+ *
+ * {@hide}
+ *
+ * @param size The number of bytes that have been freed. This same number
+ * should have been passed to trackExternalAlloc() when
+ * the underlying memory was originally allocated.
+ */
+ public native void trackExternalFree(long size);
+
+ /**
+ * Returns the number of externally-allocated bytes being tracked by
+ * trackExternalAllocation/Free().
+ */
+ public native long getExternalBytesAllocated();
+}
diff --git a/dalvik/src/main/java/dalvik/system/VMStack.java b/dalvik/src/main/java/dalvik/system/VMStack.java
new file mode 100644
index 0000000..5d7a7d3
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/VMStack.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dalvik.system;
+
+/**
+ * VM-internal classes for examining a stack.
+ */
+public final class VMStack {
+ /**
+ * Return the defining class loader of the caller's caller.
+ */
+ native public static ClassLoader getCallingClassLoader();
+
+ /**
+ * Return the defining class loader of the caller's caller's caller.
+ */
+ native public static ClassLoader getCallingClassLoader2();
+
+ /**
+ * Create an array of classes from the methods at the top of the stack.
+ * We continue until we reach the bottom of the stack or exceed the
+ * specified maximum depth. If stopAtPrivileged is set, the last
+ * element of the array will be the caller of the most-recent privileged
+ * method.
+ *
+ * The topmost stack frame (this method) and the one above that (the
+ * caller) are excluded from the array. Frames with java.lang.reflect
+ * classes are skipped over.
+ *
+ * The classes in the array are the defining classes of the methods.
+ *
+ * This is expected to be identical to Harmony's VMStack.getClasses.
+ *
+ * @param maxDepth
+ * maximum number of classes to return, or -1 for all
+ * @param stopAtPrivileged
+ * stop when a privileged frame is reached
+ * @return an array with classes for the most-recent methods on the stack
+ */
+ native public static Class<?>[] getClasses(int maxDepth,
+ boolean stopAtPrivileged);
+
+ /**
+ * Retrieve the stack trace from the specified thread.
+ *
+ * @param t
+ * thread of interest
+ * @return an array of stack trace elements, or null if the thread
+ * doesn't have a stack trace (e.g. because it exited)
+ */
+ native public static StackTraceElement[] getThreadStackTrace(Thread t);
+}
+
diff --git a/dalvik/src/main/java/dalvik/system/Zygote.java b/dalvik/src/main/java/dalvik/system/Zygote.java
new file mode 100644
index 0000000..5c527ac
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/Zygote.java
@@ -0,0 +1,70 @@
+// Copyright 2006 The Android Open Source Project
+
+package dalvik.system;
+
+/**
+ * Interfaces for supporting the Dalvik "zygote" feature, which allows
+ * a VM instance to be partially initialized and then fork()'d from
+ * the partially initialized state.
+ */
+
+public class Zygote {
+ private Zygote() {}
+
+ /**
+ * Forks a new Zygote instance, but does not leave the zygote mode.
+ * The current VM must have been started with the -Xzygote flag. The
+ * new child is expected to eventually call forkAndSpecialize()
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error
+ */
+ native public static int fork();
+
+ /**
+ * Forks a new VM instance. The current VM must have been started
+ * with the -Xzygote flag. <b>NOTE: new instance keeps all
+ * root capabilities. The new process is expected to call capset()<b>.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param enableDebugger true if JDWP should be enabled.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error.
+ */
+ native public static int forkAndSpecialize(int uid, int gid, int[] gids,
+ boolean enableDebugger, int[][] rlimits);
+
+ /**
+ * Special method to start the system server process. In addition to the
+ * common actions performed in forkAndSpecialize, the pid of the child
+ * process is recorded such that the death of the child process will cause
+ * zygote to exit.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param enableDebugger true if JDWP should be enabled.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error.
+ */
+ native public static int forkSystemServer(int uid, int gid,
+ int[] gids, boolean enableDebugger, int[][] rlimits);
+}
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java b/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
new file mode 100644
index 0000000..7b46d2e
--- /dev/null
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/NativeTestTarget.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.dalvik;
+
+/**
+ * Methods used to test calling into native code. The methods in this
+ * class are all effectively no-ops and may be used to test the mechanisms
+ * and performance of calling native methods.
+ */
+public final class NativeTestTarget {
+ /**
+ * This class is uninstantiable.
+ */
+ private NativeTestTarget() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * This is an empty native static method with no args, hooked up using
+ * JNI.
+ */
+ public static native void emptyJniStaticMethod0();
+
+ /**
+ * This is an empty native static method with six args, hooked up using
+ * JNI.
+ */
+ public static native void emptyJniStaticMethod6(int a, int b, int c,
+ int d, int e, int f);
+
+ /**
+ * This is an empty native static method with six args, hooked up
+ * using JNI. These have more complex args to show the cost of
+ * parsing the signature. All six values should be null
+ * references.
+ */
+ public static native void emptyJniStaticMethod6L(String a, String[] b,
+ int[][] c, Object d, Object[] e, Object[][][][] f);
+
+ /**
+ * This method is intended to be "inlined" by the virtual machine
+ * (e.g., given special treatment as an intrinsic).
+ */
+ public static void emptyInlineMethod() {
+ // This space intentionally left blank.
+ }
+
+ /**
+ * This method is intended to be defined in native code and hooked
+ * up using the virtual machine's special fast-path native linkage
+ * (as opposed to being hooked up using JNI).
+ */
+ public static native void emptyInternalStaticMethod();
+}
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java
new file mode 100644
index 0000000..9b98893
--- /dev/null
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/Chunk.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.dalvik.ddmc;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A chunk of DDM data. This is really just meant to hold a few pieces
+ * of data together.
+ *
+ * The "offset" and "length" fields are present so handlers can over-allocate
+ * or share byte buffers.
+ */
+public class Chunk {
+
+ /*
+ * Public members. Do not rename without updating the VM.
+ */
+ public int type; // chunk type
+ public byte[] data; // chunk data
+ public int offset, length; // position within "data"
+
+ /**
+ * Blank constructor. Fill in your own fields.
+ */
+ public Chunk() {}
+
+ /**
+ * Constructor with all fields.
+ */
+ public Chunk(int type, byte[] data, int offset, int length) {
+ this.type = type;
+ this.data = data;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ /**
+ * Construct from a ByteBuffer. The chunk is assumed to start at
+ * offset 0 and continue to the current position.
+ */
+ public Chunk(int type, ByteBuffer buf) {
+ this.type = type;
+
+ this.data = buf.array();
+ this.offset = buf.arrayOffset();
+ this.length = buf.position();
+ }
+}
+
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java
new file mode 100644
index 0000000..59a7cad
--- /dev/null
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.dalvik.ddmc;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Handle a chunk of data sent from a DDM server.
+ *
+ * To handle a chunk type, sub-class ChunkHandler and register your class
+ * with DdmServer.
+ */
+public abstract class ChunkHandler {
+
+ public static final ByteOrder CHUNK_ORDER = ByteOrder.BIG_ENDIAN;
+
+ public static final int CHUNK_FAIL = type("FAIL");
+
+
+ public ChunkHandler() {}
+
+ /**
+ * Called when the DDM server connects. The handler is allowed to
+ * send messages to the server.
+ */
+ public abstract void connected();
+
+ /**
+ * Called when the DDM server disconnects. Can be used to disable
+ * periodic transmissions or clean up saved state.
+ */
+ public abstract void disconnected();
+
+ /**
+ * Handle a single chunk of data. "request" includes the type and
+ * the chunk payload.
+ *
+ * Returns a response in a Chunk.
+ */
+ public abstract Chunk handleChunk(Chunk request);
+
+ /**
+ * Create a FAIL chunk. The "handleChunk" methods can use this to
+ * return an error message when they are not able to process a chunk.
+ */
+ public static Chunk createFailChunk(int errorCode, String msg) {
+ if (msg == null)
+ msg = "";
+
+ ByteBuffer out = ByteBuffer.allocate(8 + msg.length() * 2);
+ out.order(ChunkHandler.CHUNK_ORDER);
+ out.putInt(errorCode);
+ out.putInt(msg.length());
+ putString(out, msg);
+
+ return new Chunk(CHUNK_FAIL, out);
+ }
+
+ /**
+ * Utility function to wrap a ByteBuffer around a Chunk.
+ */
+ public static ByteBuffer wrapChunk(Chunk request) {
+ ByteBuffer in;
+
+ in = ByteBuffer.wrap(request.data, request.offset, request.length);
+ in.order(CHUNK_ORDER);
+ return in;
+ }
+
+
+ /**
+ * Utility function to copy a String out of a ByteBuffer.
+ *
+ * This is here because multiple chunk handlers can make use of it,
+ * and there's nowhere better to put it.
+ */
+ public static String getString(ByteBuffer buf, int len) {
+ char[] data = new char[len];
+ for (int i = 0; i < len; i++)
+ data[i] = buf.getChar();
+ return new String(data);
+ }
+
+ /**
+ * Utility function to copy a String into a ByteBuffer.
+ */
+ public static void putString(ByteBuffer buf, String str) {
+ int len = str.length();
+ for (int i = 0; i < len; i++)
+ buf.putChar(str.charAt(i));
+ }
+
+ /**
+ * Convert a 4-character string to a 32-bit type.
+ */
+ public static int type(String typeName)
+ {
+ int val = 0;
+
+ if (typeName.length() != 4)
+ throw new RuntimeException();
+
+ for (int i = 0; i < 4; i++) {
+ val <<= 8;
+ val |= (byte) typeName.charAt(i);
+ }
+
+ return val;
+ }
+
+ /**
+ * Convert an integer type to a 4-character string.
+ */
+ public static String name(int type)
+ {
+ char[] ascii = new char[4];
+
+ ascii[0] = (char) ((type >> 24) & 0xff);
+ ascii[1] = (char) ((type >> 16) & 0xff);
+ ascii[2] = (char) ((type >> 8) & 0xff);
+ ascii[3] = (char) (type & 0xff);
+
+ return new String(ascii);
+ }
+
+}
+
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
new file mode 100644
index 0000000..a7d429a
--- /dev/null
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmServer.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.dalvik.ddmc;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+
+
+/**
+ * This represents our connection to the DDM Server.
+ */
+public class DdmServer {
+
+ public static final int CLIENT_PROTOCOL_VERSION = 1;
+
+ private static HashMap<Integer,ChunkHandler> mHandlerMap =
+ new HashMap<Integer,ChunkHandler>();
+
+ private static final int CONNECTED = 1;
+ private static final int DISCONNECTED = 2;
+
+ private static volatile boolean mRegistrationComplete = false;
+ private static boolean mRegistrationTimedOut = false;
+
+
+ /**
+ * Don't instantiate; all members and methods are static.
+ */
+ private DdmServer() {}
+
+ /**
+ * Register an instance of the ChunkHandler class to handle a specific
+ * chunk type.
+ *
+ * Throws an exception if the type already has a handler registered.
+ */
+ public static void registerHandler(int type, ChunkHandler handler) {
+ if (handler == null)
+ throw new NullPointerException();
+
+ synchronized (mHandlerMap) {
+ if (mHandlerMap.get(type) != null)
+ throw new RuntimeException("type " + Integer.toHexString(type)
+ + " already registered");
+
+ mHandlerMap.put(type, handler);
+ }
+ }
+
+ /**
+ * Unregister the existing handler for the specified type.
+ *
+ * Returns the old handler.
+ */
+ public static ChunkHandler unregisterHandler(int type) {
+ synchronized (mHandlerMap) {
+ return mHandlerMap.remove(type);
+ }
+ }
+
+ /**
+ * The application must call here after it finishes registering
+ * handlers.
+ */
+ public static void registrationComplete() {
+ // sync on mHandlerMap because it's convenient and makes a kind of
+ // sense
+ synchronized (mHandlerMap) {
+ mRegistrationComplete = true;
+ mHandlerMap.notifyAll();
+ }
+ }
+
+ /**
+ * Send a chunk of data to the DDM server. This takes the form of a
+ * JDWP "event", which does not elicit a response from the server.
+ *
+ * Use this for "unsolicited" chunks.
+ */
+ public static void sendChunk(Chunk chunk) {
+ nativeSendChunk(chunk.type, chunk.data, chunk.offset, chunk.length);
+ }
+
+ /* send a chunk to the DDM server */
+ native private static void nativeSendChunk(int type, byte[] data,
+ int offset, int length);
+
+ /*
+ * Called by the VM when the DDM server connects or disconnects.
+ */
+ private static void broadcast(int event)
+ {
+ synchronized (mHandlerMap) {
+ Collection values = mHandlerMap.values();
+ Iterator iter = values.iterator();
+
+ while (iter.hasNext()) {
+ ChunkHandler handler = (ChunkHandler) iter.next();
+ switch (event) {
+ case CONNECTED:
+ handler.connected();
+ break;
+ case DISCONNECTED:
+ handler.disconnected();
+ break;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+ }
+
+ /*
+ * This is called by the VM when a chunk arrives.
+ *
+ * For a DDM-aware application, we want to wait until the app has had
+ * a chance to register all of its chunk handlers. Otherwise, we'll
+ * end up dropping early-arriving packets on the floor.
+ *
+ * For a non-DDM-aware application, we'll end up waiting here forever
+ * if DDMS happens to connect. It's hard to know for sure that
+ * registration isn't going to happen, so we settle for a timeout.
+ */
+ private static Chunk dispatch(int type, byte[] data, int offset, int length)
+ {
+ ChunkHandler handler;
+
+ synchronized (mHandlerMap) {
+ /*
+ * If registration hasn't completed, and we haven't timed out
+ * waiting for it, wait a bit.
+ */
+ while (!mRegistrationComplete && !mRegistrationTimedOut) {
+ //System.out.println("dispatch() waiting for reg");
+ try {
+ mHandlerMap.wait(1000); // 1.0 sec
+ } catch (InterruptedException ie) {
+ continue;
+ }
+
+ if (!mRegistrationComplete) {
+ /* timed out, don't wait again */
+ System.out.println("DDM dispatch reg wait timeout");
+ mRegistrationTimedOut = true;
+ }
+ }
+
+ handler = mHandlerMap.get(type);
+ }
+ //System.out.println(" dispatch cont");
+
+ if (handler == null) {
+ System.err.println("Can't dispatch DDM chunk "
+ + Integer.toHexString(type) + ": no handler defined");
+ return null;
+ }
+
+ Chunk chunk = new Chunk(type, data, offset, length);
+ return handler.handleChunk(chunk);
+ }
+}
+
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
new file mode 100644
index 0000000..01293b0
--- /dev/null
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/DdmVmInternal.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.harmony.dalvik.ddmc;
+
+/**
+ * Declarations for some VM-internal DDM stuff.
+ */
+public class DdmVmInternal {
+
+ /* do not instantiate */
+ private DdmVmInternal() {}
+
+ /**
+ * Enable thread notification.
+ *
+ * This is built into the VM, since that's where threads get managed.
+ */
+ native public static void threadNotify(boolean enable);
+
+ /**
+ * Enable heap info updates.
+ *
+ * This is built into the VM, since that's where the heap is managed.
+ *
+ * @param when when to send the next HPIF chunk
+ * @return true on success. false if 'when' is bad or if there was
+ * an internal error.
+ */
+ native public static boolean heapInfoNotify(int when);
+
+ /**
+ * Enable heap segment updates for the java (isNative == false) or
+ * native (isNative == true) heap.
+ *
+ * This is built into the VM, since that's where the heap is managed.
+ */
+ native public static boolean heapSegmentNotify(int when, int what,
+ boolean isNative);
+
+ /**
+ * Get status info for all threads. This is for the THST chunk.
+ *
+ * Returns a byte array with the THST data, or null if something
+ * went wrong.
+ */
+ native public static byte[] getThreadStats();
+
+ /**
+ * Get a stack trace for the specified thread ID. The ID can be found
+ * in the data from getThreadStats.
+ */
+ native public static StackTraceElement[] getStackTraceById(int threadId);
+
+ /**
+ * Enable or disable "recent allocation" tracking.
+ */
+ native public static void enableRecentAllocations(boolean enable);
+
+ /*
+ * Return a boolean indicating whether or not the "recent allocation"
+ * feature is currently enabled.
+ */
+ native public static boolean getRecentAllocationStatus();
+
+ /**
+ * Fill a buffer with data on recent heap allocations.
+ */
+ native public static byte[] getRecentAllocations();
+}
+
diff --git a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/README.txt b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/README.txt
new file mode 100644
index 0000000..99def80
--- /dev/null
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/README.txt
@@ -0,0 +1 @@
+These classes are tied to the VM, e.g. the VM may invoke some of the methods.
diff --git a/dalvik/src/main/native/dalvik_system_TouchDex.cpp b/dalvik/src/main/native/dalvik_system_TouchDex.cpp
new file mode 100644
index 0000000..e8b834b
--- /dev/null
+++ b/dalvik/src/main/native/dalvik_system_TouchDex.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Bit of code to wrap DEX force-updating with a fork() call.
+ */
+
+#define LOG_TAG "TouchDex"
+#include "JNIHelp.h"
+
+#include "cutils/properties.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <assert.h>
+#include <errno.h>
+
+#define JAVA_PACKAGE "dalvik/system"
+
+#ifndef HAVE_ANDROID_OS
+# define BASE_DIR "/work/device/out/linux-x86-debug-sim"
+#else
+# define BASE_DIR ""
+#endif
+
+namespace android {
+
+// fwd
+static void logProcStatus(pid_t pid);
+
+
+/*
+ * private static int trampoline(String dexFiles, String bcp)
+ */
+static jint dalvik_system_TouchDex_trampoline(JNIEnv* env,
+ jclass clazz, jstring dexFilesStr, jstring bcpStr)
+{
+#ifndef HAVE_ANDROID_OS
+ /* don't do this on simulator -- gdb goes "funny" in goobuntu */
+ return 0;
+#endif
+
+ const int kMinTimeout = 900; // 90 seconds
+ const char* bcp;
+ const char* dexFiles;
+ static const char* kExecFile = BASE_DIR "/system/bin/dalvikvm";
+ //static const char* kDebugArg =
+ // "-Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n";
+ static const char* kBcpArgName = "-Xbootclasspath:";
+ static const char* kClassName = "dalvik.system.TouchDex";
+ static const char* kExecMode = "-Xint";
+ static const int argc = 7;
+ char* bcpArg;
+ const char* argv[argc+1];
+ const char* kVerifyArg;
+ const char* kDexOptArg;
+ int timeoutMult;
+ pid_t pid;
+ struct timeval startWhen, endWhen;
+ char propBuf[PROPERTY_VALUE_MAX];
+ char execModeBuf[PROPERTY_VALUE_MAX + sizeof("-X")];
+ bool verifyJava = true;
+
+ property_get("dalvik.vm.verify-bytecode", propBuf, "");
+ if (strcmp(propBuf, "true") == 0) {
+ verifyJava = true;
+ } else if (strcmp(propBuf, "false") == 0) {
+ verifyJava = false;
+ } else {
+ /* bad value or not defined; use default */
+ }
+
+ if (verifyJava) {
+ kVerifyArg = "-Xverify:all";
+ kDexOptArg = "-Xdexopt:verified";
+ timeoutMult = 11;
+ } else {
+ kVerifyArg = "-Xverify:none";
+ //kDexOptArg = "-Xdexopt:all";
+ kDexOptArg = "-Xdexopt:verified";
+ timeoutMult = 7;
+ }
+
+ property_get("dalvik.vm.execution-mode", propBuf, "");
+ if (strncmp(propBuf, "int:", 4) == 0) {
+ strcpy(execModeBuf, "-X");
+ strcat(execModeBuf, propBuf);
+ kExecMode = execModeBuf;
+ }
+
+ LOGV("TouchDex trampoline forking\n");
+ gettimeofday(&startWhen, NULL);
+
+ /*
+ * Retrieve strings. Note we want to do this *before* the fork() -- bad
+ * idea to perform Java operations in the child process (not all threads
+ * get carried over to the new process).
+ */
+ bcp = env->GetStringUTFChars(bcpStr, NULL);
+ dexFiles = env->GetStringUTFChars(dexFilesStr, NULL);
+ if (bcp == NULL || dexFiles == NULL) {
+ LOGE("Bad values for bcp=%p dexFiles=%p\n", bcp, dexFiles);
+ abort();
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ LOGE("fork failed: %s", strerror(errno));
+ return -1;
+ }
+
+ if (pid == 0) {
+ /* child */
+ char* bcpArg;
+
+ LOGV("TouchDex trampoline in child\n");
+
+ bcpArg = (char*) malloc(strlen(bcp) + strlen(kBcpArgName) +1);
+ strcpy(bcpArg, kBcpArgName);
+ strcat(bcpArg, bcp);
+
+ argv[0] = kExecFile;
+ argv[1] = bcpArg;
+ argv[2] = kVerifyArg;
+ argv[3] = kDexOptArg;
+ argv[4] = kExecMode;
+ argv[5] = kClassName;
+ argv[6] = dexFiles;
+ argv[7] = NULL;
+
+ //LOGI("Calling execv with args:\n");
+ //for (int i = 0; i < argc; i++)
+ // LOGI(" %d: '%s'\n", i, argv[i]);
+
+ execv(kExecFile, (char* const*) argv);
+ free(bcpArg);
+
+ LOGE("execv '%s' failed: %s\n", kExecFile, strerror(errno));
+ exit(1);
+ } else {
+ int cc, count, dexCount, timeout;
+ int result = -1;
+ const char* cp;
+
+ /*
+ * Adjust the timeout based on how many DEX files we have to
+ * process. Larger DEX files take longer, so this is a crude
+ * approximation at best.
+ *
+ * We need this for http://b/issue?id=836771, which can leave us
+ * stuck waiting for a long time even if there is no work to be done.
+ *
+ * This is currently being (ab)used to convert single files, which
+ * sort of spoils the timeout calculation. We establish a minimum
+ * timeout for single apps.
+ *
+ * The timeout calculation doesn't work at all right when a
+ * directory is specified. So the minimum is now a minute. At
+ * this point it's probably safe to just remove the timeout.
+ *
+ * The timeout is in 1/10ths of a second.
+ */
+ dexCount = 1;
+ cp = dexFiles;
+ while (*++cp != '\0') {
+ if (*cp == ':')
+ dexCount++;
+ }
+ timeout = timeoutMult * dexCount;
+ if (timeout < kMinTimeout)
+ timeout = kMinTimeout;
+
+ env->ReleaseStringUTFChars(bcpStr, bcp);
+ env->ReleaseStringUTFChars(dexFilesStr, dexFiles);
+
+
+ LOGD("TouchDex parent waiting for pid=%d (timeout=%.1fs)\n",
+ (int) pid, timeout / 10.0);
+ for (count = 0; count < timeout; count++) {
+ /* waitpid doesn't take a timeout, so poll and sleep */
+ cc = waitpid(pid, &result, WNOHANG);
+ if (cc < 0) {
+ LOGE("waitpid(%d) failed: %s", (int) pid, strerror(errno));
+ return -1;
+ } else if (cc == 0) {
+ usleep(100000); /* 0.1 sec */
+ } else {
+ /* success! */
+ break;
+ }
+ }
+
+ if (count == timeout) {
+ /* note kill(0) returns 0 if the pid is a zombie */
+ LOGE("timed out waiting for %d; kill(0) returns %d\n",
+ (int) pid, kill(pid, 0));
+ logProcStatus(pid);
+ } else {
+ LOGV("TouchDex done after %d iterations (kill(0) returns %d)\n",
+ count, kill(pid, 0));
+ }
+
+ gettimeofday(&endWhen, NULL);
+ long long start = startWhen.tv_sec * 1000000 + startWhen.tv_usec;
+ long long end = endWhen.tv_sec * 1000000 + endWhen.tv_usec;
+
+ LOGI("Dalvik-cache prep: status=0x%04x, finished in %dms\n",
+ result, (int) ((end - start) / 1000));
+
+ if (WIFEXITED(result))
+ return WEXITSTATUS(result);
+ else
+ return result;
+ }
+}
+
+/*
+ * Dump the contents of /proc/<pid>/status to the log file.
+ */
+static void logProcStatus(pid_t pid)
+{
+ char localBuf[256];
+ FILE* fp;
+
+ sprintf(localBuf, "/proc/%d/status", (int) pid);
+ fp = fopen(localBuf, "r");
+ if (fp == NULL) {
+ LOGI("Unable to open '%s'\n", localBuf);
+ return;
+ }
+
+ LOGI("Contents of %s:\n", localBuf);
+ while (true) {
+ fgets(localBuf, sizeof(localBuf), fp);
+ if (ferror(fp) || feof(fp))
+ break;
+ LOGI(" %s", localBuf);
+ }
+
+ fclose(fp);
+}
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "trampoline", "(Ljava/lang/String;Ljava/lang/String;)I",
+ (void*) dalvik_system_TouchDex_trampoline },
+};
+
+extern "C" int register_dalvik_system_TouchDex(JNIEnv* env)
+{
+ return jniRegisterNativeMethods(env, JAVA_PACKAGE "/TouchDex",
+ gMethods, NELEM(gMethods));
+}
+
+}; // namespace android
+
diff --git a/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.c b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.c
new file mode 100644
index 0000000..25235dc
--- /dev/null
+++ b/dalvik/src/main/native/org_apache_harmony_dalvik_NativeTestTarget.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JNIHelp.h"
+
+/*
+ * public static void emptyJniStaticMethod0()
+ *
+ * For benchmarks, a do-nothing JNI method with no arguments.
+ */
+static void emptyJniStaticMethod0(JNIEnv* env, jclass clazz)
+{
+ // This space intentionally left blank.
+}
+
+/*
+ * public static void emptyJniStaticMethod6(int a, int b, int c,
+ * int d, int e, int f)
+ *
+ * For benchmarks, a do-nothing JNI method with six arguments.
+ */
+static void emptyJniStaticMethod6(JNIEnv* env, jclass clazz,
+ int a, int b, int c, int d, int e, int f)
+{
+ // This space intentionally left blank.
+}
+
+/*
+ * public static void emptyJniStaticMethod6L(String a, String[] b,
+ * int[][] c, Object d, Object[] e, Object[][][][] f)
+ *
+ * For benchmarks, a do-nothing JNI method with six arguments.
+ */
+static void emptyJniStaticMethod6L(JNIEnv* env, jclass clazz,
+ jobject a, jarray b, jarray c, jobject d, jarray e, jarray f)
+{
+ // This space intentionally left blank.
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gMethods[] = {
+ /* name, signature, funcPtr */
+ { "emptyJniStaticMethod0", "()V", emptyJniStaticMethod0 },
+ { "emptyJniStaticMethod6", "(IIIIII)V", emptyJniStaticMethod6 },
+ { "emptyJniStaticMethod6L",
+ "(Ljava/lang/String;[Ljava/lang/String;[[I"
+ "Ljava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V",
+ emptyJniStaticMethod6L },
+};
+
+int register_org_apache_harmony_dalvik_NativeTestTarget(JNIEnv* env)
+{
+ int result = jniRegisterNativeMethods(env,
+ "org/apache/harmony/dalvik/NativeTestTarget",
+ gMethods, NELEM(gMethods));
+ if (result != 0) {
+ /* print warning, but allow to continue */
+ LOGW("WARNING: NativeTestTarget not registered\n");
+ (*env)->ExceptionClear(env);
+ }
+ return 0;
+}
+
diff --git a/dalvik/src/main/native/sub.mk b/dalvik/src/main/native/sub.mk
new file mode 100644
index 0000000..67cca39
--- /dev/null
+++ b/dalvik/src/main/native/sub.mk
@@ -0,0 +1,18 @@
+# This file is included by the top-level libcore Android.mk.
+# It's not a normal makefile, so we don't include CLEAR_VARS
+# or BUILD_*_LIBRARY.
+
+LOCAL_SRC_FILES := \
+ dalvik_system_TouchDex.cpp \
+ org_apache_harmony_dalvik_NativeTestTarget.c
+
+#LOCAL_C_INCLUDES +=
+
+# Any shared/static libs that are listed here must also
+# be listed in libs/nativehelper/Android.mk.
+# TODO: fix this requirement
+
+#LOCAL_SHARED_LIBRARIES +=
+
+#LOCAL_STATIC_LIBRARIES +=
+