summaryrefslogtreecommitdiff
path: root/android/util
diff options
context:
space:
mode:
authorJustin Klaassen <justinklaassen@google.com>2017-11-30 18:18:21 -0500
committerJustin Klaassen <justinklaassen@google.com>2017-11-30 18:18:21 -0500
commit4217cf85c20565a3446a662a7f07f26137b26b7f (patch)
treea0417b47a8cc802f6642f369fd2371165bec7b5c /android/util
parent6a65f2da209bff03cb0eb6da309710ac6ee5026d (diff)
downloadandroid-28-4217cf85c20565a3446a662a7f07f26137b26b7f.tar.gz
Import Android SDK Platform P [4477446]
/google/data/ro/projects/android/fetch_artifact \ --bid 4477446 \ --target sdk_phone_armv7-win_sdk \ sdk-repo-linux-sources-4477446.zip AndroidVersion.ApiLevel has been modified to appear as 28 Change-Id: If0559643d7c328e36aafca98f0c114641d33642c
Diffstat (limited to 'android/util')
-rw-r--r--android/util/AndroidException.java6
-rw-r--r--android/util/FeatureFlagUtils.java22
-rw-r--r--android/util/Log.java295
-rw-r--r--android/util/StatsManager.java13
-rw-r--r--android/util/proto/ProtoUtils.java12
5 files changed, 320 insertions, 28 deletions
diff --git a/android/util/AndroidException.java b/android/util/AndroidException.java
index dfe00c9b..1345ddf1 100644
--- a/android/util/AndroidException.java
+++ b/android/util/AndroidException.java
@@ -34,5 +34,11 @@ public class AndroidException extends Exception {
public AndroidException(Exception cause) {
super(cause);
}
+
+ /** @hide */
+ protected AndroidException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
};
diff --git a/android/util/FeatureFlagUtils.java b/android/util/FeatureFlagUtils.java
index 2a272208..29baea17 100644
--- a/android/util/FeatureFlagUtils.java
+++ b/android/util/FeatureFlagUtils.java
@@ -18,6 +18,7 @@ package android.util;
import android.content.Context;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.text.TextUtils;
import java.util.Map;
@@ -39,13 +40,24 @@ public class FeatureFlagUtils {
* @return true if the flag is enabled (either by default in system, or override by user)
*/
public static boolean isEnabled(Context context, String feature) {
- // Tries to get feature flag from system property.
- // Step 1: check if feature flag has any override. Flag name: sys.fflag.override.<feature>
- String value = SystemProperties.get(FFLAG_OVERRIDE_PREFIX + feature);
+ // Override precedence:
+ // Settings.Global -> sys.fflag.override.* -> sys.fflag.*
+
+ // Step 1: check if feature flag is set in Settings.Global.
+ String value;
+ if (context != null) {
+ value = Settings.Global.getString(context.getContentResolver(), feature);
+ if (!TextUtils.isEmpty(value)) {
+ return Boolean.parseBoolean(value);
+ }
+ }
+
+ // Step 2: check if feature flag has any override. Flag name: sys.fflag.override.<feature>
+ value = SystemProperties.get(FFLAG_OVERRIDE_PREFIX + feature);
if (!TextUtils.isEmpty(value)) {
return Boolean.parseBoolean(value);
}
- // Step 2: check if feature flag has any default value. Flag name: sys.fflag.<feature>
+ // Step 3: check if feature flag has any default value. Flag name: sys.fflag.<feature>
value = SystemProperties.get(FFLAG_PREFIX + feature);
return Boolean.parseBoolean(value);
}
@@ -53,7 +65,7 @@ public class FeatureFlagUtils {
/**
* Override feature flag to new state.
*/
- public static void setEnabled(String feature, boolean enabled) {
+ public static void setEnabled(Context context, String feature, boolean enabled) {
SystemProperties.set(FFLAG_OVERRIDE_PREFIX + feature, enabled ? "true" : "false");
}
diff --git a/android/util/Log.java b/android/util/Log.java
index b94e48b3..02998653 100644
--- a/android/util/Log.java
+++ b/android/util/Log.java
@@ -16,12 +16,45 @@
package android.util;
+import android.os.DeadSystemException;
+
+import com.android.internal.os.RuntimeInit;
+import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.LineBreakBufferedWriter;
+
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.io.Writer;
import java.net.UnknownHostException;
/**
- * Mock Log implementation for testing on non android host.
+ * API for sending log output.
+ *
+ * <p>Generally, you should use the {@link #v Log.v()}, {@link #d Log.d()},
+ * {@link #i Log.i()}, {@link #w Log.w()}, and {@link #e Log.e()} methods to write logs.
+ * You can then <a href="{@docRoot}studio/debug/am-logcat.html">view the logs in logcat</a>.
+ *
+ * <p>The order in terms of verbosity, from least to most is
+ * ERROR, WARN, INFO, DEBUG, VERBOSE. Verbose should never be compiled
+ * into an application except during development. Debug logs are compiled
+ * in but stripped at runtime. Error, warning and info logs are always kept.
+ *
+ * <p><b>Tip:</b> A good convention is to declare a <code>TAG</code> constant
+ * in your class:
+ *
+ * <pre>private static final String TAG = "MyActivity";</pre>
+ *
+ * and use that in subsequent calls to the log methods.
+ * </p>
+ *
+ * <p><b>Tip:</b> Don't forget that when you make a call like
+ * <pre>Log.v(TAG, "index=" + i);</pre>
+ * that when you're building the string to pass into Log.d, the compiler uses a
+ * StringBuilder and at least three allocations occur: the StringBuilder
+ * itself, the buffer, and the String object. Realistically, there is also
+ * another buffer allocation and copy, and even more pressure on the gc.
+ * That means that if your log message is filtered out, you might be doing
+ * significant work and incurring significant overhead.
*/
public final class Log {
@@ -55,6 +88,29 @@ public final class Log {
*/
public static final int ASSERT = 7;
+ /**
+ * Exception class used to capture a stack trace in {@link #wtf}.
+ * @hide
+ */
+ public static class TerribleFailure extends Exception {
+ TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
+ }
+
+ /**
+ * Interface to handle terrible failures from {@link #wtf}.
+ *
+ * @hide
+ */
+ public interface TerribleFailureHandler {
+ void onTerribleFailure(String tag, TerribleFailure what, boolean system);
+ }
+
+ private static TerribleFailureHandler sWtfHandler = new TerribleFailureHandler() {
+ public void onTerribleFailure(String tag, TerribleFailure what, boolean system) {
+ RuntimeInit.wtf(tag, what, system);
+ }
+ };
+
private Log() {
}
@@ -65,7 +121,7 @@ public final class Log {
* @param msg The message you would like logged.
*/
public static int v(String tag, String msg) {
- return println(LOG_ID_MAIN, VERBOSE, tag, msg);
+ return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
/**
@@ -76,7 +132,7 @@ public final class Log {
* @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));
+ return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr);
}
/**
@@ -86,7 +142,7 @@ public final class Log {
* @param msg The message you would like logged.
*/
public static int d(String tag, String msg) {
- return println(LOG_ID_MAIN, DEBUG, tag, msg);
+ return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
}
/**
@@ -97,7 +153,7 @@ public final class Log {
* @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));
+ return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr);
}
/**
@@ -107,7 +163,7 @@ public final class Log {
* @param msg The message you would like logged.
*/
public static int i(String tag, String msg) {
- return println(LOG_ID_MAIN, INFO, tag, msg);
+ return println_native(LOG_ID_MAIN, INFO, tag, msg);
}
/**
@@ -118,7 +174,7 @@ public final class Log {
* @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));
+ return printlns(LOG_ID_MAIN, INFO, tag, msg, tr);
}
/**
@@ -128,7 +184,7 @@ public final class Log {
* @param msg The message you would like logged.
*/
public static int w(String tag, String msg) {
- return println(LOG_ID_MAIN, WARN, tag, msg);
+ return println_native(LOG_ID_MAIN, WARN, tag, msg);
}
/**
@@ -139,9 +195,31 @@ public final class Log {
* @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));
+ return printlns(LOG_ID_MAIN, WARN, tag, msg, tr);
}
+ /**
+ * Checks to see whether or not a log for the specified tag is loggable at the specified level.
+ *
+ * The default level of any tag is set to INFO. This means that any level above and including
+ * INFO will be logged. Before you make any calls to a logging method you should check to see
+ * if your tag should be logged. You can change the default level by setting a system property:
+ * 'setprop log.tag.&lt;YOUR_LOG_TAG> &lt;LEVEL>'
+ * Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
+ * turn off all logging for your tag. You can also create a local.prop file that with the
+ * following in it:
+ * 'log.tag.&lt;YOUR_LOG_TAG>=&lt;LEVEL>'
+ * and place that in /data/local.prop.
+ *
+ * @param tag The tag to check.
+ * @param level The level to check.
+ * @return Whether or not that this is allowed to be logged.
+ * @throws IllegalArgumentException is thrown if the tag.length() > 23
+ * for Nougat (7.0) releases (API <= 23) and prior, there is no
+ * tag limit of concern after this API level.
+ */
+ public static native boolean isLoggable(String tag, int level);
+
/*
* Send a {@link #WARN} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
@@ -149,7 +227,7 @@ public final class Log {
* @param tr An exception to log
*/
public static int w(String tag, Throwable tr) {
- return println(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
+ return printlns(LOG_ID_MAIN, WARN, tag, "", tr);
}
/**
@@ -159,7 +237,7 @@ public final class Log {
* @param msg The message you would like logged.
*/
public static int e(String tag, String msg) {
- return println(LOG_ID_MAIN, ERROR, tag, msg);
+ return println_native(LOG_ID_MAIN, ERROR, tag, msg);
}
/**
@@ -170,7 +248,82 @@ public final class Log {
* @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));
+ return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr);
+ }
+
+ /**
+ * What a Terrible Failure: Report a condition that should never happen.
+ * The error will always be logged at level ASSERT with the call stack.
+ * Depending on system configuration, a report may be added to the
+ * {@link android.os.DropBoxManager} and/or the process may be terminated
+ * immediately with an error dialog.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ */
+ public static int wtf(String tag, String msg) {
+ return wtf(LOG_ID_MAIN, tag, msg, null, false, false);
+ }
+
+ /**
+ * Like {@link #wtf(String, String)}, but also writes to the log the full
+ * call stack.
+ * @hide
+ */
+ public static int wtfStack(String tag, String msg) {
+ return wtf(LOG_ID_MAIN, tag, msg, null, true, false);
+ }
+
+ /**
+ * What a Terrible Failure: Report an exception that should never happen.
+ * Similar to {@link #wtf(String, String)}, with an exception to log.
+ * @param tag Used to identify the source of a log message.
+ * @param tr An exception to log.
+ */
+ public static int wtf(String tag, Throwable tr) {
+ return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false, false);
+ }
+
+ /**
+ * What a Terrible Failure: Report an exception that should never happen.
+ * Similar to {@link #wtf(String, Throwable)}, with a message as well.
+ * @param tag Used to identify the source of a log message.
+ * @param msg The message you would like logged.
+ * @param tr An exception to log. May be null.
+ */
+ public static int wtf(String tag, String msg, Throwable tr) {
+ return wtf(LOG_ID_MAIN, tag, msg, tr, false, false);
+ }
+
+ static int wtf(int logId, String tag, String msg, Throwable tr, boolean localStack,
+ boolean system) {
+ TerribleFailure what = new TerribleFailure(msg, tr);
+ // Only mark this as ERROR, do not use ASSERT since that should be
+ // reserved for cases where the system is guaranteed to abort.
+ // The onTerribleFailure call does not always cause a crash.
+ int bytes = printlns(logId, ERROR, tag, msg, localStack ? what : tr);
+ sWtfHandler.onTerribleFailure(tag, what, system);
+ return bytes;
+ }
+
+ static void wtfQuiet(int logId, String tag, String msg, boolean system) {
+ TerribleFailure what = new TerribleFailure(msg, null);
+ sWtfHandler.onTerribleFailure(tag, what, system);
+ }
+
+ /**
+ * Sets the terrible failure handler, for testing.
+ *
+ * @return the old handler
+ *
+ * @hide
+ */
+ public static TerribleFailureHandler setWtfHandler(TerribleFailureHandler handler) {
+ if (handler == null) {
+ throw new NullPointerException("handler == null");
+ }
+ TerribleFailureHandler oldHandler = sWtfHandler;
+ sWtfHandler = handler;
+ return oldHandler;
}
/**
@@ -193,7 +346,7 @@ public final class Log {
}
StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
+ PrintWriter pw = new FastPrintWriter(sw, false, 256);
tr.printStackTrace(pw);
pw.flush();
return sw.toString();
@@ -208,7 +361,7 @@ public final class Log {
* @return The number of bytes written.
*/
public static int println(int priority, String tag, String msg) {
- return println(LOG_ID_MAIN, priority, tag, msg);
+ return println_native(LOG_ID_MAIN, priority, tag, msg);
}
/** @hide */ public static final int LOG_ID_MAIN = 0;
@@ -217,9 +370,115 @@ public final class Log {
/** @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;
+ /** @hide */ public static native int println_native(int bufID,
+ int priority, String tag, String msg);
+
+ /**
+ * Return the maximum payload the log daemon accepts without truncation.
+ * @return LOGGER_ENTRY_MAX_PAYLOAD.
+ */
+ private static native int logger_entry_max_payload_native();
+
+ /**
+ * Helper function for long messages. Uses the LineBreakBufferedWriter to break
+ * up long messages and stacktraces along newlines, but tries to write in large
+ * chunks. This is to avoid truncation.
+ * @hide
+ */
+ public static int printlns(int bufID, int priority, String tag, String msg,
+ Throwable tr) {
+ ImmediateLogWriter logWriter = new ImmediateLogWriter(bufID, priority, tag);
+ // Acceptable buffer size. Get the native buffer size, subtract two zero terminators,
+ // and the length of the tag.
+ // Note: we implicitly accept possible truncation for Modified-UTF8 differences. It
+ // is too expensive to compute that ahead of time.
+ int bufferSize = PreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD // Base.
+ - 2 // Two terminators.
+ - (tag != null ? tag.length() : 0) // Tag length.
+ - 32; // Some slack.
+ // At least assume you can print *some* characters (tag is not too large).
+ bufferSize = Math.max(bufferSize, 100);
+
+ LineBreakBufferedWriter lbbw = new LineBreakBufferedWriter(logWriter, bufferSize);
+
+ lbbw.println(msg);
+
+ if (tr != null) {
+ // 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) {
+ break;
+ }
+ if (t instanceof DeadSystemException) {
+ lbbw.println("DeadSystemException: The system died; "
+ + "earlier logs will point to the root cause");
+ break;
+ }
+ t = t.getCause();
+ }
+ if (t == null) {
+ tr.printStackTrace(lbbw);
+ }
+ }
+
+ lbbw.flush();
+
+ return logWriter.getWritten();
+ }
+
+ /**
+ * PreloadHelper class. Caches the LOGGER_ENTRY_MAX_PAYLOAD value to avoid
+ * a JNI call during logging.
+ */
+ static class PreloadHolder {
+ public final static int LOGGER_ENTRY_MAX_PAYLOAD =
+ logger_entry_max_payload_native();
+ }
+
+ /**
+ * Helper class to write to the logcat. Different from LogWriter, this writes
+ * the whole given buffer and does not break along newlines.
+ */
+ private static class ImmediateLogWriter extends Writer {
+
+ private int bufID;
+ private int priority;
+ private String tag;
+
+ private int written = 0;
+
+ /**
+ * Create a writer that immediately writes to the log, using the given
+ * parameters.
+ */
+ public ImmediateLogWriter(int bufID, int priority, String tag) {
+ this.bufID = bufID;
+ this.priority = priority;
+ this.tag = tag;
+ }
+
+ public int getWritten() {
+ return written;
+ }
+
+ @Override
+ public void write(char[] cbuf, int off, int len) {
+ // Note: using String here has a bit of overhead as a Java object is created,
+ // but using the char[] directly is not easier, as it needs to be translated
+ // to a C char[] for logging.
+ written += println_native(bufID, priority, tag, new String(cbuf, off, len));
+ }
+
+ @Override
+ public void flush() {
+ // Ignored.
+ }
+
+ @Override
+ public void close() {
+ // Ignored.
+ }
}
}
diff --git a/android/util/StatsManager.java b/android/util/StatsManager.java
index 55b33a61..2bcd863c 100644
--- a/android/util/StatsManager.java
+++ b/android/util/StatsManager.java
@@ -58,11 +58,12 @@ public final class StatsManager {
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- throw new RuntimeException("StatsD service connection lost");
+ Slog.d(TAG, "Failed to find statsd when adding configuration");
+ return false;
}
return service.addConfiguration(configKey, config, pkg, cls);
} catch (RemoteException e) {
- Slog.d(TAG, "Failed to connect to statsd when getting data");
+ Slog.d(TAG, "Failed to connect to statsd when adding configuration");
return false;
}
}
@@ -80,11 +81,12 @@ public final class StatsManager {
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- throw new RuntimeException("StatsD service connection lost");
+ Slog.d(TAG, "Failed to find statsd when removing configuration");
+ return false;
}
return service.removeConfiguration(configKey);
} catch (RemoteException e) {
- Slog.d(TAG, "Failed to connect to statsd when getting data");
+ Slog.d(TAG, "Failed to connect to statsd when removing configuration");
return false;
}
}
@@ -102,7 +104,8 @@ public final class StatsManager {
try {
IStatsManager service = getIStatsManagerLocked();
if (service == null) {
- throw new RuntimeException("StatsD service connection lost");
+ Slog.d(TAG, "Failed to find statsd when getting data");
+ return null;
}
return service.getData(configKey);
} catch (RemoteException e) {
diff --git a/android/util/proto/ProtoUtils.java b/android/util/proto/ProtoUtils.java
index 449baca5..85b7ec82 100644
--- a/android/util/proto/ProtoUtils.java
+++ b/android/util/proto/ProtoUtils.java
@@ -17,6 +17,7 @@
package android.util.proto;
import android.util.AggStats;
+import android.util.Duration;
/**
* This class contains a list of helper functions to write common proto in
@@ -36,4 +37,15 @@ public class ProtoUtils {
proto.write(AggStats.MAX, max);
proto.end(aggStatsToken);
}
+
+ /**
+ * Dump Duration to ProtoOutputStream
+ * @hide
+ */
+ public static void toDuration(ProtoOutputStream proto, long fieldId, long startMs, long endMs) {
+ final long token = proto.start(fieldId);
+ proto.write(Duration.START_MS, startMs);
+ proto.write(Duration.END_MS, endMs);
+ proto.end(token);
+ }
}