summaryrefslogtreecommitdiffstats
path: root/dalvik
diff options
context:
space:
mode:
Diffstat (limited to 'dalvik')
-rw-r--r--dalvik/src/main/java/dalvik/annotation/HostController.java37
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestInfo.java63
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestStatus.java44
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestTarget.java3
-rw-r--r--dalvik/src/main/java/dalvik/annotation/TestTargetClass.java3
-rw-r--r--dalvik/src/main/java/dalvik/annotation/Timeout.java40
-rw-r--r--dalvik/src/main/java/dalvik/annotation/VirtualTestTarget.java57
-rw-r--r--dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java2
-rw-r--r--dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java128
-rw-r--r--dalvik/src/main/java/dalvik/system/BlockGuard.java121
-rw-r--r--dalvik/src/main/java/dalvik/system/CloseGuard.java9
-rw-r--r--dalvik/src/main/java/dalvik/system/DexClassLoader.java334
-rw-r--r--dalvik/src/main/java/dalvik/system/DexFile.java21
-rw-r--r--dalvik/src/main/java/dalvik/system/DexPathList.java422
-rw-r--r--dalvik/src/main/java/dalvik/system/NativeStart.java5
-rw-r--r--dalvik/src/main/java/dalvik/system/PathClassLoader.java439
-rw-r--r--dalvik/src/main/java/dalvik/system/TemporaryDirectory.java4
-rw-r--r--dalvik/src/main/java/dalvik/system/TouchDex.java147
-rw-r--r--dalvik/src/main/java/dalvik/system/TouchDexLoader.java315
-rw-r--r--dalvik/src/main/java/dalvik/system/VMRuntime.java38
-rw-r--r--dalvik/src/main/java/dalvik/system/VMStack.java12
-rw-r--r--dalvik/src/main/java/dalvik/system/Zygote.java48
-rw-r--r--dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java21
-rw-r--r--dalvik/src/main/native/dalvik_system_TouchDex.cpp269
-rw-r--r--dalvik/src/main/native/sub.mk3
25 files changed, 691 insertions, 1894 deletions
diff --git a/dalvik/src/main/java/dalvik/annotation/HostController.java b/dalvik/src/main/java/dalvik/annotation/HostController.java
deleted file mode 100644
index 749dc62..0000000
--- a/dalvik/src/main/java/dalvik/annotation/HostController.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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;
-
-/**
- * Record the host side controller information for a test method,
- * so that the CTS host can locate correspond host side unit while running it.
- * {@hide pending API Council approval}
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.METHOD })
-public @interface HostController {
-
- /**
- * The host controller method name.
- */
- String name() default "";
-}
diff --git a/dalvik/src/main/java/dalvik/annotation/TestInfo.java b/dalvik/src/main/java/dalvik/annotation/TestInfo.java
deleted file mode 100644
index 4126fcc..0000000
--- a/dalvik/src/main/java/dalvik/annotation/TestInfo.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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 the current level of coverage the test has.
- */
- TestLevel level() default TestLevel.PARTIAL;
-
- /**
- * Specifies the purpose (either if it is noteworth to mention such as if
- * it is testing a specific parameter combination) or the covered test
- * aspects (exceptions, normal cases, border edge cases, etc.) in
- * case the level is Level.PARTIAL
- */
- String purpose() 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
deleted file mode 100644
index fc7a920..0000000
--- a/dalvik/src/main/java/dalvik/annotation/TestStatus.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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
index 158698d..dcfd20c 100644
--- a/dalvik/src/main/java/dalvik/annotation/TestTarget.java
+++ b/dalvik/src/main/java/dalvik/annotation/TestTarget.java
@@ -25,9 +25,12 @@ 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).
+ *
+ * @deprecated Obsolete
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.ANNOTATION_TYPE })
+@Deprecated
public @interface TestTarget {
/**
diff --git a/dalvik/src/main/java/dalvik/annotation/TestTargetClass.java b/dalvik/src/main/java/dalvik/annotation/TestTargetClass.java
index 9144a41..e88040e 100644
--- a/dalvik/src/main/java/dalvik/annotation/TestTargetClass.java
+++ b/dalvik/src/main/java/dalvik/annotation/TestTargetClass.java
@@ -26,9 +26,12 @@ import java.lang.annotation.Target;
* 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.
+ *
+ * @deprecated Obsolete
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
+@Deprecated
public @interface TestTargetClass {
/**
diff --git a/dalvik/src/main/java/dalvik/annotation/Timeout.java b/dalvik/src/main/java/dalvik/annotation/Timeout.java
deleted file mode 100644
index 1a779ac..0000000
--- a/dalvik/src/main/java/dalvik/annotation/Timeout.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2009 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 to be used for specifying a test timeout. A test
- * harness that supports timeouts should allow a test to be run for at least
- * this time before killing it. Time is measured in seconds.
- *
- * @hide
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.ANNOTATION_TYPE, ElementType.METHOD })
-public @interface Timeout {
-
- /**
- * Specifies the test timeout in seconds.
- */
- int value();
-
-}
diff --git a/dalvik/src/main/java/dalvik/annotation/VirtualTestTarget.java b/dalvik/src/main/java/dalvik/annotation/VirtualTestTarget.java
deleted file mode 100644
index 5e57f1c..0000000
--- a/dalvik/src/main/java/dalvik/annotation/VirtualTestTarget.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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;
-
-/**
- * Annotation for "virtual" implementation classes. These are classes that have
- * the following attributes:
- * <ul>
- * <li>they implement a public interface or are a concrete implementation of a
- * public abstract class,</li>
- * <li>they are not public,</li>
- * <li>instances can only be retrieved through some kind of factory method.</li>
- * </ul>
- * <p>
- * Example: {@code MessageDigest} is an abstract class. Concrete implementations
- * of message digest algorithms such as MD5 and SHA-1 can only be retrieved
- * through one of the static {@code getInstance} methods of
- * {@code MessageDigest}, which accept the desired algorithm as a string
- * parameter and return an implementation accordingly.
- * </p>
- * <p>
- * Even though the concrete implementation class for a message digest algorithm
- * is not known, we need to be able to indicate that such a class exists and
- * that it must be tested. This is done by defining corresponding classes and
- * annotating them with {@code @VirtualTestTarget}. This class can then be
- * used in the {@code @TestTargetClass} annotation with which we annotate
- * {@code TestCase} subclasses.
- * @hide
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ ElementType.TYPE })
-public @interface VirtualTestTarget {
-
- /**
- * Field for comments.
- */
- String value() default "";
-}
diff --git a/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java b/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java
index 1209b2e..f253ee7 100644
--- a/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java
+++ b/dalvik/src/main/java/dalvik/bytecode/OpcodeInfo.java
@@ -55,7 +55,7 @@ public final class OpcodeInfo {
*/
// BEGIN(libcore-maximum-values); GENERATED AUTOMATICALLY BY opcode-gen
MAXIMUM_VALUE = 65535;
- MAXIMUM_PACKED_VALUE = 255;
+ MAXIMUM_PACKED_VALUE = 511;
// END(libcore-maximum-values)
}
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
new file mode 100644
index 0000000..ab24f0b
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2011 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.net.URL;
+import java.util.Enumeration;
+
+/**
+ * Base class for common functionality between various dex-based
+ * {@link ClassLoader} implementations.
+ */
+public class BaseDexClassLoader extends ClassLoader {
+ /** originally specified path (just used for {@code toString()}) */
+ private final String originalPath;
+
+ /** structured lists of path elements */
+ private final DexPathList pathList;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param dexPath the list of jar/apk files containing classes and
+ * resources, delimited by {@code File.pathSeparator}, which
+ * defaults to {@code ":"} on Android
+ * @param optimizedDirectory directory where optimized dex files
+ * should be written; may be {@code null}
+ * @param libraryPath the list of directories containing native
+ * libraries, delimited by {@code File.pathSeparator}; may be
+ * {@code null}
+ * @param parent the parent class loader
+ */
+ public BaseDexClassLoader(String dexPath, File optimizedDirectory,
+ String libraryPath, ClassLoader parent) {
+ super(parent);
+
+ this.originalPath = dexPath;
+ this.pathList =
+ new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ Class clazz = pathList.findClass(name);
+
+ if (clazz == null) {
+ throw new ClassNotFoundException(name);
+ }
+
+ return clazz;
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ return pathList.findResource(name);
+ }
+
+ @Override
+ protected Enumeration<URL> findResources(String name) {
+ return pathList.findResources(name);
+ }
+
+ @Override
+ public String findLibrary(String name) {
+ return pathList.findLibrary(name);
+ }
+
+ /**
+ * Returns package information for the given package.
+ * Unfortunately, instances of this class don't really have this
+ * information, and as a non-secure {@code 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()} happy. Thus we construct
+ * a {@code Package} object the first time it is being requested
+ * and fill most of the fields with dummy values. The {@code
+ * Package} object is then put into the {@code ClassLoader}'s
+ * package cache, so we see the same one next time. We don't
+ * create {@code Package} objects for {@code null} arguments or
+ * for the default package.
+ *
+ * <p>There is a limited chance that we end up with multiple
+ * {@code Package} objects representing the same package: It can
+ * happen when when a package is scattered across different JAR
+ * files which were loaded by different {@code ClassLoader}
+ * instances. This is rather unlikely, and given that this whole
+ * thing is more or less a workaround, probably not worth the
+ * effort to address.
+ *
+ * @param name the name of the class
+ * @return the package information for the class, or {@code null}
+ * if there is no package information available for it
+ */
+ @Override
+ protected synchronized Package getPackage(String name) {
+ if (name != null && !name.isEmpty()) {
+ Package pack = super.getPackage(name);
+
+ if (pack == null) {
+ pack = definePackage(name, "Unknown", "0.0", "Unknown",
+ "Unknown", "0.0", "Unknown", null);
+ }
+
+ return pack;
+ }
+
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + "[" + originalPath + "]";
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/BlockGuard.java b/dalvik/src/main/java/dalvik/system/BlockGuard.java
index 6d67fe5..56abeb8 100644
--- a/dalvik/src/main/java/dalvik/system/BlockGuard.java
+++ b/dalvik/src/main/java/dalvik/system/BlockGuard.java
@@ -24,7 +24,6 @@ import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketImpl;
import java.net.SocketOptions;
-import org.apache.harmony.luni.platform.IFileSystem;
import org.apache.harmony.luni.platform.INetworkSystem;
/**
@@ -115,7 +114,7 @@ public final class BlockGuard {
/**
* The default, permissive policy that doesn't prevent any operations.
*/
- public static Policy LAX_POLICY = new Policy() {
+ public static final Policy LAX_POLICY = new Policy() {
public void onWriteToDisk() {}
public void onReadFromDisk() {}
public void onNetwork() {}
@@ -156,104 +155,6 @@ public final class BlockGuard {
private BlockGuard() {}
/**
- * A filesystem wrapper that calls the policy check functions
- * on reads and writes.
- */
- public static class WrappedFileSystem implements IFileSystem {
- private final IFileSystem mFileSystem;
-
- public WrappedFileSystem(IFileSystem fileSystem) {
- mFileSystem = fileSystem;
- }
-
- public long read(int fileDescriptor, byte[] bytes, int offset, int length)
- throws IOException {
- BlockGuard.getThreadPolicy().onReadFromDisk();
- return mFileSystem.read(fileDescriptor, bytes, offset, length);
- }
-
- public long write(int fileDescriptor, byte[] bytes, int offset, int length)
- throws IOException {
- BlockGuard.getThreadPolicy().onWriteToDisk();
- return mFileSystem.write(fileDescriptor, bytes, offset, length);
- }
-
- public long readv(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- BlockGuard.getThreadPolicy().onReadFromDisk();
- return mFileSystem.readv(fileDescriptor, addresses, offsets, lengths, size);
- }
-
- public long writev(int fileDescriptor, int[] addresses, int[] offsets,
- int[] lengths, int size) throws IOException {
- BlockGuard.getThreadPolicy().onWriteToDisk();
- return mFileSystem.writev(fileDescriptor, addresses, offsets, lengths, size);
- }
-
- public long readDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- BlockGuard.getThreadPolicy().onReadFromDisk();
- return mFileSystem.readDirect(fileDescriptor, address, offset, length);
- }
-
- public long writeDirect(int fileDescriptor, int address, int offset,
- int length) throws IOException {
- BlockGuard.getThreadPolicy().onWriteToDisk();
- return mFileSystem.writeDirect(fileDescriptor, address, offset, length);
- }
-
- public boolean lock(int fileDescriptor, long start, long length, int type,
- boolean waitFlag) throws IOException {
- return mFileSystem.lock(fileDescriptor, start, length, type, waitFlag);
- }
-
- public void unlock(int fileDescriptor, long start, long length)
- throws IOException {
- mFileSystem.unlock(fileDescriptor, start, length);
- }
-
- public long seek(int fileDescriptor, long offset, int whence)
- throws IOException {
- return mFileSystem.seek(fileDescriptor, offset, whence);
- }
-
- public void fsync(int fileDescriptor, boolean metadata) throws IOException {
- BlockGuard.getThreadPolicy().onWriteToDisk();
- mFileSystem.fsync(fileDescriptor, metadata);
- }
-
- public void truncate(int fileDescriptor, long size) throws IOException {
- BlockGuard.getThreadPolicy().onWriteToDisk();
- mFileSystem.truncate(fileDescriptor, size);
- }
-
- public int getAllocGranularity() {
- return mFileSystem.getAllocGranularity();
- }
-
- public int open(String path, int mode) throws FileNotFoundException {
- BlockGuard.getThreadPolicy().onReadFromDisk();
- if (mode != 0) { // 0 is read-only
- BlockGuard.getThreadPolicy().onWriteToDisk();
- }
- return mFileSystem.open(path, mode);
- }
-
- public long transfer(int fileHandler, FileDescriptor socketDescriptor,
- long offset, long count) throws IOException {
- return mFileSystem.transfer(fileHandler, socketDescriptor, offset, count);
- }
-
- public int ioctlAvailable(FileDescriptor fileDescriptor) throws IOException {
- return mFileSystem.ioctlAvailable(fileDescriptor);
- }
-
- public long length(int fd) {
- return mFileSystem.length(fd);
- }
- }
-
- /**
* A network wrapper that calls the policy check functions.
*/
public static class WrappedNetworkSystem implements INetworkSystem {
@@ -343,26 +244,10 @@ public final class BlockGuard {
mNetwork.disconnectDatagram(aFD);
}
- public void socket(FileDescriptor aFD, boolean stream) throws SocketException {
- mNetwork.socket(aFD, stream);
- }
-
- public void shutdownInput(FileDescriptor descriptor) throws IOException {
- mNetwork.shutdownInput(descriptor);
- }
-
- public void shutdownOutput(FileDescriptor descriptor) throws IOException {
- mNetwork.shutdownOutput(descriptor);
- }
-
public void sendUrgentData(FileDescriptor fd, byte value) {
mNetwork.sendUrgentData(fd, value);
}
- public void listen(FileDescriptor aFD, int backlog) throws SocketException {
- mNetwork.listen(aFD, backlog);
- }
-
public void connect(FileDescriptor aFD, InetAddress inetAddress, int port,
int timeout) throws SocketException {
BlockGuard.getThreadPolicy().onNetwork();
@@ -404,10 +289,6 @@ public final class BlockGuard {
mNetwork.close(aFD);
}
- public void setInetAddress(InetAddress sender, byte[] address) {
- mNetwork.setInetAddress(sender, address);
- }
-
private boolean isLingerSocket(FileDescriptor fd) throws SocketException {
try {
Object lingerValue = mNetwork.getSocketOption(fd, SocketOptions.SO_LINGER);
diff --git a/dalvik/src/main/java/dalvik/system/CloseGuard.java b/dalvik/src/main/java/dalvik/system/CloseGuard.java
index b631852..136be2f 100644
--- a/dalvik/src/main/java/dalvik/system/CloseGuard.java
+++ b/dalvik/src/main/java/dalvik/system/CloseGuard.java
@@ -16,9 +16,6 @@
package dalvik.system;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
/**
* CloseGuard is a mechanism for flagging implicit finalizer cleanup of
* resources that should have been cleaned up by explicit close
@@ -223,13 +220,11 @@ public final class CloseGuard {
}
/**
- * Default Reporter which uses a Logger to report CloseGuard
- * violations.
+ * Default Reporter which reports CloseGuard violations to the log.
*/
private static final class DefaultReporter implements Reporter {
public void report (String message, Throwable allocationSite) {
- Logger.getLogger(CloseGuard.class.getName())
- .log(Level.WARNING, message, allocationSite);
+ System.logW(message, allocationSite);
}
}
}
diff --git a/dalvik/src/main/java/dalvik/system/DexClassLoader.java b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
index fea65dd..e059b7d 100644
--- a/dalvik/src/main/java/dalvik/system/DexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/DexClassLoader.java
@@ -17,10 +17,6 @@
package dalvik.system;
import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.zip.ZipFile;
/**
* Provides a simple {@link ClassLoader} implementation that operates on a
@@ -28,323 +24,29 @@ import java.util.zip.ZipFile;
* holds the optimized form of the files is specified explicitly. This
* can be used to execute code not installed as part of an application.
*
- * The best place to put the optimized DEX files is in app-specific
+ * The best place to put the optimized dex files is in app-specific
* storage, so that removal of the app will automatically remove the
- * optimized DEX files. If other storage is used (e.g. /sdcard), the
+ * optimized dex files. If other storage is used (e.g. /sdcard), the
* app may not have an opportunity to remove them.
*/
-public class DexClassLoader extends ClassLoader {
- // TODO: Factor out commonality between this class and PathClassLoader.
-
- private static final boolean VERBOSE_DEBUG = false;
-
- /* constructor args, held for init */
- private final String mRawDexPath;
- private final String mRawLibPath;
- private final String mDexOutputPath;
-
- /*
- * Parallel arrays for jar/apk files.
- *
- * (could stuff these into an object and have a single array;
- * improves clarity but adds overhead)
- */
- private final File[] mFiles; // source file Files, for rsrc URLs
- private final ZipFile[] mZips; // source zip files, with resources
- private final DexFile[] mDexs; // opened, prepped DEX files
-
- /**
- * Native library path.
- */
- private final String[] mLibPaths;
-
+public class DexClassLoader extends BaseDexClassLoader {
/**
* Creates a {@code DexClassLoader} that finds interpreted and native
- * code. Interpreted classes are found in a set of DEX files contained
- * in Jar or APK files.
- *
- * The path lists are separated using the character specified by
- * the "path.separator" system property, which defaults to ":".
+ * code. Interpreted classes are found in a set of dex files contained
+ * in jar or apk files.
*
- * @param dexPath
- * the list of jar/apk files containing classes and resources
- * @param dexOutputDir
- * directory where optimized DEX files should be written
- * @param libPath
- * the list of directories containing native libraries; may be null
- * @param parent
- * the parent class loader
- */
- public DexClassLoader(String dexPath, String dexOutputDir, String libPath,
- ClassLoader parent) {
- super(parent);
-
- if (dexPath == null || dexOutputDir == null) {
- throw new NullPointerException();
- }
-
- mRawDexPath = dexPath;
- mDexOutputPath = dexOutputDir;
- mRawLibPath = libPath;
-
- String[] dexPathList = mRawDexPath.split(":");
- int length = dexPathList.length;
-
- mFiles = new File[length];
- mZips = new ZipFile[length];
- mDexs = new DexFile[length];
-
- /* open all Zip and DEX files up front */
- for (int i = 0; i < length; i++) {
- File pathFile = new File(dexPathList[i]);
- mFiles[i] = pathFile;
-
- if (pathFile.isFile()) {
- if (!dexPathList[i].endsWith(".dex")) {
- /*
- * If the name doesn't end with ".dex" assume it's a zip
- * file of some sort.
- */
- try {
- mZips[i] = new ZipFile(pathFile);
- }
- catch (IOException ioex) {
- // expecting IOException and ZipException
- //System.out.println("Failed opening '" + pathFile
- // + "': " + ioex);
- //ioex.printStackTrace();
- }
- }
-
- /*
- * If we got a zip file, we still need to extract out
- * the dex file from it.
- */
- try {
- String outputName =
- generateOutputName(dexPathList[i], mDexOutputPath);
- mDexs[i] = DexFile.loadDex(dexPathList[i], outputName, 0);
- } catch (IOException ioex) {
- // It might be a resource-only zip.
- //System.out.println("Failed to construct DexFile '"
- // + pathFile + "': " + 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 (mRawLibPath != null) {
- if (pathList.length() > 0) {
- pathList += pathSep + mRawLibPath;
- }
- else {
- pathList = mRawLibPath;
- }
- }
-
- 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 (VERBOSE_DEBUG)
- System.out.println("Native lib path " +i+ ": "
- + mLibPaths[i]);
- }
- }
-
- /**
- * Convert a source path name and an output directory to an output
- * file name.
- */
- private static String generateOutputName(String sourcePathName,
- String outputDir) {
- StringBuilder newStr = new StringBuilder(80);
-
- /* start with the output directory */
- newStr.append(outputDir);
- if (!outputDir.endsWith("/"))
- newStr.append("/");
-
- /* get the filename component of the path */
- String sourceFileName;
- int lastSlash = sourcePathName.lastIndexOf("/");
- if (lastSlash < 0)
- sourceFileName = sourcePathName;
- else
- sourceFileName = sourcePathName.substring(lastSlash+1);
-
- /*
- * Replace ".jar", ".zip", whatever with ".dex". We don't want to
- * use ".odex", because the build system uses that for files that
- * are paired with resource-only jar files. If the VM can assume
- * that there's no classes.dex in the matching jar, it doesn't need
- * to open the jar to check for updated dependencies, providing a
- * slight performance boost at startup. The use of ".dex" here
- * matches the use on files in /data/dalvik-cache.
- */
- int lastDot = sourceFileName.lastIndexOf(".");
- if (lastDot < 0)
- newStr.append(sourceFileName);
- else
- newStr.append(sourceFileName, 0, lastDot);
- newStr.append(".dex");
-
- if (VERBOSE_DEBUG)
- System.out.println("Output file will be " + newStr.toString());
- return newStr.toString();
- }
-
- /**
- * Finds a class. This method is called by {@code loadClass()} after the
- * parent ClassLoader has failed to find a loaded class of the same name.
- *
- * @param name
- * The name of the class to search for, in a human-readable form
- * like "java.lang.String" or "java.net.URLClassLoader$3$1".
- * @return the {@link Class} object representing the class
- * @throws ClassNotFoundException
- * if the class cannot be found
- */
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- if (VERBOSE_DEBUG)
- System.out.println("DexClassLoader " + this
- + ": findClass '" + name + "'");
-
- int length = mFiles.length;
-
- for (int i = 0; i < length; i++) {
- if (VERBOSE_DEBUG)
- System.out.println(" Now searching: " + mFiles[i].getPath());
-
- if (mDexs[i] != null) {
- String slashName = name.replace('.', '/');
- Class clazz = mDexs[i].loadClass(slashName, this);
- if (clazz != null) {
- if (VERBOSE_DEBUG)
- System.out.println(" found");
- return clazz;
- }
- }
- }
-
- throw new ClassNotFoundException(name + " in loader " + this);
- }
-
- /**
- * Finds a resource. This method is called by {@code getResource()} after
- * the parent ClassLoader has failed to find a loaded resource of the same
- * name.
- *
- * @param name
- * The name of the resource to find
- * @return the location of the resource as a URL, or {@code null} if the
- * resource is not found.
- */
- @Override
- protected URL findResource(String name) {
- int length = mFiles.length;
-
- for (int i = 0; i < length; i++) {
- File pathFile = mFiles[i];
- ZipFile zip = mZips[i];
-
- if (zip.getEntry(name) != null) {
- if (VERBOSE_DEBUG)
- 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);
- }
- }
- }
-
- if (VERBOSE_DEBUG)
- System.out.println(" resource " + name + " not found");
-
- return null;
- }
-
- /**
- * Finds a native library. This method is called after the parent
- * ClassLoader has failed to find a native library of the same name.
- *
- * @param libname
- * The name of the library to find
- * @return the complete path of the library, or {@code null} if the library
- * is not found.
- */
- @Override
- protected String findLibrary(String libname) {
- 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()) {
- if (VERBOSE_DEBUG)
- System.out.println(" found " + libname);
- return pathName;
- }
- }
-
- if (VERBOSE_DEBUG)
- System.out.println(" library " + libname + " not found");
- return null;
- }
-
- /**
- * Returns package information for the given package. Unfortunately, the
- * DexClassLoader 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.
- *
- * @param name
- * the name of the class
- * @return the package information for the class, or {@code null} if there
- * is not package information available for it
- */
- @Override
- protected Package getPackage(String name) {
- if (name != null && !name.isEmpty()) {
- 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;
+ * @param dexPath the list of jar/apk files containing classes and
+ * resources, delimited by {@code File.pathSeparator}, which
+ * defaults to {@code ":"} on Android
+ * @param optimizedDirectory directory where optimized dex files
+ * should be written; must not be {@code null}
+ * @param libraryPath the list of directories containing native
+ * libraries, delimited by {@code File.pathSeparator}; may be
+ * {@code null}
+ * @param parent the parent class loader
+ */
+ public DexClassLoader(String dexPath, String optimizedDirectory,
+ String libraryPath, ClassLoader parent) {
+ super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index 4156f12..dc3e063 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -19,10 +19,8 @@ package dalvik.system;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.security.ProtectionDomain;
import java.util.Enumeration;
-
/**
* Manipulates DEX files. The class is similar in principle to
* {@link java.util.zip.ZipFile}. It is used primarily by class loaders.
@@ -74,10 +72,6 @@ public final class DexFile {
* access rights missing for opening it
*/
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, null, 0);
mFileName = fileName;
guard.open("close");
@@ -95,13 +89,7 @@ public final class DexFile {
* @param flags
* Enable optional features.
*/
- private DexFile(String sourceName, String outputName, int flags)
- throws IOException {
-
- String wantDex = System.getProperty("android.vm.dexfile", "false");
- if (!wantDex.equals("true"))
- throw new UnsupportedOperationException("No dex in this VM");
-
+ private DexFile(String sourceName, String outputName, int flags) throws IOException {
mCookie = openDexFile(sourceName, outputName, flags);
mFileName = sourceName;
guard.open("close");
@@ -204,13 +192,10 @@ public final class DexFile {
* @hide
*/
public Class loadClassBinaryName(String name, ClassLoader loader) {
- return defineClass(name, loader, mCookie,
- null);
- //new ProtectionDomain(name) /*DEBUG ONLY*/);
+ return defineClass(name, loader, mCookie);
}
- native private static Class defineClass(String name, ClassLoader loader,
- int cookie, ProtectionDomain pd);
+ private native static Class defineClass(String name, ClassLoader loader, int cookie);
/**
* Enumerate the names of the classes in this DEX file.
diff --git a/dalvik/src/main/java/dalvik/system/DexPathList.java b/dalvik/src/main/java/dalvik/system/DexPathList.java
new file mode 100644
index 0000000..1253223
--- /dev/null
+++ b/dalvik/src/main/java/dalvik/system/DexPathList.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2011 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.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.regex.Pattern;
+import java.util.zip.ZipFile;
+
+/**
+ * A pair of lists of entries, associated with a {@code ClassLoader}.
+ * One of the lists is a dex/resource path &mdash; typically referred
+ * to as a "class path" &mdash; list, and the other names directories
+ * containing native code libraries. Class path entries may be any of:
+ * a {@code .jar} or {@code .zip} file containing an optional
+ * top-level {@code classes.dex} file as well as arbitrary resources,
+ * or a plain {@code .dex} file (with no possibility of associated
+ * resources).
+ *
+ * <p>This class also contains methods to use these lists to look up
+ * classes and resources.</p>
+ */
+/*package*/ final class DexPathList {
+ private static final String DEX_SUFFIX = ".dex";
+ private static final String JAR_SUFFIX = ".jar";
+ private static final String ZIP_SUFFIX = ".zip";
+ private static final String APK_SUFFIX = ".apk";
+
+ /** class definition context */
+ private final ClassLoader definingContext;
+
+ /** list of dex/resource (class path) elements */
+ private final Element[] dexElements;
+
+ /** list of native library directory elements */
+ private final File[] nativeLibraryDirectories;
+
+ /**
+ * Constructs an instance.
+ *
+ * @param definingContext the context in which any as-yet unresolved
+ * classes should be defined
+ * @param dexPath list of dex/resource path elements, separated by
+ * {@code File.pathSeparator}
+ * @param libraryPath list of native library directory path elements,
+ * separated by {@code File.pathSeparator}
+ * @param optimizedDirectory directory where optimized {@code .dex} files
+ * should be found and written to, or {@code null} to use the default
+ * system directory for same
+ */
+ public DexPathList(ClassLoader definingContext, String dexPath,
+ String libraryPath, File optimizedDirectory) {
+ if (definingContext == null) {
+ throw new NullPointerException("definingContext == null");
+ }
+
+ if (dexPath == null) {
+ throw new NullPointerException("dexPath == null");
+ }
+
+ if (optimizedDirectory != null) {
+ if (!optimizedDirectory.exists()) {
+ throw new IllegalArgumentException(
+ "optimizedDirectory doesn't exist: "
+ + optimizedDirectory);
+ }
+
+ if (!(optimizedDirectory.canRead()
+ && optimizedDirectory.canWrite())) {
+ throw new IllegalArgumentException(
+ "optimizedDirectory not readable/writable: "
+ + optimizedDirectory);
+ }
+ }
+
+ this.definingContext = definingContext;
+ this.dexElements =
+ makeDexElements(splitDexPath(dexPath), optimizedDirectory);
+ this.nativeLibraryDirectories = splitLibraryPath(libraryPath);
+ }
+
+ /**
+ * Splits the given dex path string into elements using the path
+ * separator, pruning out any elements that do not refer to existing
+ * and readable files. (That is, directories are not included in the
+ * result.)
+ */
+ private static ArrayList<File> splitDexPath(String path) {
+ return splitPaths(path, null, false);
+ }
+
+ /**
+ * Splits the given library directory path string into elements
+ * using the path separator ({@code File.pathSeparator}, which
+ * defaults to {@code ":"} on Android, appending on the elements
+ * from the system library path, and pruning out any elements that
+ * do not refer to existing and readable directories.
+ */
+ private static File[] splitLibraryPath(String path) {
+ /*
+ * Native libraries may exist in both the system and
+ * application library paths, and we use this search order:
+ *
+ * 1. this class loader's library path for application
+ * libraries
+ * 2. the VM's library path from the system
+ * property for system libraries
+ *
+ * This order was reversed prior to Gingerbread; see http://b/2933456.
+ */
+ ArrayList<File> result = splitPaths(
+ path, System.getProperty("java.library.path", "."), true);
+ return result.toArray(new File[result.size()]);
+ }
+
+ /**
+ * Splits the given path strings into file elements using the path
+ * separator, combining the results and filtering out elements
+ * that don't exist, aren't readable, or aren't either a regular
+ * file or a directory (as specified). Either string may be empty
+ * or {@code null}, in which case it is ignored. If both strings
+ * are empty or {@code null}, or all elements get pruned out, then
+ * this returns a zero-element list.
+ */
+ private static ArrayList<File> splitPaths(String path1, String path2,
+ boolean wantDirectories) {
+ ArrayList<File> result = new ArrayList<File>();
+
+ splitAndAdd(path1, wantDirectories, result);
+ splitAndAdd(path2, wantDirectories, result);
+ return result;
+ }
+
+ /**
+ * Helper for {@link #splitPaths}, which does the actual splitting
+ * and filtering and adding to a result.
+ */
+ private static void splitAndAdd(String path, boolean wantDirectories,
+ ArrayList<File> resultList) {
+ if (path == null) {
+ return;
+ }
+
+ String[] strings = path.split(Pattern.quote(File.pathSeparator));
+
+ for (String s : strings) {
+ File file = new File(s);
+
+ if (! (file.exists() && file.canRead())) {
+ continue;
+ }
+
+ /*
+ * Note: There are other entities in filesystems than
+ * regular files and directories.
+ */
+ if (wantDirectories) {
+ if (!file.isDirectory()) {
+ continue;
+ }
+ } else {
+ if (!file.isFile()) {
+ continue;
+ }
+ }
+
+ resultList.add(file);
+ }
+ }
+
+ /**
+ * Makes an array of dex/resource path elements, one per element of
+ * the given array.
+ */
+ private static Element[] makeDexElements(ArrayList<File> files,
+ File optimizedDirectory) {
+ ArrayList<Element> elements = new ArrayList<Element>();
+
+ /*
+ * Open all files and load the (direct or contained) dex files
+ * up front.
+ */
+ for (File file : files) {
+ ZipFile zip = null;
+ DexFile dex = null;
+ String name = file.getName();
+
+ if (name.endsWith(DEX_SUFFIX)) {
+ // Raw dex file (not inside a zip/jar).
+ try {
+ dex = loadDexFile(file, optimizedDirectory);
+ } catch (IOException ex) {
+ System.logE("Unable to load dex file: " + file, ex);
+ }
+ } else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX)
+ || name.endsWith(ZIP_SUFFIX)) {
+ try {
+ zip = new ZipFile(file);
+ } catch (IOException ex) {
+ /*
+ * Note: ZipException (a subclass of IOException)
+ * might get thrown by the ZipFile constructor
+ * (e.g. if the file isn't actually a zip/jar
+ * file).
+ */
+ System.logE("Unable to open zip file: " + file, ex);
+ }
+
+ try {
+ dex = loadDexFile(file, optimizedDirectory);
+ } catch (IOException ignored) {
+ /*
+ * IOException might get thrown "legitimately" by
+ * the DexFile constructor if the zip file turns
+ * out to be resource-only (that is, no
+ * classes.dex file in it). Safe to just ignore
+ * the exception here, and let dex == null.
+ */
+ }
+ } else {
+ System.logW("Unknown file type for: " + file);
+ }
+
+ if ((zip != null) || (dex != null)) {
+ elements.add(new Element(file, zip, dex));
+ }
+ }
+
+ return elements.toArray(new Element[elements.size()]);
+ }
+
+ /**
+ * Constructs a {@code DexFile} instance, as appropriate depending
+ * on whether {@code optimizedDirectory} is {@code null}.
+ */
+ private static DexFile loadDexFile(File file, File optimizedDirectory)
+ throws IOException {
+ if (optimizedDirectory == null) {
+ return new DexFile(file);
+ } else {
+ String optimizedPath = optimizedPathFor(file, optimizedDirectory);
+ return DexFile.loadDex(file.getPath(), optimizedPath, 0);
+ }
+ }
+
+ /**
+ * Converts a dex/jar file path and an output directory to an
+ * output file path for an associated optimized dex file.
+ */
+ private static String optimizedPathFor(File path,
+ File optimizedDirectory) {
+ /*
+ * Get the filename component of the path, and replace the
+ * suffix with ".dex" if that's not already the suffix.
+ *
+ * We don't want to use ".odex", because the build system uses
+ * that for files that are paired with resource-only jar
+ * files. If the VM can assume that there's no classes.dex in
+ * the matching jar, it doesn't need to open the jar to check
+ * for updated dependencies, providing a slight performance
+ * boost at startup. The use of ".dex" here matches the use on
+ * files in /data/dalvik-cache.
+ */
+ String fileName = path.getName();
+ if (!fileName.endsWith(DEX_SUFFIX)) {
+ int lastDot = fileName.lastIndexOf(".");
+ if (lastDot < 0) {
+ fileName += DEX_SUFFIX;
+ } else {
+ StringBuilder sb = new StringBuilder(lastDot + 4);
+ sb.append(fileName, 0, lastDot);
+ sb.append(DEX_SUFFIX);
+ fileName = sb.toString();
+ }
+ }
+
+ File result = new File(optimizedDirectory, fileName);
+ return result.getPath();
+ }
+
+ /**
+ * Finds the named class in one of the dex files pointed at by
+ * this instance. This will find the one in the earliest listed
+ * path element. If the class is found but has not yet been
+ * defined, then this method will define it in the defining
+ * context that this instance was constructed with.
+ *
+ * @return the named class or {@code null} if the class is not
+ * found in any of the dex files
+ */
+ public Class findClass(String name) {
+ for (Element element : dexElements) {
+ DexFile dex = element.dexFile;
+
+ if (dex != null) {
+ Class clazz = dex.loadClassBinaryName(name, definingContext);
+ if (clazz != null) {
+ return clazz;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds the named resource in one of the zip/jar files pointed at
+ * by this instance. This will find the one in the earliest listed
+ * path element.
+ *
+ * @return a URL to the named resource or {@code null} if the
+ * resource is not found in any of the zip/jar files
+ */
+ public URL findResource(String name) {
+ for (Element element : dexElements) {
+ URL url = element.findResource(name);
+ if (url != null) {
+ return url;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds all the resources with the given name, returning an
+ * enumeration of them. If there are no resources with the given
+ * name, then this method returns an empty enumeration.
+ */
+ public Enumeration<URL> findResources(String name) {
+ ArrayList<URL> result = new ArrayList<URL>();
+
+ for (Element element : dexElements) {
+ URL url = element.findResource(name);
+ if (url != null) {
+ result.add(url);
+ }
+ }
+
+ return Collections.enumeration(result);
+ }
+
+ /**
+ * Finds the named native code library on any of the library
+ * directories pointed at by this instance. This will find the
+ * one in the earliest listed directory, ignoring any that are not
+ * readable regular files.
+ *
+ * @return the complete path to the library or {@code null} if no
+ * library was found
+ */
+ public String findLibrary(String libraryName) {
+ String fileName = System.mapLibraryName(libraryName);
+
+ for (File directory : nativeLibraryDirectories) {
+ File file = new File(directory, fileName);
+ if (file.exists() && file.isFile() && file.canRead()) {
+ return file.getPath();
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Element of the dex/resource file path
+ */
+ /*package*/ static class Element {
+ public final File file;
+ public final ZipFile zipFile;
+ public final DexFile dexFile;
+
+ public Element(File file, ZipFile zipFile, DexFile dexFile) {
+ this.file = file;
+ this.zipFile = zipFile;
+ this.dexFile = dexFile;
+ }
+
+ public URL findResource(String name) {
+ if ((zipFile == null) || (zipFile.getEntry(name) == null)) {
+ /*
+ * Either this element has no zip/jar file (first
+ * clause), or the zip/jar file doesn't have an entry
+ * for the given name (second clause).
+ */
+ return null;
+ }
+
+ 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:" + file.toURL() + "!/" + name);
+ } catch (MalformedURLException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/NativeStart.java b/dalvik/src/main/java/dalvik/system/NativeStart.java
index ee360ff..1382823 100644
--- a/dalvik/src/main/java/dalvik/system/NativeStart.java
+++ b/dalvik/src/main/java/dalvik/system/NativeStart.java
@@ -30,11 +30,10 @@ package dalvik.system;
* 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 {
+class NativeStart {
private NativeStart() {}
private static native void main(String[] dummy);
- public native void run();
+ private static native void run();
}
-
diff --git a/dalvik/src/main/java/dalvik/system/PathClassLoader.java b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
index 08178a5..32c5586 100644
--- a/dalvik/src/main/java/dalvik/system/PathClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/PathClassLoader.java
@@ -16,65 +16,26 @@
package dalvik.system;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.NoSuchElementException;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import libcore.io.IoUtils;
-
/**
* Provides a simple {@link ClassLoader} implementation that operates on a list
* of files and directories in the local file system, but does not attempt to
* load classes from the network. Android uses this class for its system class
* loader and for its application class loader(s).
*/
-public class PathClassLoader extends ClassLoader {
- // TODO: Factor out commonality between this class and DexClassLoader.
-
- private final String path;
- private final String libPath;
-
- /*
- * Parallel arrays for jar/apk files.
- *
- * (could stuff these into an object and have a single array;
- * improves clarity but adds overhead)
- */
- private final String[] mPaths;
- private final File[] mFiles;
- private final ZipFile[] mZips;
- private final DexFile[] mDexs;
-
- /**
- * Native library path.
- */
- private final List<String> libraryPathElements;
-
+public class PathClassLoader extends BaseDexClassLoader {
/**
* Creates a {@code PathClassLoader} that operates on a given list of files
* and directories. This method is equivalent to calling
* {@link #PathClassLoader(String, String, ClassLoader)} with a
* {@code null} value for the second argument (see description there).
*
- * @param path
- * the list of files and directories
- *
- * @param parent
- * the parent class loader
+ * @param dexPath the list of jar/apk files containing classes and
+ * resources, delimited by {@code File.pathSeparator}, which
+ * defaults to {@code ":"} on Android
+ * @param parent the parent class loader
*/
- public PathClassLoader(String path, ClassLoader parent) {
- this(path, null, parent);
+ public PathClassLoader(String dexPath, ClassLoader parent) {
+ super(dexPath, null, null, parent);
}
/**
@@ -83,382 +44,24 @@ public class PathClassLoader extends ClassLoader {
* should be one of the following:
*
* <ul>
- * <li>Directories containing classes or resources.
- * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file.
- * <li>"classes.dex" files.
+ * <li>JAR/ZIP/APK files, possibly containing a "classes.dex" file as
+ * well as arbitrary resources.
+ * <li>Raw ".dex" files (not inside a zip file).
* </ul>
*
* The entries of the second list should be directories containing
- * native library files. Both lists are separated using the
- * character specified by the "path.separator" system property,
- * which, on Android, defaults to ":".
- *
- * @param path
- * the list of files and directories containing classes and
- * resources
- *
- * @param libPath
- * the list of directories containing native libraries
- *
- * @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;
-
- mPaths = path.split(":");
- int length = mPaths.length;
-
- mFiles = new File[length];
- mZips = new ZipFile[length];
- mDexs = new DexFile[length];
-
- /* open all Zip and DEX files up front */
- for (int i = 0; i < length; i++) {
- File pathFile = new File(mPaths[i]);
- mFiles[i] = pathFile;
-
- if (pathFile.isFile()) {
- if (!mPaths[i].endsWith(".dex")) {
- /*
- * If the name doesn't end with ".dex" assume it's a zip
- * file of some sort.
- */
- try {
- mZips[i] = new ZipFile(pathFile);
- }
- catch (IOException ioex) {
- // expecting IOException and ZipException
- //System.out.println("Failed opening '" + pathFile
- // + "': " + ioex);
- //ioex.printStackTrace();
- }
- }
-
- /*
- * If we got a zip file, we still need to extract out
- * the dex file from it.
- */
- try {
- mDexs[i] = new DexFile(pathFile);
- }
- catch (IOException ioex) {
- // It might be a resource-only zip.
- //System.out.println("Failed to construct DexFile '"
- // + pathFile + "': " + ioex);
- }
- }
- }
-
- /*
- * Native libraries may exist in both the system and application library
- * paths, so we use this search order for these paths:
- * 1. This class loader's library path for application libraries
- * 2. The VM's library path from the system property for system libraries
- * This order was reversed prior to Gingerbread; see http://b/2933456
- */
- libraryPathElements = new ArrayList<String>();
- if (libPath != null) {
- for (String pathElement : libPath.split(File.pathSeparator)) {
- libraryPathElements.add(cleanupPathElement(pathElement));
- }
- }
- String systemLibraryPath = System.getProperty("java.library.path", ".");
- if (!systemLibraryPath.isEmpty()) {
- for (String pathElement : systemLibraryPath.split(File.pathSeparator)) {
- libraryPathElements.add(cleanupPathElement(pathElement));
- }
- }
- }
-
- /**
- * Returns a path element that includes a trailing file separator.
- */
- private String cleanupPathElement(String path) {
- return path.endsWith(File.separator) ? path : (path + File.separator);
- }
-
- /**
- * Finds a class. This method is called by {@code loadClass()} after the
- * parent ClassLoader has failed to find a loaded class of the same name.
+ * native library files.
*
- * @param name
- * The "binary name" of the class to search for, in a
- * human-readable form like "java.lang.String" or
- * "java.net.URLClassLoader$3$1".
- * @return the {@link Class} object representing the class
- * @throws ClassNotFoundException
- * if the class cannot be found
+ * @param dexPath the list of jar/apk files containing classes and
+ * resources, delimited by {@code File.pathSeparator}, which
+ * defaults to {@code ":"} on Android
+ * @param libraryPath the list of directories containing native
+ * libraries, delimited by {@code File.pathSeparator}; may be
+ * {@code null}
+ * @param parent the parent class loader
*/
- @Override
- protected Class<?> findClass(String name) throws ClassNotFoundException {
- //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) {
- Class clazz = mDexs[i].loadClassBinaryName(name, 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);
- }
-
- /**
- * Finds a resource. This method is called by {@code getResource()} after
- * the parent ClassLoader has failed to find a loaded resource of the same
- * name.
- *
- * @param name
- * The name of the resource to find
- * @return the location of the resource as a URL, or {@code null} if the
- * resource is not found.
- */
- @Override
- protected URL findResource(String name) {
- //java.util.logging.Logger.global.severe("findResource: " + name);
-
- int length = mPaths.length;
-
- for (int i = 0; i < length; i++) {
- URL result = findResource(name, i);
- if (result != null) {
- return result;
- }
- }
-
- return null;
- }
-
- /**
- * Finds an enumeration of URLs for the resource with the specified name.
- *
- * @param resName
- * the name of the resource to find.
- * @return an enumeration of {@code URL} objects for the requested resource.
- */
- @Override
- protected Enumeration<URL> findResources(String resName) {
- int length = mPaths.length;
- ArrayList<URL> results = new ArrayList<URL>();
- for (int i = 0; i < length; i++) {
- URL result = findResource(resName, i);
- if (result != null) {
- results.add(result);
- }
- }
- return Collections.enumeration(results);
- }
-
- private URL findResource(String name, int 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) {
- try {
- return IoUtils.readFileAsByteArray(path);
- } catch (IOException ex) {
- System.err.println("Error reading from " + path);
- // swallow it, return null instead
- return null;
- }
- }
-
- /*
- * 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;
- }
-
- /**
- * Finds a native library. This class loader first searches its own library
- * path (as specified in the constructor) and then the system library path.
- * In Android 2.2 and earlier, the search order was reversed.
- *
- * @param libname
- * The name of the library to find
- * @return the complete path of the library, or {@code null} if the library
- * is not found.
- */
- public String findLibrary(String libname) {
- String fileName = System.mapLibraryName(libname);
- for (String pathElement : libraryPathElements) {
- String pathName = pathElement + 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.
- *
- * @param name
- * the name of the class
- * @return the package information for the class, or {@code null} if there
- * is not package information available for it
- */
- @Override
- protected Package getPackage(String name) {
- if (name != null && !name.isEmpty()) {
- 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;
- }
-
- public String toString () {
- return getClass().getName() + "[" + path + "]";
+ public PathClassLoader(String dexPath, String libraryPath,
+ ClassLoader parent) {
+ super(dexPath, null, libraryPath, parent);
}
}
diff --git a/dalvik/src/main/java/dalvik/system/TemporaryDirectory.java b/dalvik/src/main/java/dalvik/system/TemporaryDirectory.java
index 1f2defd..ff0f759 100644
--- a/dalvik/src/main/java/dalvik/system/TemporaryDirectory.java
+++ b/dalvik/src/main/java/dalvik/system/TemporaryDirectory.java
@@ -17,7 +17,6 @@
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
@@ -68,8 +67,7 @@ public class TemporaryDirectory {
*/
public static synchronized void setUpDirectory(File baseDir) {
if (configured) {
- Logger.global.info("Already set to: " +
- System.getProperty(PROPERTY));
+ System.logE("Already set to: " + System.getProperty(PROPERTY));
return;
}
diff --git a/dalvik/src/main/java/dalvik/system/TouchDex.java b/dalvik/src/main/java/dalvik/system/TouchDex.java
deleted file mode 100644
index 53cd00c..0000000
--- a/dalvik/src/main/java/dalvik/system/TouchDex.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * 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.File;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/**
- * Induces optimization/verification of a set of DEX files.
- *
- * @hide
- */
-public class TouchDex {
-
- /**
- * Forks a process, makes sure the DEX files are prepared, and returns
- * when everything is finished.
- * <p>
- * 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/ZIP/APK should work.)
- *
- * @param dexFiles a 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);
-
- /**
- * The entry point for the child process. args[0] can be a colon-separated
- * path list, or "-" to read from stdin.
- * <p>
- * 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
deleted file mode 100644
index e5f9743..0000000
--- a/dalvik/src/main/java/dalvik/system/TouchDexLoader.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * 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.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import libcore.io.IoUtils;
-
-/**
- * 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;
-
- /*
- * Parallel arrays for jar/apk files.
- *
- * (could stuff these into an object and have a single array;
- * improves clarity but adds overhead)
- */
- private final String[] mPaths;
- private final File[] mFiles;
- private final ZipFile[] mZips;
- private final DexFile[] mDexs;
-
- /**
- * Native library path.
- */
- private final String[] mLibPaths;
-
- /**
- * 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;
-
- 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
- {
- 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) {
- 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) {
- try {
- return IoUtils.readFileAsByteArray(path);
- } catch (IOException ex) {
- System.err.println("Error reading from " + path);
- // swallow it, return null instead
- return null;
- }
- }
-
- /*
- * 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) {
- 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;
- }
-}
diff --git a/dalvik/src/main/java/dalvik/system/VMRuntime.java b/dalvik/src/main/java/dalvik/system/VMRuntime.java
index 373dd03..3e35ecf 100644
--- a/dalvik/src/main/java/dalvik/system/VMRuntime.java
+++ b/dalvik/src/main/java/dalvik/system/VMRuntime.java
@@ -47,6 +47,27 @@ public final class VMRuntime {
}
/**
+ * Returns a copy of the VM's command-line property settings.
+ * These are in the form "name=value" rather than "-Dname=value".
+ */
+ public native String[] properties();
+
+ /**
+ * Returns the VM's boot class path.
+ */
+ public native String bootClassPath();
+
+ /**
+ * Returns the VM's class path.
+ */
+ public native String classPath();
+
+ /**
+ * Returns the VM's version.
+ */
+ public native String vmVersion();
+
+ /**
* 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
@@ -104,17 +125,20 @@ public final class VMRuntime {
}
/**
- * Requests that the virtual machine collect available memory,
- * and collects any SoftReferences that are not strongly-reachable.
+ * This method exists for binary compatibility. It used to
+ * perform a garbage collection that cleared SoftReferences.
*/
- public native void gcSoftReferences();
+ @Deprecated
+ public 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.
+ * This method exists for binary compatibility. It is equivalent
+ * to {@link System#runFinalization}.
*/
- public native void runFinalizationSync();
+ @Deprecated
+ public void runFinalizationSync() {
+ System.runFinalization();
+ }
/**
* Implements setTargetHeapUtilization().
diff --git a/dalvik/src/main/java/dalvik/system/VMStack.java b/dalvik/src/main/java/dalvik/system/VMStack.java
index 16a04e6..a8430d8 100644
--- a/dalvik/src/main/java/dalvik/system/VMStack.java
+++ b/dalvik/src/main/java/dalvik/system/VMStack.java
@@ -49,9 +49,7 @@ public final class VMStack {
/**
* Creates 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.
+ * specified maximum depth.
* <p>
* The topmost stack frame (this method) and the one above that (the
* caller) are excluded from the array. Frames with java.lang.reflect
@@ -59,16 +57,14 @@ public final class VMStack {
* <p>
* The classes in the array are the defining classes of the methods.
* <p>
- * This is expected to be identical to Harmony's VMStack.getClasses.
+ * This is similar to Harmony's VMStack.getClasses, except that this
+ * implementation doesn't have a concept of "privileged" frames.
*
* @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);
+ native public static Class<?>[] getClasses(int maxDepth);
/**
* Retrieves the stack trace from the specified thread.
diff --git a/dalvik/src/main/java/dalvik/system/Zygote.java b/dalvik/src/main/java/dalvik/system/Zygote.java
index 96928c8..791460b 100644
--- a/dalvik/src/main/java/dalvik/system/Zygote.java
+++ b/dalvik/src/main/java/dalvik/system/Zygote.java
@@ -16,6 +16,8 @@
package dalvik.system;
+import java.lang.FinalizerThread;
+
/**
* Provides access to the Dalvik "zygote" feature, which allows a VM instance to
* be partially initialized and then fork()'d from the partially initialized
@@ -45,6 +47,14 @@ public class Zygote {
private Zygote() {}
+ private static void preFork() {
+ FinalizerThread.stopFinalizer();
+ }
+
+ private static void postFork() {
+ FinalizerThread.startFinalizer();
+ }
+
/**
* Forks a new Zygote instance, but does not leave the zygote mode.
* The current VM must have been started with the -Xzygote flag. The
@@ -53,7 +63,14 @@ public class Zygote {
* @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();
+ public static int fork() {
+ preFork();
+ int pid = nativeFork();
+ postFork();
+ return pid;
+ }
+
+ native public static int nativeFork();
/**
* Forks a new VM instance. The current VM must have been started
@@ -75,8 +92,16 @@ public class Zygote {
* @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,
- int debugFlags, int[][] rlimits);
+ public static int forkAndSpecialize(int uid, int gid, int[] gids,
+ int debugFlags, int[][] rlimits) {
+ preFork();
+ int pid = nativeForkAndSpecialize(uid, gid, gids, debugFlags, rlimits);
+ postFork();
+ return pid;
+ }
+
+ native public static int nativeForkAndSpecialize(int uid, int gid,
+ int[] gids, int debugFlags, int[][] rlimits);
/**
* Forks a new VM instance.
@@ -112,9 +137,16 @@ public class Zygote {
* @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, int debugFlags, int[][] rlimits,
- long permittedCapabilities, long effectiveCapabilities);
+ public static int forkSystemServer(int uid, int gid, int[] gids,
+ int debugFlags, int[][] rlimits,
+ long permittedCapabilities, long effectiveCapabilities) {
+ preFork();
+ int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits,
+ permittedCapabilities,
+ effectiveCapabilities);
+ postFork();
+ return pid;
+ }
/**
* Special method to start the system server process.
@@ -126,4 +158,8 @@ public class Zygote {
int debugFlags = enableDebugger ? DEBUG_ENABLE_DEBUGGER : 0;
return forkAndSpecialize(uid, gid, gids, debugFlags, rlimits);
}
+
+ native public static int nativeForkSystemServer(int uid, int gid,
+ int[] gids, int debugFlags, int[][] rlimits,
+ long permittedCapabilities, long effectiveCapabilities);
}
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
index 5ca3b2a..5d0073b 100644
--- a/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java
+++ b/dalvik/src/main/java/org/apache/harmony/dalvik/ddmc/ChunkHandler.java
@@ -108,19 +108,15 @@ public abstract class ChunkHandler {
/**
* 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);
+ public static int type(String typeName) {
+ if (typeName.length() != 4) {
+ throw new IllegalArgumentException("Bad type name: " + typeName);
}
-
- return val;
+ int result = 0;
+ for (int i = 0; i < 4; ++i) {
+ result = ((result << 8) | (typeName.charAt(i) & 0xff));
+ }
+ return result;
}
/**
@@ -139,4 +135,3 @@ public abstract class ChunkHandler {
}
}
-
diff --git a/dalvik/src/main/native/dalvik_system_TouchDex.cpp b/dalvik/src/main/native/dalvik_system_TouchDex.cpp
deleted file mode 100644
index 719ac3c..0000000
--- a/dalvik/src/main/native/dalvik_system_TouchDex.cpp
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * 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, 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;
- 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);
-}
-
-static JNINativeMethod gMethods[] = {
- { "trampoline", "(Ljava/lang/String;Ljava/lang/String;)I",
- (void*) dalvik_system_TouchDex_trampoline },
-};
-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/sub.mk b/dalvik/src/main/native/sub.mk
index 27d4c9c..4adc8a1 100644
--- a/dalvik/src/main/native/sub.mk
+++ b/dalvik/src/main/native/sub.mk
@@ -1,9 +1,9 @@
+# -*- mode: makefile -*-
# 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.cpp
#LOCAL_C_INCLUDES +=
@@ -15,4 +15,3 @@ LOCAL_SRC_FILES := \
#LOCAL_SHARED_LIBRARIES +=
#LOCAL_STATIC_LIBRARIES +=
-