diff options
Diffstat (limited to 'dalvik')
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 — typically referred + * to as a "class path" — 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 += - |