diff options
52 files changed, 789 insertions, 235 deletions
diff --git a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java index f31e9c154f15..b753006e193e 100644 --- a/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java +++ b/apct-tests/perftests/core/src/android/libcore/regression/CharsetUtf8PerfTest.java @@ -37,9 +37,7 @@ import java.nio.charset.Charset; public class CharsetUtf8PerfTest { @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - private final int mNoOfBytes = 0x100; // 4MB - - private void makeUnicodeRange(int startingCodePoint, int endingCodePoint, int repeated) { + private void makeUnicodeRange(int startingCodePoint, int endingCodePoint) { StringBuilder builder = new StringBuilder(); for (int codePoint = startingCodePoint; codePoint <= endingCodePoint; codePoint++) { if (codePoint < Character.MIN_SURROGATE || codePoint > Character.MAX_SURROGATE) { @@ -48,35 +46,30 @@ public class CharsetUtf8PerfTest { } String str = builder.toString(); - StringBuilder builder2 = new StringBuilder(); BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - for (int i = 0; i < repeated; i++) { - builder2.append(str); - } + StringBuilder builder2 = new StringBuilder(); + builder2.append(str); } } @Test public void time_ascii() { - makeUnicodeRange(0, 0x7f, mNoOfBytes / 0x80); + makeUnicodeRange(0, 0x7f); } @Test public void time_bmp2() { - makeUnicodeRange(0x0080, 0x07ff, mNoOfBytes / 2 / 0x780); + makeUnicodeRange(0x0080, 0x07ff); } @Test public void time_bmp3() { - makeUnicodeRange( - 0x0800, - 0xffff, - mNoOfBytes / 3 / 0xf000 /* 0x10000 - 0x0800 - no of surrogate code points */); + makeUnicodeRange(0x0800, 0xffff); } @Test public void time_supplementary() { - makeUnicodeRange(0x10000, 0x10ffff, mNoOfBytes / 4 / 0x100000); + makeUnicodeRange(0x10000, 0x10ffff); } } diff --git a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java index e3691a783bd6..76656bd67afa 100644 --- a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java +++ b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java @@ -52,19 +52,39 @@ public class FastDataPerfTest { while (state.keepRunning()) { os.reset(); final BufferedOutputStream bos = new BufferedOutputStream(os, BUFFER_SIZE); - final DataOutput out = new DataOutputStream(bos); - doWrite(out); - bos.flush(); + final DataOutputStream out = new DataOutputStream(bos); + try { + doWrite(out); + out.flush(); + } finally { + out.close(); + } + } + } + + @Test + public void timeWrite_LocalUsing4ByteSequences() throws IOException { + final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + os.reset(); + final FastDataOutput out = FastDataOutput.obtainUsing4ByteSequences(os); + try { + doWrite(out); + out.flush(); + } finally { + out.release(); + } } } @Test - public void timeWrite_Local() throws IOException { + public void timeWrite_LocalUsing3ByteSequences() throws IOException { final ByteArrayOutputStream os = new ByteArrayOutputStream(OUTPUT_SIZE); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { os.reset(); - final FastDataOutput out = FastDataOutput.obtain(os); + final FastDataOutput out = FastDataOutput.obtainUsing3ByteSequences(os); try { doWrite(out); out.flush(); @@ -81,19 +101,42 @@ public class FastDataPerfTest { while (state.keepRunning()) { is.reset(); final BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE); - final DataInput in = new DataInputStream(bis); - doRead(in); + final DataInputStream in = new DataInputStream(bis); + try { + doRead(in); + } finally { + in.close(); + } + } + } + + @Test + public void timeRead_LocalUsing4ByteSequences() throws Exception { + final ByteArrayInputStream is = new ByteArrayInputStream(doWrite()); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + is.reset(); + final FastDataInput in = FastDataInput.obtainUsing4ByteSequences(is); + try { + doRead(in); + } finally { + in.release(); + } } } @Test - public void timeRead_Local() throws Exception { + public void timeRead_LocalUsing3ByteSequences() throws Exception { final ByteArrayInputStream is = new ByteArrayInputStream(doWrite()); final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { is.reset(); - final DataInput in = new FastDataInput(is, BUFFER_SIZE); - doRead(in); + final FastDataInput in = FastDataInput.obtainUsing3ByteSequences(is); + try { + doRead(in); + } finally { + in.release(); + } } } diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp index fbb99d2aea89..836801deaa08 100644 --- a/cmds/incidentd/src/IncidentService.cpp +++ b/cmds/incidentd/src/IncidentService.cpp @@ -47,10 +47,16 @@ enum { #define DEFAULT_REFACTORY_PERIOD_MS (24 * 60 * 60 * 1000) // 1 Day // Skip these sections (for dumpstate only) -// Skip logs (1100 - 1108) and traces (1200 - 1202) because they are already in the bug report. +// Skip logs (1100 - 1108), traces (1200 - 1202), dumpsys (3000 - 3024, 3027 - 3056, 4000 - 4001) +// because they are already in the bug report. #define SKIPPED_DUMPSTATE_SECTIONS { \ 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, /* Logs */ \ - 1200, 1201, 1202, /* Native, hal, java traces */ } + 1200, 1201, 1202, /* Native, hal, java traces */ \ + 3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 3011, 3012, 3013, \ + 3014, 3015, 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, 3024, 3027, 3028, 3029, \ + 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043, \ + 3044, 3045, 3046, 3047, 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, 3056, 4000, \ + 4001, /* Dumpsys */ } namespace android { namespace os { diff --git a/core/api/current.txt b/core/api/current.txt index 6d3b493d3943..584c67f288c1 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -31118,7 +31118,7 @@ package android.os { method @Deprecated public static void changeDebugPort(int); method public static void dumpHprofData(String) throws java.io.IOException; method public static boolean dumpService(String, java.io.FileDescriptor, String[]); - method public static void enableEmulatorTraceOutput(); + method @Deprecated public static void enableEmulatorTraceOutput(); method public static int getBinderDeathObjectCount(); method public static int getBinderLocalObjectCount(); method public static int getBinderProxyObjectCount(); diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index b4930fa931eb..399f11b0f2a7 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -1155,6 +1155,8 @@ public final class Debug * consequences. * * To temporarily enable tracing, use {@link #startNativeTracing()}. + * + * @deprecated Please use other tracing method in this class. */ public static void enableEmulatorTraceOutput() { Log.w(TAG, "Unimplemented"); diff --git a/core/java/android/util/CharsetUtils.java b/core/java/android/util/CharsetUtils.java index fa146675b8d1..3b08c3b6d52f 100644 --- a/core/java/android/util/CharsetUtils.java +++ b/core/java/android/util/CharsetUtils.java @@ -26,6 +26,12 @@ import dalvik.annotation.optimization.FastNative; * <p> * These methods purposefully accept only non-movable byte array addresses to * avoid extra JNI overhead. + * <p> + * Callers are cautioned that there is a long-standing ART bug that emits + * non-standard 4-byte sequences, as described by {@code kUtfUse4ByteSequence} + * in {@code art/runtime/jni/jni_internal.cc}. If precise modified UTF-8 + * encoding is required, use {@link com.android.internal.util.ModifiedUtf8} + * instead. * * @hide */ @@ -33,6 +39,12 @@ public class CharsetUtils { /** * Attempt to encode the given string as modified UTF-8 into the destination * byte array without making any new allocations. + * <p> + * Callers are cautioned that there is a long-standing ART bug that emits + * non-standard 4-byte sequences, as described by + * {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}. + * If precise modified UTF-8 encoding is required, use + * {@link com.android.internal.util.ModifiedUtf8} instead. * * @param src string value to be encoded * @param dest destination byte array to encode into @@ -50,6 +62,12 @@ public class CharsetUtils { /** * Attempt to encode the given string as modified UTF-8 into the destination * byte array without making any new allocations. + * <p> + * Callers are cautioned that there is a long-standing ART bug that emits + * non-standard 4-byte sequences, as described by + * {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}. + * If precise modified UTF-8 encoding is required, use + * {@link com.android.internal.util.ModifiedUtf8} instead. * * @param src string value to be encoded * @param srcLen exact length of string to be encoded @@ -66,6 +84,12 @@ public class CharsetUtils { /** * Attempt to decode a modified UTF-8 string from the source byte array. + * <p> + * Callers are cautioned that there is a long-standing ART bug that emits + * non-standard 4-byte sequences, as described by + * {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}. + * If precise modified UTF-8 encoding is required, use + * {@link com.android.internal.util.ModifiedUtf8} instead. * * @param src source byte array to decode from * @param srcOff offset into source where decoding should begin diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java index b5fe4f58dfb2..f1e91d0234e4 100644 --- a/core/java/android/util/Log.java +++ b/core/java/android/util/Log.java @@ -66,6 +66,10 @@ import java.net.UnknownHostException; * <p>When calling the log methods that take a Throwable parameter, * if any of the throwables in the cause chain is an <code>UnknownHostException</code>, * then the stack trace is not logged. + * + * <p>Note: The return value from the logging functions in this class may vary between Android + * releases due to changes in the logging implementation. For the methods that return an integer, + * a positive value may be considered as a successful invocation. */ public final class Log { /** @hide */ @@ -134,6 +138,7 @@ public final class Log { * @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 A positive value if the message was loggable (see {@link #isLoggable}). */ public static int v(@Nullable String tag, @NonNull String msg) { return println_native(LOG_ID_MAIN, VERBOSE, tag, msg); @@ -144,7 +149,8 @@ public final class Log { * @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 + * @param tr An exception to log. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int v(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) { return printlns(LOG_ID_MAIN, VERBOSE, tag, msg, tr); @@ -155,6 +161,7 @@ public final class Log { * @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 A positive value if the message was loggable (see {@link #isLoggable}). */ public static int d(@Nullable String tag, @NonNull String msg) { return println_native(LOG_ID_MAIN, DEBUG, tag, msg); @@ -165,7 +172,8 @@ public final class Log { * @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 + * @param tr An exception to log. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int d(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) { return printlns(LOG_ID_MAIN, DEBUG, tag, msg, tr); @@ -176,6 +184,7 @@ public final class Log { * @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 A positive value if the message was loggable (see {@link #isLoggable}). */ public static int i(@Nullable String tag, @NonNull String msg) { return println_native(LOG_ID_MAIN, INFO, tag, msg); @@ -186,7 +195,7 @@ public final class Log { * @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 + * @param tr An exception to log. */ public static int i(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) { return printlns(LOG_ID_MAIN, INFO, tag, msg, tr); @@ -197,6 +206,7 @@ public final class Log { * @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 A positive value if the message was loggable (see {@link #isLoggable}). */ public static int w(@Nullable String tag, @NonNull String msg) { return println_native(LOG_ID_MAIN, WARN, tag, msg); @@ -207,7 +217,8 @@ public final class Log { * @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 + * @param tr An exception to log. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int w(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) { return printlns(LOG_ID_MAIN, WARN, tag, msg, tr); @@ -239,7 +250,8 @@ public final class Log { * 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 + * @param tr An exception to log. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int w(@Nullable String tag, @Nullable Throwable tr) { return printlns(LOG_ID_MAIN, WARN, tag, "", tr); @@ -250,6 +262,7 @@ public final class Log { * @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 A positive value if the message was loggable (see {@link #isLoggable}). */ public static int e(@Nullable String tag, @NonNull String msg) { return println_native(LOG_ID_MAIN, ERROR, tag, msg); @@ -260,7 +273,8 @@ public final class Log { * @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 + * @param tr An exception to log. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int e(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) { return printlns(LOG_ID_MAIN, ERROR, tag, msg, tr); @@ -274,6 +288,7 @@ public final class Log { * immediately with an error dialog. * @param tag Used to identify the source of a log message. * @param msg The message you would like logged. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int wtf(@Nullable String tag, @Nullable String msg) { return wtf(LOG_ID_MAIN, tag, msg, null, false, false); @@ -293,6 +308,7 @@ public final class Log { * 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. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int wtf(@Nullable String tag, @NonNull Throwable tr) { return wtf(LOG_ID_MAIN, tag, tr.getMessage(), tr, false, false); @@ -304,6 +320,7 @@ public final class Log { * @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. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int wtf(@Nullable String tag, @Nullable String msg, @Nullable Throwable tr) { return wtf(LOG_ID_MAIN, tag, msg, tr, false, false); @@ -348,7 +365,7 @@ public final class Log { * <p>If any of the throwables in the cause chain is an <code>UnknownHostException</code>, * this returns an empty string. - * @param tr An exception to log + * @param tr An exception to log. */ @NonNull public static String getStackTraceString(@Nullable Throwable tr) { @@ -379,7 +396,7 @@ public final class Log { * @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. + * @return A positive value if the message was loggable (see {@link #isLoggable}). */ public static int println(@Level int priority, @Nullable String tag, @NonNull String msg) { return println_native(LOG_ID_MAIN, priority, tag, msg); @@ -391,7 +408,16 @@ public final class Log { /** @hide */ public static final int LOG_ID_SYSTEM = 3; /** @hide */ public static final int LOG_ID_CRASH = 4; - /** @hide */ + /** + * Low-level logging call. + * @param bufID The buffer ID to receive the message. + * @param priority The priority of the 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 A positive value if the message was loggable (see {@link #isLoggable}). + * @hide + */ @UnsupportedAppUsage public static native int println_native(int bufID, int priority, String tag, String msg); @@ -407,6 +433,7 @@ public final class Log { * @param tag Used to identify the source of a log message. It usually identifies * the class or activity where the log call occurs. * @param message The message you would like logged. + * @return A positive value if the message was loggable (see {@link #isLoggable}). * @hide */ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @@ -425,6 +452,7 @@ public final class Log { * 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. + * @return A positive value if the message was loggable (see {@link #isLoggable}). * @hide */ public static int printlns(int bufID, int priority, @Nullable String tag, @NonNull String msg, diff --git a/core/java/android/util/TEST_MAPPING b/core/java/android/util/TEST_MAPPING new file mode 100644 index 000000000000..0ae1c1593366 --- /dev/null +++ b/core/java/android/util/TEST_MAPPING @@ -0,0 +1,28 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.util.CharsetUtilsTest" + }, + { + "include-filter": "com.android.internal.util.FastDataTest" + } + ], + "file_patterns": ["CharsetUtils|FastData"] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.util.XmlTest" + }, + { + "include-filter": "android.util.BinaryXmlTest" + } + ], + "file_patterns": ["Xml"] + } + ] +} diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ba6ba63e4ed0..780e282b30af 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -13202,6 +13202,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Set if view is a heading for a section of content for accessibility purposes. + * <p> + * Users of some accessibility services can choose to navigate between headings + * instead of between paragraphs, words, etc. Apps that provide headings on + * sections of text can help the text navigation experience. * * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. * diff --git a/core/java/com/android/internal/util/BinaryXmlPullParser.java b/core/java/com/android/internal/util/BinaryXmlPullParser.java index 57552f301bd6..d3abac9f8877 100644 --- a/core/java/com/android/internal/util/BinaryXmlPullParser.java +++ b/core/java/com/android/internal/util/BinaryXmlPullParser.java @@ -73,12 +73,6 @@ import java.util.Objects; * </ul> */ public final class BinaryXmlPullParser implements TypedXmlPullParser { - /** - * Default buffer size, which matches {@code FastXmlSerializer}. This should - * be kept in sync with {@link BinaryXmlPullParser}. - */ - private static final int BUFFER_SIZE = 32_768; - private FastDataInput mIn; private int mCurrentToken = START_DOCUMENT; @@ -100,7 +94,12 @@ public final class BinaryXmlPullParser implements TypedXmlPullParser { throw new UnsupportedOperationException(); } - mIn = new FastDataInput(is, BUFFER_SIZE); + if (mIn != null) { + mIn.release(); + mIn = null; + } + + mIn = FastDataInput.obtainUsing4ByteSequences(is); mCurrentToken = START_DOCUMENT; mCurrentDepth = 0; diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java index f0ca1edb0b90..485430a43768 100644 --- a/core/java/com/android/internal/util/BinaryXmlSerializer.java +++ b/core/java/com/android/internal/util/BinaryXmlSerializer.java @@ -91,12 +91,6 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer { static final int TYPE_BOOLEAN_TRUE = 12 << 4; static final int TYPE_BOOLEAN_FALSE = 13 << 4; - /** - * Default buffer size, which matches {@code FastXmlSerializer}. This should - * be kept in sync with {@link BinaryXmlPullParser}. - */ - private static final int BUFFER_SIZE = 32_768; - private FastDataOutput mOut; /** @@ -124,7 +118,7 @@ public final class BinaryXmlSerializer implements TypedXmlSerializer { throw new UnsupportedOperationException(); } - mOut = FastDataOutput.obtain(os); + mOut = FastDataOutput.obtainUsing4ByteSequences(os); mOut.write(PROTOCOL_MAGIC_VERSION_0); mTagCount = 0; diff --git a/core/java/com/android/internal/util/FastDataInput.java b/core/java/com/android/internal/util/FastDataInput.java index f8d241b5ede0..5117034815fc 100644 --- a/core/java/com/android/internal/util/FastDataInput.java +++ b/core/java/com/android/internal/util/FastDataInput.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; /** * Optimized implementation of {@link DataInput} which buffers data in memory @@ -41,13 +42,18 @@ import java.util.Objects; public class FastDataInput implements DataInput, Closeable { private static final int MAX_UNSIGNED_SHORT = 65_535; + private static final int DEFAULT_BUFFER_SIZE = 32_768; + + private static AtomicReference<FastDataInput> sInCache = new AtomicReference<>(); + private final VMRuntime mRuntime; - private final InputStream mIn; private final byte[] mBuffer; private final long mBufferPtr; private final int mBufferCap; + private final boolean mUse4ByteSequence; + private InputStream mIn; private int mBufferPos; private int mBufferLim; @@ -57,7 +63,18 @@ public class FastDataInput implements DataInput, Closeable { private int mStringRefCount = 0; private String[] mStringRefs = new String[32]; + /** + * @deprecated callers must specify {@code use4ByteSequence} so they make a + * clear choice about working around a long-standing ART bug, as + * described by the {@code kUtfUse4ByteSequence} comments in + * {@code art/runtime/jni/jni_internal.cc}. + */ + @Deprecated public FastDataInput(@NonNull InputStream in, int bufferSize) { + this(in, bufferSize, true /* use4ByteSequence */); + } + + public FastDataInput(@NonNull InputStream in, int bufferSize, boolean use4ByteSequence) { mRuntime = VMRuntime.getRuntime(); mIn = Objects.requireNonNull(in); if (bufferSize < 8) { @@ -67,6 +84,64 @@ public class FastDataInput implements DataInput, Closeable { mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize); mBufferPtr = mRuntime.addressOf(mBuffer); mBufferCap = mBuffer.length; + mUse4ByteSequence = use4ByteSequence; + } + + /** + * Obtain a {@link FastDataInput} configured with the given + * {@link InputStream} and which encodes large code-points using 3-byte + * sequences. + * <p> + * This <em>is</em> compatible with the {@link DataInput} API contract, + * which specifies that large code-points must be encoded with 3-byte + * sequences. + */ + public static FastDataInput obtainUsing3ByteSequences(@NonNull InputStream in) { + return new FastDataInput(in, DEFAULT_BUFFER_SIZE, false /* use4ByteSequence */); + } + + /** + * Obtain a {@link FastDataInput} configured with the given + * {@link InputStream} and which decodes large code-points using 4-byte + * sequences. + * <p> + * This <em>is not</em> compatible with the {@link DataInput} API contract, + * which specifies that large code-points must be encoded with 3-byte + * sequences. + */ + public static FastDataInput obtainUsing4ByteSequences(@NonNull InputStream in) { + FastDataInput instance = sInCache.getAndSet(null); + if (instance != null) { + instance.setInput(in); + return instance; + } + return new FastDataInput(in, DEFAULT_BUFFER_SIZE, true /* use4ByteSequence */); + } + + /** + * Release a {@link FastDataInput} to potentially be recycled. You must not + * interact with the object after releasing it. + */ + public void release() { + mIn = null; + mBufferPos = 0; + mBufferLim = 0; + mStringRefCount = 0; + + if (mBufferCap == DEFAULT_BUFFER_SIZE && mUse4ByteSequence) { + // Try to return to the cache. + sInCache.compareAndSet(null, this); + } + } + + /** + * Re-initializes the object for the new input. + */ + private void setInput(@NonNull InputStream in) { + mIn = Objects.requireNonNull(in); + mBufferPos = 0; + mBufferLim = 0; + mStringRefCount = 0; } private void fill(int need) throws IOException { @@ -90,6 +165,7 @@ public class FastDataInput implements DataInput, Closeable { @Override public void close() throws IOException { mIn.close(); + release(); } @Override @@ -126,6 +202,14 @@ public class FastDataInput implements DataInput, Closeable { @Override public String readUTF() throws IOException { + if (mUse4ByteSequence) { + return readUTFUsing4ByteSequences(); + } else { + return readUTFUsing3ByteSequences(); + } + } + + private String readUTFUsing4ByteSequences() throws IOException { // Attempt to read directly from buffer space if there's enough room, // otherwise fall back to chunking into place final int len = readUnsignedShort(); @@ -141,6 +225,22 @@ public class FastDataInput implements DataInput, Closeable { } } + private String readUTFUsing3ByteSequences() throws IOException { + // Attempt to read directly from buffer space if there's enough room, + // otherwise fall back to chunking into place + final int len = readUnsignedShort(); + if (mBufferCap > len) { + if (mBufferLim - mBufferPos < len) fill(len); + final String res = ModifiedUtf8.decode(mBuffer, new char[len], mBufferPos, len); + mBufferPos += len; + return res; + } else { + final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1); + readFully(tmp, 0, len); + return ModifiedUtf8.decode(tmp, new char[len], 0, len); + } + } + /** * Read a {@link String} value with the additional signal that the given * value is a candidate for being canonicalized, similar to diff --git a/core/java/com/android/internal/util/FastDataOutput.java b/core/java/com/android/internal/util/FastDataOutput.java index bc8496b3bdd3..c9e8f8f08229 100644 --- a/core/java/com/android/internal/util/FastDataOutput.java +++ b/core/java/com/android/internal/util/FastDataOutput.java @@ -42,7 +42,7 @@ import java.util.concurrent.atomic.AtomicReference; public class FastDataOutput implements DataOutput, Flushable, Closeable { private static final int MAX_UNSIGNED_SHORT = 65_535; - private static final int BUFFER_SIZE = 32_768; + private static final int DEFAULT_BUFFER_SIZE = 32_768; private static AtomicReference<FastDataOutput> sOutCache = new AtomicReference<>(); @@ -51,6 +51,7 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable { private final byte[] mBuffer; private final long mBufferPtr; private final int mBufferCap; + private final boolean mUse4ByteSequence; private OutputStream mOut; private int mBufferPos; @@ -60,7 +61,18 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable { */ private final HashMap<String, Short> mStringRefs = new HashMap<>(); + /** + * @deprecated callers must specify {@code use4ByteSequence} so they make a + * clear choice about working around a long-standing ART bug, as + * described by the {@code kUtfUse4ByteSequence} comments in + * {@code art/runtime/jni/jni_internal.cc}. + */ + @Deprecated public FastDataOutput(@NonNull OutputStream out, int bufferSize) { + this(out, bufferSize, true /* use4ByteSequence */); + } + + public FastDataOutput(@NonNull OutputStream out, int bufferSize, boolean use4ByteSequence) { mRuntime = VMRuntime.getRuntime(); if (bufferSize < 8) { throw new IllegalArgumentException(); @@ -69,25 +81,45 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable { mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize); mBufferPtr = mRuntime.addressOf(mBuffer); mBufferCap = mBuffer.length; + mUse4ByteSequence = use4ByteSequence; setOutput(out); } /** - * Create a new FastDataOutput object or retrieve one from cache. + * Obtain a {@link FastDataOutput} configured with the given + * {@link OutputStream} and which encodes large code-points using 3-byte + * sequences. + * <p> + * This <em>is</em> compatible with the {@link DataOutput} API contract, + * which specifies that large code-points must be encoded with 3-byte + * sequences. + */ + public static FastDataOutput obtainUsing3ByteSequences(@NonNull OutputStream out) { + return new FastDataOutput(out, DEFAULT_BUFFER_SIZE, false /* use4ByteSequence */); + } + + /** + * Obtain a {@link FastDataOutput} configured with the given + * {@link OutputStream} and which encodes large code-points using 4-byte + * sequences. + * <p> + * This <em>is not</em> compatible with the {@link DataOutput} API contract, + * which specifies that large code-points must be encoded with 3-byte + * sequences. */ - public static FastDataOutput obtain(@NonNull OutputStream out) { + public static FastDataOutput obtainUsing4ByteSequences(@NonNull OutputStream out) { FastDataOutput instance = sOutCache.getAndSet(null); if (instance != null) { instance.setOutput(out); return instance; } - return new FastDataOutput(out, BUFFER_SIZE); + return new FastDataOutput(out, DEFAULT_BUFFER_SIZE, true /* use4ByteSequence */); } /** - * Put a FastDataOutput object back into the cache. - * You must not touch the object after this call. + * Release a {@link FastDataOutput} to potentially be recycled. You must not + * interact with the object after releasing it. */ public void release() { if (mBufferPos > 0) { @@ -98,7 +130,7 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable { mBufferPos = 0; mStringRefs.clear(); - if (mBufferCap == BUFFER_SIZE) { + if (mBufferCap == DEFAULT_BUFFER_SIZE && mUse4ByteSequence) { // Try to return to the cache. sOutCache.compareAndSet(null, this); } @@ -156,6 +188,14 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable { @Override public void writeUTF(String s) throws IOException { + if (mUse4ByteSequence) { + writeUTFUsing4ByteSequences(s); + } else { + writeUTFUsing3ByteSequences(s); + } + } + + private void writeUTFUsing4ByteSequences(String s) throws IOException { // Attempt to write directly to buffer space if there's enough room, // otherwise fall back to chunking into place if (mBufferCap - mBufferPos < 2 + s.length()) drain(); @@ -183,6 +223,27 @@ public class FastDataOutput implements DataOutput, Flushable, Closeable { } } + private void writeUTFUsing3ByteSequences(String s) throws IOException { + final int len = (int) ModifiedUtf8.countBytes(s, false); + if (len > MAX_UNSIGNED_SHORT) { + throw new IOException("Modified UTF-8 length too large: " + len); + } + + // Attempt to write directly to buffer space if there's enough room, + // otherwise fall back to chunking into place + if (mBufferCap >= 2 + len) { + if (mBufferCap - mBufferPos < 2 + len) drain(); + writeShort(len); + ModifiedUtf8.encode(mBuffer, mBufferPos, s); + mBufferPos += len; + } else { + final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1); + ModifiedUtf8.encode(tmp, 0, s); + writeShort(len); + write(tmp, 0, len); + } + } + /** * Write a {@link String} value with the additional signal that the given * value is a candidate for being canonicalized, similar to diff --git a/core/java/com/android/internal/util/ModifiedUtf8.java b/core/java/com/android/internal/util/ModifiedUtf8.java new file mode 100644 index 000000000000..a144c0034dd2 --- /dev/null +++ b/core/java/com/android/internal/util/ModifiedUtf8.java @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 com.android.internal.util; + +import java.io.UTFDataFormatException; + +public class ModifiedUtf8 { + /** + * Decodes a byte array containing <i>modified UTF-8</i> bytes into a string. + * + * <p>Note that although this method decodes the (supposedly impossible) zero byte to U+0000, + * that's what the RI does too. + */ + public static String decode(byte[] in, char[] out, int offset, int utfSize) + throws UTFDataFormatException { + int count = 0, s = 0, a; + while (count < utfSize) { + if ((out[s] = (char) in[offset + count++]) < '\u0080') { + s++; + } else if (((a = out[s]) & 0xe0) == 0xc0) { + if (count >= utfSize) { + throw new UTFDataFormatException("bad second byte at " + count); + } + int b = in[offset + count++]; + if ((b & 0xC0) != 0x80) { + throw new UTFDataFormatException("bad second byte at " + (count - 1)); + } + out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F)); + } else if ((a & 0xf0) == 0xe0) { + if (count + 1 >= utfSize) { + throw new UTFDataFormatException("bad third byte at " + (count + 1)); + } + int b = in[offset + count++]; + int c = in[offset + count++]; + if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) { + throw new UTFDataFormatException("bad second or third byte at " + (count - 2)); + } + out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)); + } else { + throw new UTFDataFormatException("bad byte at " + (count - 1)); + } + } + return new String(out, 0, s); + } + + /** + * Returns the number of bytes the modified UTF-8 representation of 's' would take. Note + * that this is just the space for the bytes representing the characters, not the length + * which precedes those bytes, because different callers represent the length differently, + * as two, four, or even eight bytes. If {@code shortLength} is true, we'll throw an + * exception if the string is too long for its length to be represented by a short. + */ + public static long countBytes(String s, boolean shortLength) throws UTFDataFormatException { + long result = 0; + final int length = s.length(); + for (int i = 0; i < length; ++i) { + char ch = s.charAt(i); + if (ch != 0 && ch <= 127) { // U+0000 uses two bytes. + ++result; + } else if (ch <= 2047) { + result += 2; + } else { + result += 3; + } + if (shortLength && result > 65535) { + throw new UTFDataFormatException("String more than 65535 UTF bytes long"); + } + } + return result; + } + + /** + * Encodes the <i>modified UTF-8</i> bytes corresponding to string {@code s} into the + * byte array {@code dst}, starting at the given {@code offset}. + */ + public static void encode(byte[] dst, int offset, String s) { + final int length = s.length(); + for (int i = 0; i < length; i++) { + char ch = s.charAt(i); + if (ch != 0 && ch <= 127) { // U+0000 uses two bytes. + dst[offset++] = (byte) ch; + } else if (ch <= 2047) { + dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6))); + dst[offset++] = (byte) (0x80 | (0x3f & ch)); + } else { + dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12))); + dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6))); + dst[offset++] = (byte) (0x80 | (0x3f & ch)); + } + } + } + + private ModifiedUtf8() { + } +} diff --git a/core/java/com/android/internal/util/TEST_MAPPING b/core/java/com/android/internal/util/TEST_MAPPING index 5881c5198617..41d59bbeb801 100644 --- a/core/java/com/android/internal/util/TEST_MAPPING +++ b/core/java/com/android/internal/util/TEST_MAPPING @@ -1,7 +1,20 @@ { "presubmit": [ { - "name": "ScreenshotHelperTests" + "name": "ScreenshotHelperTests", + "file_patterns": ["ScreenshotHelper"] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.util.XmlTest" + }, + { + "include-filter": "android.util.BinaryXmlTest" + } + ], + "file_patterns": ["Xml"] } ] -}
\ No newline at end of file +} diff --git a/core/jni/Android.bp b/core/jni/Android.bp index aa661713b1fe..4bc946e17d04 100644 --- a/core/jni/Android.bp +++ b/core/jni/Android.bp @@ -50,6 +50,7 @@ cc_library_shared { "android_util_XmlBlock.cpp", "android_util_jar_StrictJarFile.cpp", "com_android_internal_util_VirtualRefBasePtr.cpp", + "core_jni_helpers.cpp", ":deviceproductinfoconstants_aidl", ], diff --git a/core/jni/OWNERS b/core/jni/OWNERS index 96e9cc1c97f5..ff97ab007efe 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -47,6 +47,7 @@ per-file EphemeralStorage* = file:platform/system/libhwbinder:/OWNERS per-file android_hardware_SensorManager* = arthuri@google.com, bduddie@google.com, stange@google.com per-file *Zygote* = file:/ZYGOTE_OWNERS +per-file core_jni_helpers.* = file:/ZYGOTE_OWNERS per-file fd_utils.* = file:/ZYGOTE_OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS per-file android_animation_* = file:/core/java/android/animation/OWNERS diff --git a/core/jni/TEST_MAPPING b/core/jni/TEST_MAPPING new file mode 100644 index 000000000000..004c30ee5113 --- /dev/null +++ b/core/jni/TEST_MAPPING @@ -0,0 +1,16 @@ +{ + "presubmit": [ + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.util.CharsetUtilsTest" + }, + { + "include-filter": "com.android.internal.util.FastDataTest" + } + ], + "file_patterns": ["CharsetUtils|FastData"] + } + ] +} diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index 78b403c39a17..cb97698fefea 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -348,7 +348,7 @@ private: virtual int handleEvent(int fd, int events, void* data) { JNIEnv* env = AndroidRuntime::getJNIEnv(); sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data); - ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); + ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); ssize_t n; ASensorEvent buffer[16]; diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 05855867ed62..be7bee35da3d 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -138,7 +138,7 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla uint32_t count, VsyncEventData vsyncEventData) { JNIEnv* env = AndroidRuntime::getJNIEnv(); - ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); + ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); if (receiverObj.get()) { ALOGV("receiver %p ~ Invoking vsync handler.", this); @@ -155,7 +155,7 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisp bool connected) { JNIEnv* env = AndroidRuntime::getJNIEnv(); - ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); + ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); if (receiverObj.get()) { ALOGV("receiver %p ~ Invoking hotplug handler.", this); env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchHotplug, @@ -170,7 +170,7 @@ void NativeDisplayEventReceiver::dispatchModeChanged(nsecs_t timestamp, Physical int32_t modeId, nsecs_t) { JNIEnv* env = AndroidRuntime::getJNIEnv(); - ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); + ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); if (receiverObj.get()) { ALOGV("receiver %p ~ Invoking mode changed handler.", this); env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchModeChanged, @@ -185,7 +185,7 @@ void NativeDisplayEventReceiver::dispatchFrameRateOverrides( nsecs_t timestamp, PhysicalDisplayId displayId, std::vector<FrameRateOverride> overrides) { JNIEnv* env = AndroidRuntime::getJNIEnv(); - ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal)); + ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal)); if (receiverObj.get()) { ALOGV("receiver %p ~ Invoking FrameRateOverride handler.", this); const auto frameRateOverrideClass = diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index a7ec38f8b0f6..2b932cb37332 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -329,7 +329,7 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, if (!skipCallbacks && !mBatchedInputEventPending && mInputConsumer.hasPendingBatch()) { // There is a pending batch. Come back later. if (!receiverObj.get()) { - receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); + receiverObj.reset(GetReferent(env, mReceiverWeakGlobal)); if (!receiverObj.get()) { ALOGW("channel '%s' ~ Receiver object was finalized " "without being disposed.", @@ -358,7 +358,7 @@ status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env, if (!skipCallbacks) { if (!receiverObj.get()) { - receiverObj.reset(jniGetReferent(env, mReceiverWeakGlobal)); + receiverObj.reset(GetReferent(env, mReceiverWeakGlobal)); if (!receiverObj.get()) { ALOGW("channel '%s' ~ Receiver object was finalized " "without being disposed.", getInputChannelName().c_str()); diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp index 5da273896e29..4bc567abf27a 100644 --- a/core/jni/android_view_InputEventSender.cpp +++ b/core/jni/android_view_InputEventSender.cpp @@ -200,7 +200,7 @@ status_t NativeInputEventSender::processConsumerResponse(JNIEnv* env) { ALOGD("channel '%s' ~ Receiving finished signals.", getInputChannelName().c_str()); } - ScopedLocalRef<jobject> senderObj(env, jniGetReferent(env, mSenderWeakGlobal)); + ScopedLocalRef<jobject> senderObj(env, GetReferent(env, mSenderWeakGlobal)); if (!senderObj.get()) { ALOGW("channel '%s' ~ Sender object was finalized without being disposed.", getInputChannelName().c_str()); diff --git a/core/jni/android_view_InputQueue.cpp b/core/jni/android_view_InputQueue.cpp index 74bbd7b2cb32..2f9df1fbe9d0 100644 --- a/core/jni/android_view_InputQueue.cpp +++ b/core/jni/android_view_InputQueue.cpp @@ -136,7 +136,7 @@ void InputQueue::handleMessage(const Message& message) { switch(message.what) { case MSG_FINISH_INPUT: JNIEnv* env = AndroidRuntime::getJNIEnv(); - ScopedLocalRef<jobject> inputQueueObj(env, jniGetReferent(env, mInputQueueWeakGlobal)); + ScopedLocalRef<jobject> inputQueueObj(env, GetReferent(env, mInputQueueWeakGlobal)); if (!inputQueueObj.get()) { ALOGW("InputQueue was finalized without being disposed"); return; diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index ef6fd7dd6829..be82879c8411 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -36,7 +36,6 @@ #include <inttypes.h> #include <sys/stat.h> #include <sys/types.h> -#include <linux/fs.h> #include <memory> @@ -254,16 +253,6 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr return INSTALL_FAILED_CONTAINER_ERROR; } - // If a filesystem like f2fs supports per-file compression, set the compression bit before data - // writes - unsigned int flags; - if (ioctl(fd, FS_IOC_GETFLAGS, &flags) == -1) { - ALOGE("Failed to call FS_IOC_GETFLAGS on %s: %s\n", localTmpFileName, strerror(errno)); - } else if ((flags & FS_COMPR_FL) == 0) { - flags |= FS_COMPR_FL; - ioctl(fd, FS_IOC_SETFLAGS, &flags); - } - if (!zipFile->uncompressEntry(zipEntry, fd)) { ALOGE("Failed uncompressing %s to %s\n", fileName, localTmpFileName); close(fd); diff --git a/core/jni/core_jni_helpers.cpp b/core/jni/core_jni_helpers.cpp new file mode 100644 index 000000000000..b65053bbe8ab --- /dev/null +++ b/core/jni/core_jni_helpers.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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. + */ + +#include "core_jni_helpers.h" + +namespace android { + +namespace { + +jmethodID gGetReferent = nullptr; + +} // namespace + +jobject GetReferent(JNIEnv* env, jobject ref) { + if (gGetReferent == nullptr) { + jclass clazz = FindClassOrDie(env, "java/lang/ref/Reference"); + gGetReferent = GetMethodIDOrDie(env, clazz, "get", "()Ljava/lang/Object;"); + } + return env->CallObjectMethod(ref, gGetReferent); +} + +} // namespace android
\ No newline at end of file diff --git a/core/jni/core_jni_helpers.h b/core/jni/core_jni_helpers.h index 526804998896..b85a42529fb6 100644 --- a/core/jni/core_jni_helpers.h +++ b/core/jni/core_jni_helpers.h @@ -90,11 +90,10 @@ static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className, return res; } -static inline jobject jniGetReferent(JNIEnv* env, jobject ref) { - jclass cls = FindClassOrDie(env, "java/lang/ref/Reference"); - jmethodID get = GetMethodIDOrDie(env, cls, "get", "()Ljava/lang/Object;"); - return env->CallObjectMethod(ref, get); -} +/** + * Returns the result of invoking java.lang.ref.Reference.get() on a Reference object. + */ +jobject GetReferent(JNIEnv* env, jobject ref); /** * Read the specified field from jobject, and convert to std::string. diff --git a/core/tests/coretests/src/android/util/XmlTest.java b/core/tests/coretests/src/android/util/XmlTest.java index 4e10ea926966..1cd4d139b229 100644 --- a/core/tests/coretests/src/android/util/XmlTest.java +++ b/core/tests/coretests/src/android/util/XmlTest.java @@ -224,7 +224,7 @@ public class XmlTest { doVerifyRead(in); } - private static final String TEST_STRING = "com.example"; + private static final String TEST_STRING = "com☃example😀typical☃package😀name"; private static final String TEST_STRING_EMPTY = ""; private static final byte[] TEST_BYTES = new byte[] { 0, 1, 2, 3, 4, 3, 2, 1, 0 }; private static final byte[] TEST_BYTES_EMPTY = new byte[0]; diff --git a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java index 81fb39fed026..04dfd6ee30e2 100644 --- a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java +++ b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java @@ -23,10 +23,13 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.util.ExceptionUtils; -import androidx.test.ext.junit.runners.AndroidJUnit4; +import libcore.util.HexEncoding; +import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -38,22 +41,34 @@ import java.io.EOFException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Collection; import java.util.function.Consumer; -@RunWith(AndroidJUnit4.class) +@RunWith(Parameterized.class) public class FastDataTest { + private final boolean use4ByteSequence; + private static final String TEST_SHORT_STRING = "a"; - private static final String TEST_LONG_STRING = "com☃example☃typical☃package☃name"; + private static final String TEST_LONG_STRING = "com☃example😀typical☃package😀name"; private static final byte[] TEST_BYTES = TEST_LONG_STRING.getBytes(StandardCharsets.UTF_16LE); + @Parameters(name = "use4ByteSequence={0}") + public static Collection<Object[]> data() { + return Arrays.asList(new Object[][] { {true}, {false} }); + } + + public FastDataTest(boolean use4ByteSequence) { + this.use4ByteSequence = use4ByteSequence; + } + @Test public void testEndOfFile_Int() throws Exception { try (FastDataInput in = new FastDataInput(new ByteArrayInputStream( - new byte[] { 1 }), 1000)) { + new byte[] { 1 }), 1000, use4ByteSequence)) { assertThrows(EOFException.class, () -> in.readInt()); } try (FastDataInput in = new FastDataInput(new ByteArrayInputStream( - new byte[] { 1, 1, 1, 1 }), 1000)) { + new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) { assertEquals(1, in.readByte()); assertThrows(EOFException.class, () -> in.readInt()); } @@ -62,11 +77,11 @@ public class FastDataTest { @Test public void testEndOfFile_String() throws Exception { try (FastDataInput in = new FastDataInput(new ByteArrayInputStream( - new byte[] { 1 }), 1000)) { + new byte[] { 1 }), 1000, use4ByteSequence)) { assertThrows(EOFException.class, () -> in.readUTF()); } try (FastDataInput in = new FastDataInput(new ByteArrayInputStream( - new byte[] { 1, 1, 1, 1 }), 1000)) { + new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) { assertThrows(EOFException.class, () -> in.readUTF()); } } @@ -74,12 +89,12 @@ public class FastDataTest { @Test public void testEndOfFile_Bytes_Small() throws Exception { try (FastDataInput in = new FastDataInput(new ByteArrayInputStream( - new byte[] { 1, 1, 1, 1 }), 1000)) { + new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) { final byte[] tmp = new byte[10]; assertThrows(EOFException.class, () -> in.readFully(tmp)); } try (FastDataInput in = new FastDataInput(new ByteArrayInputStream( - new byte[] { 1, 1, 1, 1 }), 1000)) { + new byte[] { 1, 1, 1, 1 }), 1000, use4ByteSequence)) { final byte[] tmp = new byte[10_000]; assertThrows(EOFException.class, () -> in.readFully(tmp)); } @@ -88,7 +103,8 @@ public class FastDataTest { @Test public void testUTF_Bounds() throws Exception { final char[] buf = new char[65_534]; - try (FastDataOutput out = new FastDataOutput(new ByteArrayOutputStream(), BOUNCE_SIZE)) { + try (FastDataOutput out = new FastDataOutput(new ByteArrayOutputStream(), + BOUNCE_SIZE, use4ByteSequence)) { // Writing simple string will fit fine Arrays.fill(buf, '!'); final String simple = new String(buf); @@ -100,11 +116,15 @@ public class FastDataTest { final String complex = new String(buf); assertThrows(IOException.class, () -> out.writeUTF(complex)); assertThrows(IOException.class, () -> out.writeInternedUTF(complex)); + + out.flush(); } } @Test public void testTranscode() throws Exception { + Assume.assumeFalse(use4ByteSequence); + // Verify that upstream data can be read by fast { final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); @@ -113,20 +133,22 @@ public class FastDataTest { out.flush(); final FastDataInput in = new FastDataInput( - new ByteArrayInputStream(outStream.toByteArray()), BOUNCE_SIZE); - doTransodeRead(in); + new ByteArrayInputStream(outStream.toByteArray()), + BOUNCE_SIZE, use4ByteSequence); + doTranscodeRead(in); } // Verify that fast data can be read by upstream { final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - final FastDataOutput out = new FastDataOutput(outStream, BOUNCE_SIZE); + final FastDataOutput out = new FastDataOutput(outStream, + BOUNCE_SIZE, use4ByteSequence); doTranscodeWrite(out); out.flush(); final DataInputStream in = new DataInputStream( new ByteArrayInputStream(outStream.toByteArray())); - doTransodeRead(in); + doTranscodeRead(in); } } @@ -144,7 +166,7 @@ public class FastDataTest { out.writeDouble(32d); } - private static void doTransodeRead(DataInput in) throws IOException { + private static void doTranscodeRead(DataInput in) throws IOException { assertEquals(true, in.readBoolean()); assertEquals(false, in.readBoolean()); assertEquals(1, in.readByte()); @@ -225,10 +247,12 @@ public class FastDataTest { doBounce((out) -> { out.writeUTF(""); out.writeUTF("☃"); + out.writeUTF("😀"); out.writeUTF("example"); }, (in) -> { assertEquals("", in.readUTF()); assertEquals("☃", in.readUTF()); + assertEquals("😀", in.readUTF()); assertEquals("example", in.readUTF()); }); } @@ -263,6 +287,35 @@ public class FastDataTest { }, 1); } + /** + * Verify that we encode every valid code-point identically to RI when + * running in 3-byte mode. + */ + @Test + public void testBounce_UTF_Exhaustive() throws Exception { + Assume.assumeFalse(use4ByteSequence); + + final ByteArrayOutputStream slowStream = new ByteArrayOutputStream(); + final DataOutput slowData = new DataOutputStream(slowStream); + + final ByteArrayOutputStream fastStream = new ByteArrayOutputStream(); + final FastDataOutput fastData = FastDataOutput.obtainUsing3ByteSequences(fastStream); + + for (int cp = Character.MIN_CODE_POINT; cp < Character.MAX_CODE_POINT; cp++) { + if (Character.isValidCodePoint(cp)) { + final String cpString = new String(Character.toChars(cp)); + slowStream.reset(); + slowData.writeUTF(cpString); + fastStream.reset(); + fastData.writeUTF(cpString); + fastData.flush(); + assertEquals("Bad encoding for code-point " + Integer.toHexString(cp), + HexEncoding.encodeToString(slowStream.toByteArray()), + HexEncoding.encodeToString(fastStream.toByteArray())); + } + } + } + @Test public void testBounce_InternedUTF() throws Exception { doBounce((out) -> { @@ -355,22 +408,24 @@ public class FastDataTest { * Verify that some common data can be written and read back, effectively * "bouncing" it through a serialized representation. */ - private static void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out, + private void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out, @NonNull ThrowingConsumer<FastDataInput> in) throws Exception { doBounce(out, in, BOUNCE_REPEAT); } - private static void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out, + private void doBounce(@NonNull ThrowingConsumer<FastDataOutput> out, @NonNull ThrowingConsumer<FastDataInput> in, int count) throws Exception { final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - final FastDataOutput outData = new FastDataOutput(outStream, BOUNCE_SIZE); + final FastDataOutput outData = new FastDataOutput(outStream, + BOUNCE_SIZE, use4ByteSequence); for (int i = 0; i < count; i++) { out.accept(outData); } outData.flush(); final ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray()); - final FastDataInput inData = new FastDataInput(inStream, BOUNCE_SIZE); + final FastDataInput inData = new FastDataInput(inStream, + BOUNCE_SIZE, use4ByteSequence); for (int i = 0; i < count; i++) { in.accept(inData); } diff --git a/identity/java/android/security/identity/Util.java b/identity/java/android/security/identity/Util.java index e56bd5167906..789ff06f064b 100644 --- a/identity/java/android/security/identity/Util.java +++ b/identity/java/android/security/identity/Util.java @@ -20,12 +20,12 @@ import android.annotation.NonNull; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.interfaces.ECPublicKey; import java.security.spec.ECPoint; -import java.util.Collection; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -36,15 +36,6 @@ import javax.crypto.spec.SecretKeySpec; public class Util { private static final String TAG = "Util"; - static int[] integerCollectionToArray(Collection<Integer> collection) { - int[] result = new int[collection.size()]; - int n = 0; - for (int item : collection) { - result[n++] = item; - } - return result; - } - static byte[] stripLeadingZeroes(byte[] value) { int n = 0; while (n < value.length && value[n] == 0) { @@ -61,15 +52,47 @@ public class Util { static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) { ECPoint w = ((ECPublicKey) publicKey).getW(); - // X and Y are always positive so for interop we remove any leading zeroes - // inserted by the BigInteger encoder. - byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray()); - byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray()); + BigInteger x = w.getAffineX(); + BigInteger y = w.getAffineY(); + if (x.compareTo(BigInteger.ZERO) < 0) { + throw new RuntimeException("X is negative"); + } + if (y.compareTo(BigInteger.ZERO) < 0) { + throw new RuntimeException("Y is negative"); + } try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(0x04); - baos.write(x); - baos.write(y); + + // Each coordinate may be encoded in 33*, 32, or fewer bytes. + // + // * : it can be 33 bytes because toByteArray() guarantees "The array will contain the + // minimum number of bytes required to represent this BigInteger, including at + // least one sign bit, which is (ceil((this.bitLength() + 1)/8))" which means that + // the MSB is always 0x00. This is taken care of by calling calling + // stripLeadingZeroes(). + // + // We need the encoding to be exactly 32 bytes since according to RFC 5480 section 2.2 + // and SEC 1: Elliptic Curve Cryptography section 2.3.3 the encoding is 0x04 | X | Y + // where X and Y are encoded in exactly 32 byte, big endian integer values each. + // + byte[] xBytes = stripLeadingZeroes(x.toByteArray()); + if (xBytes.length > 32) { + throw new RuntimeException("xBytes is " + xBytes.length + " which is unexpected"); + } + for (int n = 0; n < 32 - xBytes.length; n++) { + baos.write(0x00); + } + baos.write(xBytes); + + byte[] yBytes = stripLeadingZeroes(y.toByteArray()); + if (yBytes.length > 32) { + throw new RuntimeException("yBytes is " + yBytes.length + " which is unexpected"); + } + for (int n = 0; n < 32 - yBytes.length; n++) { + baos.write(0x00); + } + baos.write(yBytes); return baos.toByteArray(); } catch (IOException e) { throw new RuntimeException("Unexpected IOException", e); diff --git a/libs/WindowManager/OWNERS b/libs/WindowManager/OWNERS index 780e4c1632f7..2c61df96eb03 100644 --- a/libs/WindowManager/OWNERS +++ b/libs/WindowManager/OWNERS @@ -1,6 +1,3 @@ set noparent include /services/core/java/com/android/server/wm/OWNERS - -# Give submodule owners in shell resource approval -per-file Shell/res*/*/*.xml = hwwang@google.com, lbill@google.com, madym@google.com diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS new file mode 100644 index 000000000000..4b125904004a --- /dev/null +++ b/libs/WindowManager/Shell/OWNERS @@ -0,0 +1,4 @@ +xutan@google.com + +# Give submodule owners in shell resource approval +per-file res*/*/*.xml = hwwang@google.com, lbill@google.com, madym@google.com diff --git a/libs/incident/libincident.map.txt b/libs/incident/libincident.map.txt index f157763f1a03..f75cceaf59fa 100644 --- a/libs/incident/libincident.map.txt +++ b/libs/incident/libincident.map.txt @@ -1,15 +1,15 @@ LIBINCIDENT { global: - AIncidentReportArgs_init; # apex # introduced=30 - AIncidentReportArgs_clone; # apex # introduced=30 - AIncidentReportArgs_delete; # apex # introduced=30 - AIncidentReportArgs_setAll; # apex # introduced=30 - AIncidentReportArgs_setPrivacyPolicy; # apex # introduced=30 - AIncidentReportArgs_addSection; # apex # introduced=30 - AIncidentReportArgs_setReceiverPackage; # apex # introduced=30 - AIncidentReportArgs_setReceiverClass; # apex # introduced=30 - AIncidentReportArgs_addHeader; # apex # introduced=30 - AIncidentReportArgs_takeReport; # apex # introduced=30 + AIncidentReportArgs_init; # systemapi # introduced=30 + AIncidentReportArgs_clone; # systemapi # introduced=30 + AIncidentReportArgs_delete; # systemapi # introduced=30 + AIncidentReportArgs_setAll; # systemapi # introduced=30 + AIncidentReportArgs_setPrivacyPolicy; # systemapi # introduced=30 + AIncidentReportArgs_addSection; # systemapi # introduced=30 + AIncidentReportArgs_setReceiverPackage; # systemapi # introduced=30 + AIncidentReportArgs_setReceiverClass; # systemapi # introduced=30 + AIncidentReportArgs_addHeader; # systemapi # introduced=30 + AIncidentReportArgs_takeReport; # systemapi # introduced=30 local: *; }; diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedBackupTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedBackupTaskTest.java index f6914efd6d83..23d6e34db4f1 100644 --- a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedBackupTaskTest.java +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedBackupTaskTest.java @@ -22,8 +22,8 @@ import static com.android.server.backup.encryption.protos.nano.ChunksMetadataPro import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java index 096b2da10c98..bfc5d0dca3ff 100644 --- a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedFullBackupTaskTest.java @@ -18,9 +18,9 @@ package com.android.server.backup.encryption.tasks; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertThrows; diff --git a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java index fa4fef50ac1a..222b88221ba2 100644 --- a/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java +++ b/packages/BackupEncryption/test/robolectric/src/com/android/server/backup/encryption/tasks/EncryptedKvBackupTaskTest.java @@ -19,8 +19,8 @@ package com.android.server.backup.encryption.tasks; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.testng.Assert.assertFalse; @@ -41,13 +41,6 @@ import com.android.server.backup.encryption.protos.nano.KeyValueListingProto; import com.android.server.backup.encryption.protos.nano.WrappedKeyProto; import com.android.server.backup.testing.CryptoTestUtils; -import java.io.IOException; -import java.util.Arrays; -import java.util.Map; -import java.util.Map.Entry; - -import javax.crypto.SecretKey; - import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -59,6 +52,14 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; +import java.io.IOException; +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; + +import javax.crypto.SecretKey; + + @RunWith(RobolectricTestRunner.class) public class EncryptedKvBackupTaskTest { private static final boolean INCREMENTAL = true; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java index 1f2297ba3a0c..fc2bf0a9bd93 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java @@ -21,10 +21,10 @@ import static android.os.UserHandle.MU_ENABLED; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java index 95f7ef41b10b..508dffc2fa21 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/net/DataUsageUtilsTest.java @@ -18,7 +18,7 @@ package com.android.settingslib.net; import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java index f28572f5f71d..cf07c6bb7cb9 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/EditUserInfoControllerTest.java @@ -22,7 +22,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import android.app.Activity; @@ -143,7 +143,7 @@ public class EditUserInfoControllerTest { dialog.show(); dialog.cancel(); - verifyZeroInteractions(successCallback); + verifyNoInteractions(successCallback); verify(cancelCallback, times(1)) .run(); } @@ -159,7 +159,7 @@ public class EditUserInfoControllerTest { dialog.show(); dialog.getButton(Dialog.BUTTON_NEGATIVE).performClick(); - verifyZeroInteractions(successCallback); + verifyNoInteractions(successCallback); verify(cancelCallback, times(1)) .run(); } @@ -180,7 +180,7 @@ public class EditUserInfoControllerTest { verify(successCallback, times(1)) .accept("test", oldUserIcon); - verifyZeroInteractions(cancelCallback); + verifyNoInteractions(cancelCallback); } @Test @@ -198,7 +198,7 @@ public class EditUserInfoControllerTest { verify(successCallback, times(1)) .accept("test", null); - verifyZeroInteractions(cancelCallback); + verifyNoInteractions(cancelCallback); } @Test @@ -219,7 +219,7 @@ public class EditUserInfoControllerTest { verify(successCallback, times(1)) .accept(expectedNewName, mCurrentIcon); - verifyZeroInteractions(cancelCallback); + verifyNoInteractions(cancelCallback); } @Test @@ -238,7 +238,7 @@ public class EditUserInfoControllerTest { verify(successCallback, times(1)) .accept("test", newPhoto); - verifyZeroInteractions(cancelCallback); + verifyNoInteractions(cancelCallback); } @Test @@ -257,7 +257,7 @@ public class EditUserInfoControllerTest { verify(successCallback, times(1)) .accept("test", newPhoto); - verifyZeroInteractions(cancelCallback); + verifyNoInteractions(cancelCallback); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragmentTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragmentTest.java index 0b3495def21f..ca0aa0d7b900 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragmentTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/UpdatableListPreferenceDialogFragmentTest.java @@ -56,7 +56,7 @@ public class UpdatableListPreferenceDialogFragmentTest { mUpdatableListPrefDlgFragment = spy(UpdatableListPreferenceDialogFragment .newInstance(KEY, MetricsProto.MetricsEvent.DIALOG_SWITCH_A2DP_DEVICES)); - mEntries = spy(new ArrayList<>()); + mEntries = new ArrayList<>(); mUpdatableListPrefDlgFragment.setEntries(mEntries); mUpdatableListPrefDlgFragment .setMetricsCategory(mUpdatableListPrefDlgFragment.getArguments()); diff --git a/packages/SystemUI/checks/Android.bp b/packages/SystemUI/checks/Android.bp index 8457312dc403..9671adde4904 100644 --- a/packages/SystemUI/checks/Android.bp +++ b/packages/SystemUI/checks/Android.bp @@ -32,10 +32,17 @@ java_library_host { "auto_service_annotations", "lint_api", ], + kotlincflags: ["-Xjvm-default=all"], } java_test_host { name: "SystemUILintCheckerTest", + // TODO(b/239881504): Since this test was written, Android + // Lint was updated, and now includes classes that were + // compiled for java 15. The soong build doesn't support + // java 15 yet, so we can't compile against "lint". Disable + // the test until java 15 is supported. + enabled: false, srcs: [ "tests/**/*.kt", "tests/**/*.java", diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java index 946c52e8ee5b..21b8baf85369 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java @@ -414,37 +414,43 @@ public class UdfpsControllerTest extends SysuiTestCase { final UdfpsOverlayParams oldParams = new UdfpsOverlayParams(sensorBounds[0], displayWidth[0], displayHeight[0], scaleFactor[0], rotation[0]); - for (int i1 = 0; i1 <= 1; ++i1) - for (int i2 = 0; i2 <= 1; ++i2) - for (int i3 = 0; i3 <= 1; ++i3) - for (int i4 = 0; i4 <= 1; ++i4) - for (int i5 = 0; i5 <= 1; ++i5) { - final UdfpsOverlayParams newParams = new UdfpsOverlayParams(sensorBounds[i1], - displayWidth[i2], displayHeight[i3], scaleFactor[i4], rotation[i5]); - - if (newParams.equals(oldParams)) { - continue; + for (int i1 = 0; i1 <= 1; ++i1) { + for (int i2 = 0; i2 <= 1; ++i2) { + for (int i3 = 0; i3 <= 1; ++i3) { + for (int i4 = 0; i4 <= 1; ++i4) { + for (int i5 = 0; i5 <= 1; ++i5) { + final UdfpsOverlayParams newParams = new UdfpsOverlayParams( + sensorBounds[i1], displayWidth[i2], displayHeight[i3], + scaleFactor[i4], rotation[i5]); + + if (newParams.equals(oldParams)) { + continue; + } + + // Initialize the overlay with old parameters. + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, oldParams); + + // Show the overlay. + reset(mWindowManager); + mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, + TEST_UDFPS_SENSOR_ID, + BiometricOverlayConstants.REASON_ENROLL_ENROLLING, + mUdfpsOverlayControllerCallback); + mFgExecutor.runAllReady(); + verify(mWindowManager).addView(any(), any()); + + // Update overlay parameters. + reset(mWindowManager); + mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, newParams); + mFgExecutor.runAllReady(); + + // Ensure the overlay was recreated. + verify(mWindowManager).removeView(any()); + verify(mWindowManager).addView(any(), any()); + } + } + } } - - // Initialize the overlay with old parameters. - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, oldParams); - - // Show the overlay. - reset(mWindowManager); - mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, TEST_UDFPS_SENSOR_ID, - BiometricOverlayConstants.REASON_ENROLL_ENROLLING, - mUdfpsOverlayControllerCallback); - mFgExecutor.runAllReady(); - verify(mWindowManager).addView(any(), any()); - - // Update overlay parameters. - reset(mWindowManager); - mUdfpsController.updateOverlayParams(TEST_UDFPS_SENSOR_ID, newParams); - mFgExecutor.runAllReady(); - - // Ensure the overlay was recreated. - verify(mWindowManager).removeView(any()); - verify(mWindowManager).addView(any(), any()); } } diff --git a/rs/OWNERS b/rs/OWNERS index 61853d3d40cf..fd03660d2d81 100644 --- a/rs/OWNERS +++ b/rs/OWNERS @@ -1,5 +1,2 @@ -butlermichael@google.com -dgross@google.com -jeanluc@google.com -miaowang@google.com -yangni@google.com +# Bug component: 43047 +include platform/frameworks/rs:/RS_OWNERS # RenderScript team diff --git a/sax/tests/saxtests/src/android/sax/SafeSaxTest.java b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java index e8cf2f748c88..a68fc9ab2290 100644 --- a/sax/tests/saxtests/src/android/sax/SafeSaxTest.java +++ b/sax/tests/saxtests/src/android/sax/SafeSaxTest.java @@ -26,7 +26,6 @@ import android.sax.TextElementListener; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.SmallTest; -import android.text.format.Time; import android.util.Log; import android.util.Xml; import com.android.internal.util.XmlUtils; @@ -39,6 +38,7 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.time.Instant; import com.android.frameworks.saxtests.R; @@ -225,8 +225,7 @@ public class SafeSaxTest extends AndroidTestCase { .setEndTextElementListener(new EndTextElementListener() { public void end(String body) { // TODO(tomtaylor): programmatically get the timezone - video.dateAdded = new Time(Time.TIMEZONE_UTC); - video.dateAdded.parse3339(body); + video.dateAdded = Instant.parse(body); } }); @@ -472,8 +471,7 @@ public class SafeSaxTest extends AndroidTestCase { if (uri.equals(ATOM_NAMESPACE)) { if (localName.equals("published")) { // TODO(tomtaylor): programmatically get the timezone - video.dateAdded = new Time(Time.TIMEZONE_UTC); - video.dateAdded.parse3339(takeText()); + video.dateAdded = Instant.parse(takeText()); return; } @@ -532,7 +530,7 @@ public class SafeSaxTest extends AndroidTestCase { public float rating; // ranges from 0.0 to 5.0 public Boolean triedToLoadThumbnail; public String authorName; - public Time dateAdded; + public Instant dateAdded; public String category; public String tags; public String description; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index c3fc8e0a7535..774fe5bc862c 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1095,7 +1095,7 @@ public class Vpn { // Except for Settings and VpnDialogs, the caller should be matched one of oldPackage or // newPackage. Otherwise, non VPN owner might get the VPN always-on status of the VPN owner. // See b/191382886. - if (mContext.checkCallingOrSelfPermission(CONTROL_VPN) != PERMISSION_GRANTED) { + if (!hasControlVpnPermission()) { if (oldPackage != null) { verifyCallingUidAndPackage(oldPackage); } @@ -2045,6 +2045,10 @@ public class Vpn { "Unauthorized Caller"); } + private boolean hasControlVpnPermission() { + return mContext.checkCallingOrSelfPermission(CONTROL_VPN) == PERMISSION_GRANTED; + } + private class Connection implements ServiceConnection { private IBinder mService; @@ -3337,7 +3341,7 @@ public class Vpn { // TODO(b/230548427): Remove SDK check once VPN related stuff are // decoupled from ConnectivityServiceTest. - if (SdkLevel.isAtLeastT() && category != null) { + if (SdkLevel.isAtLeastT() && category != null && isVpnApp(mPackage)) { sendEventToVpnManagerApp(category, errorClass, errorCode, getPackage(), mSessionKey, makeVpnProfileStateLocked(), mActiveNetwork, @@ -3846,8 +3850,10 @@ public class Vpn { Binder.restoreCallingIdentity(token); } - // TODO: if package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop. - // This mirrors the prepareAndAuthorize that is used by VpnService. + // If package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop. + if (hasControlVpnPermission()) { + setPackageAuthorization(packageName, VpnManager.TYPE_VPN_PLATFORM); + } // Return whether the app is already pre-consented return isVpnProfilePreConsented(mContext, packageName); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index d1e0b0474b61..829b9c7692fe 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -9909,10 +9909,16 @@ public class NotificationManagerService extends SystemService { * given NAS is bound in. */ private boolean isInteractionVisibleToListener(ManagedServiceInfo info, int userId) { - boolean isAssistantService = mAssistants.isServiceTokenValidLocked(info.service); + boolean isAssistantService = isServiceTokenValid(info.service); return !isAssistantService || info.isSameUser(userId); } + private boolean isServiceTokenValid(IInterface service) { + synchronized (mNotificationLock) { + return mAssistants.isServiceTokenValidLocked(service); + } + } + private boolean isPackageSuspendedForUser(String pkg, int uid) { final long identity = Binder.clearCallingIdentity(); int userId = UserHandle.getUserId(uid); @@ -11169,7 +11175,7 @@ public class NotificationManagerService extends SystemService { BackgroundThread.getHandler().post(() -> { if (info.isSystem || hasCompanionDevice(info) - || mAssistants.isServiceTokenValidLocked(info.service)) { + || isServiceTokenValid(info.service)) { notifyNotificationChannelChanged( info, pkg, user, channel, modificationType); } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9d708add5ca5..7895f708a5ca 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -18636,9 +18636,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { Objects.requireNonNull(strings, "strings must be provided."); mInjector.binderWithCleanCallingIdentity(() -> { - if (mDeviceManagementResourcesProvider.updateStrings(strings)) - sendStringsUpdatedBroadcast( - strings.stream().map(s -> s.getStringId()).collect(Collectors.toList())); + if (mDeviceManagementResourcesProvider.updateStrings(strings)) { + sendStringsUpdatedBroadcast( + strings.stream().map(s -> s.getStringId()).collect(Collectors.toList())); + } }); } diff --git a/services/net/Android.bp b/services/net/Android.bp index 804ccc514df5..3d40f6445834 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -18,7 +18,6 @@ java_library_static { name: "services.net", defaults: ["platform_service_defaults"], srcs: [ - ":net-module-utils-srcs", ":services.net-sources", ], static_libs: [ diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index ca9ff6f15f3f..962a07ac6553 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -43,23 +43,23 @@ import static com.android.server.backup.testing.Utils.transferStreamedData; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.intThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.anyLong; +import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.eq; import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.intThat; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; import static org.robolectric.shadow.api.Shadow.extract; @@ -2185,7 +2185,7 @@ public class KeyValueBackupTaskTest { task.waitCancel(); reset(transportMock.transport); taskFinished.block(); - verifyZeroInteractions(transportMock.transport); + verifyNoInteractions(transportMock.transport); } @Test diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java index 38becc6af0dc..297940e9c8c6 100644 --- a/telephony/java/android/telephony/CellSignalStrengthNr.java +++ b/telephony/java/android/telephony/CellSignalStrengthNr.java @@ -49,7 +49,7 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa private static final String TAG = "CellSignalStrengthNr"; // Lifted from Default carrier configs and max range of SSRSRP - // Boundaries: [-140 dB, -44 dB] + // Boundaries: [-156 dB, -31 dB] private int[] mSsRsrpThresholds = new int[] { -110, /* SIGNAL_STRENGTH_POOR */ -90, /* SIGNAL_STRENGTH_MODERATE */ @@ -173,14 +173,14 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa */ public CellSignalStrengthNr(int csiRsrp, int csiRsrq, int csiSinr, int csiCqiTableIndex, List<Byte> csiCqiReport, int ssRsrp, int ssRsrq, int ssSinr) { - mCsiRsrp = inRangeOrUnavailable(csiRsrp, -140, -44); + mCsiRsrp = inRangeOrUnavailable(csiRsrp, -156, -31); mCsiRsrq = inRangeOrUnavailable(csiRsrq, -20, -3); mCsiSinr = inRangeOrUnavailable(csiSinr, -23, 23); mCsiCqiTableIndex = inRangeOrUnavailable(csiCqiTableIndex, 1, 3); mCsiCqiReport = csiCqiReport.stream() - .map(cqi -> new Integer(inRangeOrUnavailable(Byte.toUnsignedInt(cqi), 0, 15))) + .map(cqi -> inRangeOrUnavailable(Byte.toUnsignedInt(cqi), 0, 15)) .collect(Collectors.toList()); - mSsRsrp = inRangeOrUnavailable(ssRsrp, -140, -44); + mSsRsrp = inRangeOrUnavailable(ssRsrp, -156, -31); mSsRsrq = inRangeOrUnavailable(ssRsrq, -43, 20); mSsSinr = inRangeOrUnavailable(ssSinr, -23, 40); updateLevel(null, null); @@ -212,8 +212,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa } /** - * Reference: 3GPP TS 38.215. - * Range: -140 dBm to -44 dBm. + * Reference: 3GPP TS 38.133 10.1.6.1. + * Range: -156 dBm to -31 dBm. * @return SS reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported * value. */ @@ -242,8 +242,8 @@ public final class CellSignalStrengthNr extends CellSignalStrength implements Pa } /** - * Reference: 3GPP TS 38.215. - * Range: -140 dBm to -44 dBm. + * Reference: 3GPP TS 38.133 10.1.6.1. + * Range: -156 dBm to -31 dBm. * @return CSI reference signal received power, {@link CellInfo#UNAVAILABLE} means unreported * value. */ diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index d07d8097bce4..70f1639ae50d 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -3113,8 +3113,9 @@ public class SubscriptionManager { * @param callback Callback will be triggered once it succeeds or failed. * Pass null if don't care about the result. * + * @throws IllegalStateException when subscription manager service is not available. + * @throws SecurityException when clients do not have MODIFY_PHONE_STATE permission. * @hide - * */ @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -3124,7 +3125,9 @@ public class SubscriptionManager { if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId); try { ISub iSub = TelephonyManager.getSubscriptionService(); - if (iSub == null) return; + if (iSub == null) { + throw new IllegalStateException("subscription manager service is null."); + } ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() { @Override @@ -3144,7 +3147,8 @@ public class SubscriptionManager { }; iSub.setPreferredDataSubscriptionId(subId, needValidation, callbackStub); } catch (RemoteException ex) { - // ignore it + loge("setPreferredDataSubscriptionId RemoteException=" + ex); + ex.rethrowFromSystemServer(); } } diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java index 235ed842b749..081a74a58342 100644 --- a/telephony/java/android/telephony/data/ApnSetting.java +++ b/telephony/java/android/telephony/data/ApnSetting.java @@ -1137,10 +1137,7 @@ public class ApnSetting implements Parcelable { return false; } // DEFAULT can handle HIPRI. - if (hasApnType(type)) { - return true; - } - return false; + return hasApnType(type); } // Check whether the types of two APN same (even only one type of each APN is same). diff --git a/tools/lint/Android.bp b/tools/lint/Android.bp index 17547ef8b561..260104145505 100644 --- a/tools/lint/Android.bp +++ b/tools/lint/Android.bp @@ -29,10 +29,17 @@ java_library_host { "auto_service_annotations", "lint_api", ], + kotlincflags: ["-Xjvm-default=all"], } java_test_host { name: "AndroidFrameworkLintCheckerTest", + // TODO(b/239881504): Since this test was written, Android + // Lint was updated, and now includes classes that were + // compiled for java 15. The soong build doesn't support + // java 15 yet, so we can't compile against "lint". Disable + // the test until java 15 is supported. + enabled: false, srcs: ["checks/src/test/java/**/*.kt"], static_libs: [ "AndroidFrameworkLintChecker", |