summaryrefslogtreecommitdiffstats
path: root/library
diff options
context:
space:
mode:
authorYohann Roussel <yroussel@google.com>2014-06-26 13:33:15 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-06-24 06:38:28 +0000
commit591acd99f16989233ff3e226546272bb60024559 (patch)
treefe9523df46a9b77c8fcce98070ea822d01fbde69 /library
parentc741a211ee1c92e8796e3eb9a87007cf144038d1 (diff)
parent7b86f7e21c70ac06129c05ed137e585a308c6fd1 (diff)
downloadandroid_frameworks_multidex-591acd99f16989233ff3e226546272bb60024559.tar.gz
android_frameworks_multidex-591acd99f16989233ff3e226546272bb60024559.tar.bz2
android_frameworks_multidex-591acd99f16989233ff3e226546272bb60024559.zip
Merge "Deactivate the library if vm version is 2.1 or newer."
Diffstat (limited to 'library')
-rw-r--r--library/src/android/support/multidex/MultiDex.java62
-rw-r--r--library/test/src/android/support/multidex/MultiDexTest.java47
-rw-r--r--library/test/src/android/util/Log.java225
3 files changed, 324 insertions, 10 deletions
diff --git a/library/src/android/support/multidex/MultiDex.java b/library/src/android/support/multidex/MultiDex.java
index 97c1ddd..cd38112 100644
--- a/library/src/android/support/multidex/MultiDex.java
+++ b/library/src/android/support/multidex/MultiDex.java
@@ -37,6 +37,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import java.util.zip.ZipFile;
/**
@@ -48,9 +50,8 @@ import java.util.zip.ZipFile;
* {@link #install(Context)}.
*
* <p/>
- * <strong>IMPORTANT:</strong>This library provides compatibility for platforms
- * with API level 4 through 20. This library does nothing on newer versions of
- * the platform which provide built-in support for secondary dex files.
+ * This library provides compatibility for platforms with API level 4 through 20. This library does
+ * nothing on newer versions of the platform which provide built-in support for secondary dex files.
*/
public final class MultiDex {
@@ -58,12 +59,19 @@ public final class MultiDex {
private static final String SECONDARY_FOLDER_NAME = "secondary-dexes";
- private static final int SUPPORTED_MULTIDEX_SDK_VERSION = 21;
+ private static final int MAX_SUPPORTED_SDK_VERSION = 20;
private static final int MIN_SDK_VERSION = 4;
+ private static final int VM_WITH_MULTIDEX_VERSION_MAJOR = 2;
+
+ private static final int VM_WITH_MULTIDEX_VERSION_MINOR = 1;
+
private static final Set<String> installedApk = new HashSet<String>();
+ private static final boolean IS_VM_MULTIDEX_CAPABLE =
+ isVMMultidexCapable(System.getProperty("java.vm.version"));
+
private MultiDex() {}
/**
@@ -78,13 +86,16 @@ public final class MultiDex {
*/
public static void install(Context context) {
Log.i(TAG, "install");
+ if (IS_VM_MULTIDEX_CAPABLE) {
+ Log.i(TAG, "VM has multidex support, MultiDex support library is disabled.");
+ return;
+ }
if (Build.VERSION.SDK_INT < MIN_SDK_VERSION) {
throw new RuntimeException("Multi dex installation failed. SDK " + Build.VERSION.SDK_INT
+ " is unsupported. Min SDK version is " + MIN_SDK_VERSION + ".");
}
-
try {
PackageManager pm;
String packageName;
@@ -118,11 +129,13 @@ public final class MultiDex {
}
installedApk.add(apkPath);
- if (Build.VERSION.SDK_INT >= SUPPORTED_MULTIDEX_SDK_VERSION) {
- // STOPSHIP: Any app that uses this class needs approval before being released
- // as well as figuring out what the right behavior should be here.
- throw new RuntimeException("Platform support of multidex for SDK " +
- Build.VERSION.SDK_INT + " has not been confirmed yet.");
+ if (Build.VERSION.SDK_INT > MAX_SUPPORTED_SDK_VERSION) {
+ Log.w(TAG, "MultiDex is not guaranteed to work in SDK version "
+ + Build.VERSION.SDK_INT + ": SDK version higher than "
+ + MAX_SUPPORTED_SDK_VERSION + " should be backed by "
+ + "runtime with built-in multidex capabilty but it's not the "
+ + "case here: java.vm.version=\""
+ + System.getProperty("java.vm.version") + "\"");
}
/* The patched class loader is expected to be a descendant of
@@ -175,6 +188,35 @@ public final class MultiDex {
Log.i(TAG, "install done");
}
+ /**
+ * Identifies if the current VM has a native support for multidex, meaning there is no need for
+ * additional installation by this library.
+ * @return true if the VM handles multidex
+ */
+ /* package visible for test */
+ static boolean isVMMultidexCapable(String versionString) {
+ boolean isMultidexCapable = false;
+ if (versionString != null) {
+ Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)(\\.\\d+)?").matcher(versionString);
+ if (matcher.matches()) {
+ try {
+ int major = Integer.parseInt(matcher.group(1));
+ int minor = Integer.parseInt(matcher.group(2));
+ isMultidexCapable = (major > VM_WITH_MULTIDEX_VERSION_MAJOR)
+ || ((major == VM_WITH_MULTIDEX_VERSION_MAJOR)
+ && (minor >= VM_WITH_MULTIDEX_VERSION_MINOR));
+ } catch (NumberFormatException e) {
+ // let isMultidexCapable be false
+ }
+ }
+ }
+ Log.i(TAG, "VM with version " + versionString +
+ (isMultidexCapable ?
+ " has multidex support" :
+ " does not have multidex support"));
+ return isMultidexCapable;
+ }
+
private static void installSecondaryDexes(ClassLoader loader, File dexDir, List<File> files)
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
InvocationTargetException, NoSuchMethodException, IOException {
diff --git a/library/test/src/android/support/multidex/MultiDexTest.java b/library/test/src/android/support/multidex/MultiDexTest.java
new file mode 100644
index 0000000..62bdc30
--- /dev/null
+++ b/library/test/src/android/support/multidex/MultiDexTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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 android.support.multidex;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Test for {@link MultiDex} class.
+ */
+public class MultiDexTest {
+ @Test
+ public void testVersionCheck() {
+ Assert.assertFalse(MultiDex.isVMMultidexCapable(null));
+ Assert.assertFalse(MultiDex.isVMMultidexCapable("-1.32.54"));
+ Assert.assertFalse(MultiDex.isVMMultidexCapable("1.32.54"));
+ Assert.assertFalse(MultiDex.isVMMultidexCapable("1.32"));
+ Assert.assertFalse(MultiDex.isVMMultidexCapable("2.0"));
+ Assert.assertFalse(MultiDex.isVMMultidexCapable("2.000.1254"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("2.1.1254"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("2.1"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("2.2"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("2.1.0000"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("2.2.0000"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("002.0001.0010"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("3.0"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("3.0.0"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("3.0.1"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("3.1.0"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("03.1.132645"));
+ Assert.assertTrue(MultiDex.isVMMultidexCapable("03.2"));
+ }
+}
diff --git a/library/test/src/android/util/Log.java b/library/test/src/android/util/Log.java
new file mode 100644
index 0000000..b94e48b
--- /dev/null
+++ b/library/test/src/android/util/Log.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2006 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 android.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.net.UnknownHostException;
+
+/**
+ * Mock Log implementation for testing on non android host.
+ */
+public final class Log {
+
+ /**
+ * Priority constant for the println method; use Log.v.
+ */
+ public static final int VERBOSE = 2;
+
+ /**
+ * Priority constant for the println method; use Log.d.
+ */
+ public static final int DEBUG = 3;
+
+ /**
+ * Priority constant for the println method; use Log.i.
+ */
+ public static final int INFO = 4;
+
+ /**
+ * Priority constant for the println method; use Log.w.
+ */
+ public static final int WARN = 5;
+
+ /**
+ * Priority constant for the println method; use Log.e.
+ */
+ public static final int ERROR = 6;
+
+ /**
+ * Priority constant for the println method.
+ */
+ public static final int ASSERT = 7;
+
+ private Log() {
+ }
+
+ /**
+ * Send a {@link #VERBOSE} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int v(String tag, String msg) {
+ return println(LOG_ID_MAIN, VERBOSE, tag, msg);
+ }
+
+ /**
+ * Send a {@link #VERBOSE} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int v(String tag, String msg, Throwable tr) {
+ return println(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Send a {@link #DEBUG} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int d(String tag, String msg) {
+ return println(LOG_ID_MAIN, DEBUG, tag, msg);
+ }
+
+ /**
+ * Send a {@link #DEBUG} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int d(String tag, String msg, Throwable tr) {
+ return println(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Send an {@link #INFO} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int i(String tag, String msg) {
+ return println(LOG_ID_MAIN, INFO, tag, msg);
+ }
+
+ /**
+ * Send a {@link #INFO} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int i(String tag, String msg, Throwable tr) {
+ return println(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Send a {@link #WARN} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int w(String tag, String msg) {
+ return println(LOG_ID_MAIN, WARN, tag, msg);
+ }
+
+ /**
+ * Send a {@link #WARN} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int w(String tag, String msg, Throwable tr) {
+ return println(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /*
+ * Send a {@link #WARN} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param tr An exception to log
+ */
+ public static int w(String tag, Throwable tr) {
+ return println(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
+ }
+
+ /**
+ * Send an {@link #ERROR} log message.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ */
+ public static int e(String tag, String msg) {
+ return println(LOG_ID_MAIN, ERROR, tag, msg);
+ }
+
+ /**
+ * Send a {@link #ERROR} log message and log the exception.
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log
+ */
+ public static int e(String tag, String msg, Throwable tr) {
+ return println(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
+ }
+
+ /**
+ * Handy function to get a loggable stack trace from a Throwable
+ * @param tr An exception to log
+ */
+ public static String getStackTraceString(Throwable tr) {
+ if (tr == null) {
+ return "";
+ }
+
+ // This is to reduce the amount of log spew that apps do in the non-error
+ // condition of the network being unavailable.
+ Throwable t = tr;
+ while (t != null) {
+ if (t instanceof UnknownHostException) {
+ return "";
+ }
+ t = t.getCause();
+ }
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ tr.printStackTrace(pw);
+ pw.flush();
+ return sw.toString();
+ }
+
+ /**
+ * Low-level logging call.
+ * @param priority The priority/type of this log message
+ * @param tag Used to identify the source of a log message. It usually identifies
+ * the class or activity where the log call occurs.
+ * @param msg The message you would like logged.
+ * @return The number of bytes written.
+ */
+ public static int println(int priority, String tag, String msg) {
+ return println(LOG_ID_MAIN, priority, tag, msg);
+ }
+
+ /** @hide */ public static final int LOG_ID_MAIN = 0;
+ /** @hide */ public static final int LOG_ID_RADIO = 1;
+ /** @hide */ public static final int LOG_ID_EVENTS = 2;
+ /** @hide */ public static final int LOG_ID_SYSTEM = 3;
+ /** @hide */ public static final int LOG_ID_CRASH = 4;
+
+ /** @hide */ @SuppressWarnings("unused")
+ public static int println(int bufID,
+ int priority, String tag, String msg) {
+ return 0;
+ }
+}