summaryrefslogtreecommitdiff
path: root/base/android/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'base/android/java/src')
-rw-r--r--base/android/java/src/org/chromium/base/BuildInfo.java171
-rw-r--r--base/android/java/src/org/chromium/base/ContextUtils.java115
-rw-r--r--base/android/java/src/org/chromium/base/Log.java387
-rw-r--r--base/android/java/src/org/chromium/base/PackageUtils.java37
-rw-r--r--base/android/java/src/org/chromium/base/VisibleForTesting.java12
-rw-r--r--base/android/java/src/org/chromium/base/annotations/AccessedByNative.java20
-rw-r--r--base/android/java/src/org/chromium/base/annotations/CalledByNative.java23
-rw-r--r--base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java27
-rw-r--r--base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java35
-rw-r--r--base/android/java/src/org/chromium/base/annotations/JNINamespace.java20
-rw-r--r--base/android/java/src/org/chromium/base/annotations/MainDex.java21
-rw-r--r--base/android/java/src/org/chromium/base/annotations/NativeCall.java24
-rw-r--r--base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java25
-rw-r--r--base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java18
-rw-r--r--base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java20
-rw-r--r--base/android/java/src/org/chromium/base/annotations/UsedByReflection.java24
16 files changed, 979 insertions, 0 deletions
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
new file mode 100644
index 0000000000..de4ad08a83
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -0,0 +1,171 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.os.StrictMode;
+
+import org.chromium.base.annotations.CalledByNative;
+
+/**
+ * BuildInfo is a utility class providing easy access to {@link PackageInfo} information. This is
+ * primarily of use for accessing package information from native code.
+ */
+public class BuildInfo {
+ private static final String TAG = "BuildInfo";
+ private static final int MAX_FINGERPRINT_LENGTH = 128;
+
+ /**
+ * BuildInfo is a static utility class and therefore shouldn't be instantiated.
+ */
+ private BuildInfo() {}
+
+ @CalledByNative
+ public static String getDevice() {
+ return Build.DEVICE;
+ }
+
+ @CalledByNative
+ public static String getBrand() {
+ return Build.BRAND;
+ }
+
+ @CalledByNative
+ public static String getAndroidBuildId() {
+ return Build.ID;
+ }
+
+ /**
+ * @return The build fingerprint for the current Android install. The value is truncated to a
+ * 128 characters as this is used for crash and UMA reporting, which should avoid huge
+ * strings.
+ */
+ @CalledByNative
+ public static String getAndroidBuildFingerprint() {
+ return Build.FINGERPRINT.substring(
+ 0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH));
+ }
+
+ @CalledByNative
+ public static String getDeviceManufacturer() {
+ return Build.MANUFACTURER;
+ }
+
+ @CalledByNative
+ public static String getDeviceModel() {
+ return Build.MODEL;
+ }
+
+ @CalledByNative
+ public static String getGMSVersionCode() {
+ String msg = "gms versionCode not available.";
+ try {
+ PackageManager packageManager =
+ ContextUtils.getApplicationContext().getPackageManager();
+ PackageInfo packageInfo = packageManager.getPackageInfo("com.google.android.gms", 0);
+ msg = Integer.toString(packageInfo.versionCode);
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, "GMS package is not found.", e);
+ }
+ return msg;
+ }
+
+ @CalledByNative
+ public static String getPackageVersionCode() {
+ String msg = "versionCode not available.";
+ try {
+ PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(getPackageName(), 0);
+ msg = "";
+ if (pi.versionCode > 0) {
+ msg = Integer.toString(pi.versionCode);
+ }
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, msg);
+ }
+ return msg;
+ }
+
+ @CalledByNative
+ public static String getPackageVersionName() {
+ String msg = "versionName not available";
+ try {
+ PackageManager pm = ContextUtils.getApplicationContext().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(getPackageName(), 0);
+ msg = "";
+ if (pi.versionName != null) {
+ msg = pi.versionName;
+ }
+ } catch (NameNotFoundException e) {
+ Log.d(TAG, msg);
+ }
+ return msg;
+ }
+
+ @CalledByNative
+ public static String getPackageLabel() {
+ // Third-party code does disk read on the getApplicationInfo call. http://crbug.com/614343
+ StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+ try {
+ PackageManager packageManager =
+ ContextUtils.getApplicationContext().getPackageManager();
+ ApplicationInfo appInfo = packageManager.getApplicationInfo(
+ getPackageName(), PackageManager.GET_META_DATA);
+ CharSequence label = packageManager.getApplicationLabel(appInfo);
+ return label != null ? label.toString() : "";
+ } catch (NameNotFoundException e) {
+ return "";
+ } finally {
+ StrictMode.setThreadPolicy(oldPolicy);
+ }
+ }
+
+ @CalledByNative
+ public static String getPackageName() {
+ if (ContextUtils.getApplicationContext() == null) {
+ return "";
+ }
+ return ContextUtils.getApplicationContext().getPackageName();
+ }
+
+ @CalledByNative
+ public static String getBuildType() {
+ return Build.TYPE;
+ }
+
+ /**
+ * Check if this is a debuggable build of Android. Use this to enable developer-only features.
+ */
+ public static boolean isDebugAndroid() {
+ return "eng".equals(Build.TYPE) || "userdebug".equals(Build.TYPE);
+ }
+
+ @CalledByNative
+ public static int getSdkInt() {
+ return Build.VERSION.SDK_INT;
+ }
+
+ /**
+ * @return Whether the current device is running Android O release or newer.
+ */
+ public static boolean isAtLeastO() {
+ return !"REL".equals(Build.VERSION.CODENAME)
+ && ("O".equals(Build.VERSION.CODENAME) || Build.VERSION.CODENAME.startsWith("OMR"));
+ }
+
+ /**
+ * @return Whether the current app targets the SDK for at least O
+ */
+ public static boolean targetsAtLeastO(Context appContext) {
+ return isAtLeastO()
+ && appContext.getApplicationInfo().targetSdkVersion
+ == Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+}
diff --git a/base/android/java/src/org/chromium/base/ContextUtils.java b/base/android/java/src/org/chromium/base/ContextUtils.java
new file mode 100644
index 0000000000..448eff9b6a
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ContextUtils.java
@@ -0,0 +1,115 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.MainDex;
+
+/**
+ * This class provides Android application context related utility methods.
+ */
+@JNINamespace("base::android")
+@MainDex
+public class ContextUtils {
+ private static final String TAG = "ContextUtils";
+ private static Context sApplicationContext;
+
+ /**
+ * Initialization-on-demand holder. This exists for thread-safe lazy initialization.
+ */
+ private static class Holder {
+ // Not final for tests.
+ private static SharedPreferences sSharedPreferences = fetchAppSharedPreferences();
+ }
+
+ /**
+ * Get the Android application context.
+ *
+ * Under normal circumstances there is only one application context in a process, so it's safe
+ * to treat this as a global. In WebView it's possible for more than one app using WebView to be
+ * running in a single process, but this mechanism is rarely used and this is not the only
+ * problem in that scenario, so we don't currently forbid using it as a global.
+ *
+ * Do not downcast the context returned by this method to Application (or any subclass). It may
+ * not be an Application object; it may be wrapped in a ContextWrapper. The only assumption you
+ * may make is that it is a Context whose lifetime is the same as the lifetime of the process.
+ */
+ public static Context getApplicationContext() {
+ return sApplicationContext;
+ }
+
+ /**
+ * Initializes the java application context.
+ *
+ * This should be called exactly once early on during startup, before native is loaded and
+ * before any other clients make use of the application context through this class.
+ *
+ * @param appContext The application context.
+ */
+ public static void initApplicationContext(Context appContext) {
+ // Conceding that occasionally in tests, native is loaded before the browser process is
+ // started, in which case the browser process re-sets the application context.
+ if (sApplicationContext != null && sApplicationContext != appContext) {
+ throw new RuntimeException("Attempting to set multiple global application contexts.");
+ }
+ initJavaSideApplicationContext(appContext);
+ }
+
+ /**
+ * Initialize the native Android application context to be the same as the java counter-part.
+ */
+ public static void initApplicationContextForNative() {
+ if (sApplicationContext == null) {
+ throw new RuntimeException("Cannot have native global application context be null.");
+ }
+ nativeInitNativeSideApplicationContext(sApplicationContext);
+ }
+
+ /**
+ * Only called by the static holder class and tests.
+ *
+ * @return The application-wide shared preferences.
+ */
+ private static SharedPreferences fetchAppSharedPreferences() {
+ return PreferenceManager.getDefaultSharedPreferences(sApplicationContext);
+ }
+
+ /**
+ * This is used to ensure that we always use the application context to fetch the default shared
+ * preferences. This avoids needless I/O for android N and above. It also makes it clear that
+ * the app-wide shared preference is desired, rather than the potentially context-specific one.
+ *
+ * @return application-wide shared preferences.
+ */
+ public static SharedPreferences getAppSharedPreferences() {
+ return Holder.sSharedPreferences;
+ }
+
+ /**
+ * Occasionally tests cannot ensure the application context doesn't change between tests (junit)
+ * and sometimes specific tests has its own special needs, initApplicationContext should be used
+ * as much as possible, but this method can be used to override it.
+ *
+ * @param appContext The new application context.
+ */
+ @VisibleForTesting
+ public static void initApplicationContextForTests(Context appContext) {
+ initJavaSideApplicationContext(appContext);
+ Holder.sSharedPreferences = fetchAppSharedPreferences();
+ }
+
+ private static void initJavaSideApplicationContext(Context appContext) {
+ if (appContext == null) {
+ throw new RuntimeException("Global application context cannot be set to null.");
+ }
+ sApplicationContext = appContext;
+ }
+
+ private static native void nativeInitNativeSideApplicationContext(Context appContext);
+}
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
new file mode 100644
index 0000000000..399f16dfc1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -0,0 +1,387 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import org.chromium.base.annotations.RemovableInRelease;
+
+import java.util.Locale;
+
+/**
+ * Utility class for Logging.
+ *
+ * <p>
+ * Defines logging access points for each feature. They format and forward the logs to
+ * {@link android.util.Log}, allowing to standardize the output, to make it easy to identify
+ * the origin of logs, and enable or disable logging in different parts of the code.
+ * </p>
+ * <p>
+ * Usage documentation: {@code //docs/android_logging.md}.
+ * </p>
+ */
+public class Log {
+ /** Convenience property, same as {@link android.util.Log#ASSERT}. */
+ public static final int ASSERT = android.util.Log.ASSERT;
+
+ /** Convenience property, same as {@link android.util.Log#DEBUG}. */
+ public static final int DEBUG = android.util.Log.DEBUG;
+
+ /** Convenience property, same as {@link android.util.Log#ERROR}. */
+ public static final int ERROR = android.util.Log.ERROR;
+
+ /** Convenience property, same as {@link android.util.Log#INFO}. */
+ public static final int INFO = android.util.Log.INFO;
+
+ /** Convenience property, same as {@link android.util.Log#VERBOSE}. */
+ public static final int VERBOSE = android.util.Log.VERBOSE;
+
+ /** Convenience property, same as {@link android.util.Log#WARN}. */
+ public static final int WARN = android.util.Log.WARN;
+
+ private static final String sTagPrefix = "cr_";
+ private static final String sDeprecatedTagPrefix = "cr.";
+
+ private Log() {
+ // Static only access
+ }
+
+ /** Returns a formatted log message, using the supplied format and arguments.*/
+ private static String formatLog(String messageTemplate, Object... params) {
+ if (params != null && params.length != 0) {
+ messageTemplate = String.format(Locale.US, messageTemplate, params);
+ }
+
+ return messageTemplate;
+ }
+
+ /**
+ * Returns a normalized tag that will be in the form: "cr_foo". This function is called by the
+ * various Log overrides. If using {@link #isLoggable(String, int)}, you might want to call it
+ * to get the tag that will actually be used.
+ * @see #sTagPrefix
+ */
+ public static String normalizeTag(String tag) {
+ if (tag.startsWith(sTagPrefix)) return tag;
+
+ // TODO(dgn) simplify this once 'cr.' is out of the repo (http://crbug.com/533072)
+ int unprefixedTagStart = 0;
+ if (tag.startsWith(sDeprecatedTagPrefix)) {
+ unprefixedTagStart = sDeprecatedTagPrefix.length();
+ }
+
+ return sTagPrefix + tag.substring(unprefixedTagStart, tag.length());
+ }
+
+ /**
+ * Returns a formatted log message, using the supplied format and arguments.
+ * The message will be prepended with the filename and line number of the call.
+ */
+ private static String formatLogWithStack(String messageTemplate, Object... params) {
+ return "[" + getCallOrigin() + "] " + formatLog(messageTemplate, params);
+ }
+
+ /**
+ * Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}.
+ *
+ * Note: Has no effect on whether logs are sent or not. Use a method with
+ * {@link RemovableInRelease} to log something in Debug builds only.
+ */
+ public static boolean isLoggable(String tag, int level) {
+ return android.util.Log.isLoggable(tag, level);
+ }
+
+ /**
+ * Sends a {@link android.util.Log#VERBOSE} log message.
+ *
+ * For optimization purposes, only the fixed parameters versions are visible. If you need more
+ * than 7 parameters, consider building your log message using a function annotated with
+ * {@link RemovableInRelease}.
+ *
+ * @param tag Used to identify the source of a log message. Might be modified in the output
+ * (see {@link #normalizeTag(String)})
+ * @param messageTemplate The message you would like logged. It is to be specified as a format
+ * string.
+ * @param args Arguments referenced by the format specifiers in the format string. If the last
+ * one is a {@link Throwable}, its trace will be printed.
+ */
+ private static void verbose(String tag, String messageTemplate, Object... args) {
+ String message = formatLogWithStack(messageTemplate, args);
+ Throwable tr = getThrowableToLog(args);
+ if (tr != null) {
+ android.util.Log.v(normalizeTag(tag), message, tr);
+ } else {
+ android.util.Log.v(normalizeTag(tag), message);
+ }
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 0 args version. */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(String tag, String message) {
+ verbose(tag, message);
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(String tag, String messageTemplate, Object arg1) {
+ verbose(tag, messageTemplate, arg1);
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 2 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2) {
+ verbose(tag, messageTemplate, arg1, arg2);
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 3 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(
+ String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3);
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 4 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4);
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 5 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 6 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+
+ /** Sends a {@link android.util.Log#VERBOSE} log message. 7 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6, Object arg7) {
+ verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ /**
+ * Sends a {@link android.util.Log#DEBUG} log message.
+ *
+ * For optimization purposes, only the fixed parameters versions are visible. If you need more
+ * than 7 parameters, consider building your log message using a function annotated with
+ * {@link RemovableInRelease}.
+ *
+ * @param tag Used to identify the source of a log message. Might be modified in the output
+ * (see {@link #normalizeTag(String)})
+ * @param messageTemplate The message you would like logged. It is to be specified as a format
+ * string.
+ * @param args Arguments referenced by the format specifiers in the format string. If the last
+ * one is a {@link Throwable}, its trace will be printed.
+ */
+ private static void debug(String tag, String messageTemplate, Object... args) {
+ String message = formatLogWithStack(messageTemplate, args);
+ Throwable tr = getThrowableToLog(args);
+ if (tr != null) {
+ android.util.Log.d(normalizeTag(tag), message, tr);
+ } else {
+ android.util.Log.d(normalizeTag(tag), message);
+ }
+ }
+
+ /** Sends a {@link android.util.Log#DEBUG} log message. 0 args version. */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(String tag, String message) {
+ debug(tag, message);
+ }
+
+ /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(String tag, String messageTemplate, Object arg1) {
+ debug(tag, messageTemplate, arg1);
+ }
+ /** Sends a {@link android.util.Log#DEBUG} log message. 2 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2) {
+ debug(tag, messageTemplate, arg1, arg2);
+ }
+ /** Sends a {@link android.util.Log#DEBUG} log message. 3 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(
+ String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+ debug(tag, messageTemplate, arg1, arg2, arg3);
+ }
+
+ /** Sends a {@link android.util.Log#DEBUG} log message. 4 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4);
+ }
+
+ /** Sends a {@link android.util.Log#DEBUG} log message. 5 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+ }
+
+ /** Sends a {@link android.util.Log#DEBUG} log message. 6 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+ }
+
+ /** Sends a {@link android.util.Log#DEBUG} log message. 7 args version */
+ @RemovableInRelease
+ @VisibleForTesting
+ public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+ Object arg4, Object arg5, Object arg6, Object arg7) {
+ debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ }
+
+ /**
+ * Sends an {@link android.util.Log#INFO} log message.
+ *
+ * @param tag Used to identify the source of a log message. Might be modified in the output
+ * (see {@link #normalizeTag(String)})
+ * @param messageTemplate The message you would like logged. It is to be specified as a format
+ * string.
+ * @param args Arguments referenced by the format specifiers in the format string. If the last
+ * one is a {@link Throwable}, its trace will be printed.
+ */
+ @VisibleForTesting
+ public static void i(String tag, String messageTemplate, Object... args) {
+ String message = formatLog(messageTemplate, args);
+ Throwable tr = getThrowableToLog(args);
+ if (tr != null) {
+ android.util.Log.i(normalizeTag(tag), message, tr);
+ } else {
+ android.util.Log.i(normalizeTag(tag), message);
+ }
+ }
+
+ /**
+ * Sends a {@link android.util.Log#WARN} log message.
+ *
+ * @param tag Used to identify the source of a log message. Might be modified in the output
+ * (see {@link #normalizeTag(String)})
+ * @param messageTemplate The message you would like logged. It is to be specified as a format
+ * string.
+ * @param args Arguments referenced by the format specifiers in the format string. If the last
+ * one is a {@link Throwable}, its trace will be printed.
+ */
+ @VisibleForTesting
+ public static void w(String tag, String messageTemplate, Object... args) {
+ String message = formatLog(messageTemplate, args);
+ Throwable tr = getThrowableToLog(args);
+ if (tr != null) {
+ android.util.Log.w(normalizeTag(tag), message, tr);
+ } else {
+ android.util.Log.w(normalizeTag(tag), message);
+ }
+ }
+
+ /**
+ * Sends an {@link android.util.Log#ERROR} log message.
+ *
+ * @param tag Used to identify the source of a log message. Might be modified in the output
+ * (see {@link #normalizeTag(String)})
+ * @param messageTemplate The message you would like logged. It is to be specified as a format
+ * string.
+ * @param args Arguments referenced by the format specifiers in the format string. If the last
+ * one is a {@link Throwable}, its trace will be printed.
+ */
+ @VisibleForTesting
+ public static void e(String tag, String messageTemplate, Object... args) {
+ String message = formatLog(messageTemplate, args);
+ Throwable tr = getThrowableToLog(args);
+ if (tr != null) {
+ android.util.Log.e(normalizeTag(tag), message, tr);
+ } else {
+ android.util.Log.e(normalizeTag(tag), message);
+ }
+ }
+
+ /**
+ * What a Terrible Failure: Used for conditions that should never happen, and logged at
+ * the {@link android.util.Log#ASSERT} level. Depending on the configuration, it might
+ * terminate the process.
+ *
+ * @see android.util.Log#wtf(String, String, Throwable)
+ *
+ * @param tag Used to identify the source of a log message. Might be modified in the output
+ * (see {@link #normalizeTag(String)})
+ * @param messageTemplate The message you would like logged. It is to be specified as a format
+ * string.
+ * @param args Arguments referenced by the format specifiers in the format string. If the last
+ * one is a {@link Throwable}, its trace will be printed.
+ */
+ @VisibleForTesting
+ public static void wtf(String tag, String messageTemplate, Object... args) {
+ String message = formatLog(messageTemplate, args);
+ Throwable tr = getThrowableToLog(args);
+ if (tr != null) {
+ android.util.Log.wtf(normalizeTag(tag), message, tr);
+ } else {
+ android.util.Log.wtf(normalizeTag(tag), message);
+ }
+ }
+
+ /** Handy function to get a loggable stack trace from a Throwable. */
+ public static String getStackTraceString(Throwable tr) {
+ return android.util.Log.getStackTraceString(tr);
+ }
+
+ private static Throwable getThrowableToLog(Object[] args) {
+ if (args == null || args.length == 0) return null;
+
+ Object lastArg = args[args.length - 1];
+
+ if (!(lastArg instanceof Throwable)) return null;
+ return (Throwable) lastArg;
+ }
+
+ /** Returns a string form of the origin of the log call, to be used as secondary tag.*/
+ private static String getCallOrigin() {
+ StackTraceElement[] st = Thread.currentThread().getStackTrace();
+
+ // The call stack should look like:
+ // n [a variable number of calls depending on the vm used]
+ // +0 getCallOrigin()
+ // +1 privateLogFunction: verbose or debug
+ // +2 formatLogWithStack()
+ // +3 logFunction: v or d
+ // +4 caller
+
+ int callerStackIndex;
+ String logClassName = Log.class.getName();
+ for (callerStackIndex = 0; callerStackIndex < st.length; callerStackIndex++) {
+ if (st[callerStackIndex].getClassName().equals(logClassName)) {
+ callerStackIndex += 4;
+ break;
+ }
+ }
+
+ return st[callerStackIndex].getFileName() + ":" + st[callerStackIndex].getLineNumber();
+ }
+}
diff --git a/base/android/java/src/org/chromium/base/PackageUtils.java b/base/android/java/src/org/chromium/base/PackageUtils.java
new file mode 100644
index 0000000000..ab554cdc45
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PackageUtils.java
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+
+/**
+ * This class provides package checking related methods.
+ */
+public class PackageUtils {
+ /**
+ * Retrieves the version of the given package installed on the device.
+ *
+ * @param context Any context.
+ * @param packageName Name of the package to find.
+ * @return The package's version code if found, -1 otherwise.
+ */
+ public static int getPackageVersion(Context context, String packageName) {
+ int versionCode = -1;
+ PackageManager pm = context.getPackageManager();
+ try {
+ PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+ if (packageInfo != null) versionCode = packageInfo.versionCode;
+ } catch (PackageManager.NameNotFoundException e) {
+ // Do nothing, versionCode stays -1
+ }
+ return versionCode;
+ }
+
+ private PackageUtils() {
+ // Hide constructor
+ }
+}
diff --git a/base/android/java/src/org/chromium/base/VisibleForTesting.java b/base/android/java/src/org/chromium/base/VisibleForTesting.java
new file mode 100644
index 0000000000..24cbfadfaa
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/VisibleForTesting.java
@@ -0,0 +1,12 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * Annotation used to mark code that has wider visibility or present for testing code.
+ */
+public @interface VisibleForTesting {
+
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
new file mode 100644
index 0000000000..6df7c11027
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
@@ -0,0 +1,20 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @AccessedByNative is used to ensure proguard will keep this field, since it's
+ * only accessed by native.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.CLASS)
+public @interface AccessedByNative {
+ public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/CalledByNative.java b/base/android/java/src/org/chromium/base/annotations/CalledByNative.java
new file mode 100644
index 0000000000..94ef3fab48
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/CalledByNative.java
@@ -0,0 +1,23 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @CalledByNative is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface CalledByNative {
+ /*
+ * If present, tells which inner class the method belongs to.
+ */
+ public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
new file mode 100644
index 0000000000..c0abcbe649
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
@@ -0,0 +1,27 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @CalledByNativeUnchecked is used to generate JNI bindings that do not check for exceptions.
+ * It only makes sense to use this annotation on methods that declare a throws... spec.
+ * However, note that the exception received native side maybe an 'unchecked' (RuntimeExpception)
+ * such as NullPointerException, so the native code should differentiate these cases.
+ * Usage of this should be very rare; where possible handle exceptions in the Java side and use a
+ * return value to indicate success / failure.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface CalledByNativeUnchecked {
+ /*
+ * If present, tells which inner class the method belongs to.
+ */
+ public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java b/base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java
new file mode 100644
index 0000000000..f1bf85ef4b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/JNIAdditionalImport.java
@@ -0,0 +1,35 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JNIAdditionalImport is used by the JNI generator to qualify inner types used on JNI methods. Must
+ * be used when an inner class is used from a class within the same package. Example:
+ *
+ * <pre>
+ * @JNIAdditionImport(Foo.class)
+ * public class Bar {
+ * @CalledByNative static void doSomethingWithInner(Foo.Inner inner) {
+ * ...
+ * }
+ * }
+ * <pre>
+ * <p>
+ * Notes:
+ * 1) Foo must be in the same package as Bar
+ * 2) For classes in different packages, they should be imported as:
+ * import other.package.Foo;
+ * and this annotation should not be used.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface JNIAdditionalImport {
+ Class<?>[] value();
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/JNINamespace.java b/base/android/java/src/org/chromium/base/annotations/JNINamespace.java
new file mode 100644
index 0000000000..4cd5531fae
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/JNINamespace.java
@@ -0,0 +1,20 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @JNINamespace is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code using the specified namespace.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JNINamespace {
+ public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/MainDex.java b/base/android/java/src/org/chromium/base/annotations/MainDex.java
new file mode 100644
index 0000000000..0b35ade8ee
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/MainDex.java
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation that signals that a class should be kept in the main dex file.
+ *
+ * This generally means it's used by renderer processes, which can't load secondary dexes
+ * on K and below.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface MainDex {
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/NativeCall.java b/base/android/java/src/org/chromium/base/annotations/NativeCall.java
new file mode 100644
index 0000000000..b69cd17e25
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/NativeCall.java
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeCall is used by the JNI generator to create the necessary JNI bindings
+ * so a native function can be bound to a Java inner class. The native class for
+ * which the JNI method will be generated is specified by the first parameter.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface NativeCall {
+ /*
+ * Value determines which native class the method should map to.
+ */
+ public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java b/base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java
new file mode 100644
index 0000000000..afbc36854e
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/NativeClassQualifiedName.java
@@ -0,0 +1,25 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeClassQualifiedName is used by the JNI generator to create the necessary JNI
+ * bindings to call into the specified native class name.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NativeClassQualifiedName {
+ /*
+ * Tells which native class the method is going to be bound to.
+ * The first parameter of the annotated method must be an int nativePtr pointing to
+ * an instance of this class.
+ */
+ public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java b/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java
new file mode 100644
index 0000000000..2191334a4d
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/RemovableInRelease.java
@@ -0,0 +1,18 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * The annotated function can be removed in release builds.
+ *
+ * Calls to this function will be removed if its return value is not used. If all calls are removed,
+ * the function definition itself will be candidate for removal.
+ * It works by indicating to Proguard that the function has no side effects.
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface RemovableInRelease {}
diff --git a/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java b/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
new file mode 100644
index 0000000000..89068ac941
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
@@ -0,0 +1,20 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * @SuppressFBWarnings is used to suppress FindBugs warnings.
+ *
+ * The long name of FindBugs warnings can be found at
+ * http://findbugs.sourceforge.net/bugDescriptions.html
+ */
+@Retention(RetentionPolicy.CLASS)
+public @interface SuppressFBWarnings {
+ String[] value() default {};
+ String justification() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
new file mode 100644
index 0000000000..a2af704e0c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
@@ -0,0 +1,24 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used for marking methods and fields that are called by reflection.
+ * Useful for keeping components that would otherwise be removed by Proguard.
+ * Use the value parameter to mention a file that calls this method.
+ *
+ * Note that adding this annotation to a method is not enough to guarantee that
+ * it is kept - either its class must be referenced elsewhere in the program, or
+ * the class must be annotated with this as well.
+ */
+@Target({
+ ElementType.METHOD, ElementType.FIELD, ElementType.TYPE,
+ ElementType.CONSTRUCTOR })
+public @interface UsedByReflection {
+ String value();
+}