diff options
Diffstat (limited to 'dalvik')
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 <= 0.0 or >= 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 <size> 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 <size> 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 += + |