diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 8edf03d033f8a..af027837ec917 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -2301,11 +2301,11 @@ public class Notification implements Parcelable priority = parcel.readInt(); - category = parcel.readString(); + category = parcel.readString8(); - mGroupKey = parcel.readString(); + mGroupKey = parcel.readString8(); - mSortKey = parcel.readString(); + mSortKey = parcel.readString8(); extras = Bundle.setDefusable(parcel.readBundle(), true); // may be null fixDuplicateExtras(); @@ -2329,12 +2329,12 @@ public class Notification implements Parcelable color = parcel.readInt(); if (parcel.readInt() != 0) { - mChannelId = parcel.readString(); + mChannelId = parcel.readString8(); } mTimeout = parcel.readLong(); if (parcel.readInt() != 0) { - mShortcutId = parcel.readString(); + mShortcutId = parcel.readString8(); } if (parcel.readInt() != 0) { @@ -2766,11 +2766,11 @@ public class Notification implements Parcelable parcel.writeInt(priority); - parcel.writeString(category); + parcel.writeString8(category); - parcel.writeString(mGroupKey); + parcel.writeString8(mGroupKey); - parcel.writeString(mSortKey); + parcel.writeString8(mSortKey); parcel.writeBundle(extras); // null ok @@ -2803,7 +2803,7 @@ public class Notification implements Parcelable if (mChannelId != null) { parcel.writeInt(1); - parcel.writeString(mChannelId); + parcel.writeString8(mChannelId); } else { parcel.writeInt(0); } @@ -2811,7 +2811,7 @@ public class Notification implements Parcelable if (mShortcutId != null) { parcel.writeInt(1); - parcel.writeString(mShortcutId); + parcel.writeString8(mShortcutId); } else { parcel.writeInt(0); } @@ -8873,7 +8873,7 @@ public class Notification implements Parcelable } mDesiredHeightResId = in.readInt(); if (in.readInt() != 0) { - mShortcutId = in.readString(); + mShortcutId = in.readString8(); } } @@ -9029,7 +9029,7 @@ public class Notification implements Parcelable out.writeInt(mDesiredHeightResId); out.writeInt(TextUtils.isEmpty(mShortcutId) ? 0 : 1); if (!TextUtils.isEmpty(mShortcutId)) { - out.writeString(mShortcutId); + out.writeString8(mShortcutId); } } diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java index 9c806fa286bc3..1923bf3c5a23c 100644 --- a/core/java/android/content/ClipData.java +++ b/core/java/android/content/ClipData.java @@ -1206,7 +1206,7 @@ public class ClipData implements Parcelable { } } else { dest.writeInt(PARCEL_TYPE_STRING); - dest.writeString(text); + dest.writeString8(text); } } @@ -1215,7 +1215,7 @@ public class ClipData implements Parcelable { */ private static String readHtmlTextFromParcel(Parcel in) { if (in.readInt() == PARCEL_TYPE_STRING) { - return in.readString(); + return in.readString8(); } ParcelFileDescriptor pfd = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index 494d2aeaf42a2..1fb426eb3cfc8 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -91,8 +91,8 @@ public class ContentProviderOperation implements Parcelable { private ContentProviderOperation(Parcel source) { mType = source.readInt(); mUri = Uri.CREATOR.createFromParcel(source); - mMethod = source.readInt() != 0 ? source.readString() : null; - mArg = source.readInt() != 0 ? source.readString() : null; + mMethod = source.readInt() != 0 ? source.readString8() : null; + mArg = source.readInt() != 0 ? source.readString8() : null; final int valuesSize = source.readInt(); if (valuesSize != -1) { mValues = new ArrayMap<>(valuesSize); @@ -107,7 +107,7 @@ public class ContentProviderOperation implements Parcelable { } else { mExtras = null; } - mSelection = source.readInt() != 0 ? source.readString() : null; + mSelection = source.readInt() != 0 ? source.readString8() : null; mSelectionArgs = source.readSparseArray(null); mExpectedCount = source.readInt() != 0 ? source.readInt() : null; mYieldAllowed = source.readInt() != 0; @@ -135,13 +135,13 @@ public class ContentProviderOperation implements Parcelable { Uri.writeToParcel(dest, mUri); if (mMethod != null) { dest.writeInt(1); - dest.writeString(mMethod); + dest.writeString8(mMethod); } else { dest.writeInt(0); } if (mArg != null) { dest.writeInt(1); - dest.writeString(mArg); + dest.writeString8(mArg); } else { dest.writeInt(0); } @@ -159,7 +159,7 @@ public class ContentProviderOperation implements Parcelable { } if (mSelection != null) { dest.writeInt(1); - dest.writeString(mSelection); + dest.writeString8(mSelection); } else { dest.writeInt(0); } @@ -591,7 +591,7 @@ public class ContentProviderOperation implements Parcelable { public BackReference(Parcel src) { this.fromIndex = src.readInt(); if (src.readInt() != 0) { - this.fromKey = src.readString(); + this.fromKey = src.readString8(); } else { this.fromKey = null; } @@ -620,7 +620,7 @@ public class ContentProviderOperation implements Parcelable { dest.writeInt(fromIndex); if (fromKey != null) { dest.writeInt(1); - dest.writeString(fromKey); + dest.writeString8(fromKey); } else { dest.writeInt(0); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index b1d6c830d3b72..def150ab49e51 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -888,8 +888,8 @@ public class Intent implements Parcelable, Cloneable { public ShortcutIconResource createFromParcel(Parcel source) { ShortcutIconResource icon = new ShortcutIconResource(); - icon.packageName = source.readString(); - icon.resourceName = source.readString(); + icon.packageName = source.readString8(); + icon.resourceName = source.readString8(); return icon; } @@ -906,8 +906,8 @@ public class Intent implements Parcelable, Cloneable { } public void writeToParcel(Parcel dest, int flags) { - dest.writeString(packageName); - dest.writeString(resourceName); + dest.writeString8(packageName); + dest.writeString8(resourceName); } @Override @@ -10807,12 +10807,12 @@ public class Intent implements Parcelable, Cloneable { } public void writeToParcel(Parcel out, int flags) { - out.writeString(mAction); + out.writeString8(mAction); Uri.writeToParcel(out, mData); - out.writeString(mType); - out.writeString(mIdentifier); + out.writeString8(mType); + out.writeString8(mIdentifier); out.writeInt(mFlags); - out.writeString(mPackage); + out.writeString8(mPackage); ComponentName.writeToParcel(mComponent, out); if (mSourceBounds != null) { @@ -10826,7 +10826,7 @@ public class Intent implements Parcelable, Cloneable { final int N = mCategories.size(); out.writeInt(N); for (int i=0; i(); int i; for (i=0; i { } static Uri readFrom(Parcel parcel) { - return new StringUri(parcel.readString()); + return new StringUri(parcel.readString8()); } public int describeContents() { @@ -509,7 +509,7 @@ public abstract class Uri implements Parcelable, Comparable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); - parcel.writeString(uriString); + parcel.writeString8(uriString); } /** Cached scheme separator index. */ @@ -875,7 +875,7 @@ public abstract class Uri implements Parcelable, Comparable { static Uri readFrom(Parcel parcel) { return new OpaqueUri( - parcel.readString(), + parcel.readString8(), Part.readFrom(parcel), Part.readFrom(parcel) ); @@ -887,7 +887,7 @@ public abstract class Uri implements Parcelable, Comparable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); - parcel.writeString(scheme); + parcel.writeString8(scheme); ssp.writeTo(parcel); fragment.writeTo(parcel); } @@ -1195,7 +1195,7 @@ public abstract class Uri implements Parcelable, Comparable { static Uri readFrom(Parcel parcel) { return new HierarchicalUri( - parcel.readString(), + parcel.readString8(), Part.readFrom(parcel), PathPart.readFrom(parcel), Part.readFrom(parcel), @@ -1209,7 +1209,7 @@ public abstract class Uri implements Parcelable, Comparable { public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(TYPE_ID); - parcel.writeString(scheme); + parcel.writeString8(scheme); authority.writeTo(parcel); path.writeTo(parcel); query.writeTo(parcel); @@ -2028,7 +2028,7 @@ public abstract class Uri implements Parcelable, Comparable { + mCanonicalRepresentation + ")"); } parcel.writeInt(mCanonicalRepresentation); - parcel.writeString(canonicalValue); + parcel.writeString8(canonicalValue); } } @@ -2060,7 +2060,7 @@ public abstract class Uri implements Parcelable, Comparable { static Part readFrom(Parcel parcel) { int representation = parcel.readInt(); - String value = parcel.readString(); + String value = parcel.readString8(); switch (representation) { case REPRESENTATION_ENCODED: return fromEncoded(value); @@ -2251,9 +2251,9 @@ public abstract class Uri implements Parcelable, Comparable { int representation = parcel.readInt(); switch (representation) { case REPRESENTATION_ENCODED: - return fromEncoded(parcel.readString()); + return fromEncoded(parcel.readString8()); case REPRESENTATION_DECODED: - return fromDecoded(parcel.readString()); + return fromDecoded(parcel.readString8()); default: throw new IllegalArgumentException("Unknown representation: " + representation); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index f0b7b5fa5a1a2..93f6607ff9d46 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -307,7 +307,9 @@ public final class Parcel { @FastNative private static native void nativeWriteDouble(long nativePtr, double val); @FastNative - static native void nativeWriteString(long nativePtr, String val); + private static native void nativeWriteString8(long nativePtr, String val); + @FastNative + private static native void nativeWriteString16(long nativePtr, String val); @FastNative private static native void nativeWriteStrongBinder(long nativePtr, IBinder val); @FastNative @@ -325,7 +327,9 @@ public final class Parcel { @CriticalNative private static native double nativeReadDouble(long nativePtr); @FastNative - static native String nativeReadString(long nativePtr); + private static native String nativeReadString8(long nativePtr); + @FastNative + private static native String nativeReadString16(long nativePtr); @FastNative private static native IBinder nativeReadStrongBinder(long nativePtr); @FastNative @@ -386,8 +390,12 @@ public final class Parcel { * must use {@link #writeStringNoHelper(String)} to avoid * infinity recursive calls. */ - public void writeString(Parcel p, String s) { - nativeWriteString(p.mNativePtr, s); + public void writeString8(Parcel p, String s) { + p.writeString8NoHelper(s); + } + + public void writeString16(Parcel p, String s) { + p.writeString16NoHelper(s); } /** @@ -395,8 +403,12 @@ public final class Parcel { * must use {@link #readStringNoHelper()} to avoid * infinity recursive calls. */ - public String readString(Parcel p) { - return nativeReadString(p.mNativePtr); + public String readString8(Parcel p) { + return p.readString8NoHelper(); + } + + public String readString16(Parcel p) { + return p.readString16NoHelper(); } } @@ -759,7 +771,17 @@ public final class Parcel { * growing dataCapacity() if needed. */ public final void writeString(@Nullable String val) { - mReadWriteHelper.writeString(this, val); + writeString16(val); + } + + /** {@hide} */ + public final void writeString8(@Nullable String val) { + mReadWriteHelper.writeString8(this, val); + } + + /** {@hide} */ + public final void writeString16(@Nullable String val) { + mReadWriteHelper.writeString16(this, val); } /** @@ -770,7 +792,17 @@ public final class Parcel { * @hide */ public void writeStringNoHelper(@Nullable String val) { - nativeWriteString(mNativePtr, val); + writeString16NoHelper(val); + } + + /** {@hide} */ + public void writeString8NoHelper(@Nullable String val) { + nativeWriteString8(mNativePtr, val); + } + + /** {@hide} */ + public void writeString16NoHelper(@Nullable String val) { + nativeWriteString16(mNativePtr, val); } /** @@ -2337,7 +2369,17 @@ public final class Parcel { */ @Nullable public final String readString() { - return mReadWriteHelper.readString(this); + return readString16(); + } + + /** {@hide} */ + public final @Nullable String readString8() { + return mReadWriteHelper.readString8(this); + } + + /** {@hide} */ + public final @Nullable String readString16() { + return mReadWriteHelper.readString16(this); } /** @@ -2347,9 +2389,18 @@ public final class Parcel { * * @hide */ - @Nullable - public String readStringNoHelper() { - return nativeReadString(mNativePtr); + public @Nullable String readStringNoHelper() { + return readString16NoHelper(); + } + + /** {@hide} */ + public @Nullable String readString8NoHelper() { + return nativeReadString8(mNativePtr); + } + + /** {@hide} */ + public @Nullable String readString16NoHelper() { + return nativeReadString16(mNativePtr); } /** diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index df4ead13d5cb5..28639b3ea2f7f 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -748,7 +748,7 @@ public class TextUtils { int parcelableFlags) { if (cs instanceof Spanned) { p.writeInt(0); - p.writeString(cs.toString()); + p.writeString8(cs.toString()); Spanned sp = (Spanned) cs; Object[] os = sp.getSpans(0, cs.length(), Object.class); @@ -785,9 +785,9 @@ public class TextUtils { } else { p.writeInt(1); if (cs != null) { - p.writeString(cs.toString()); + p.writeString8(cs.toString()); } else { - p.writeString(null); + p.writeString8(null); } } } @@ -807,7 +807,7 @@ public class TextUtils { public CharSequence createFromParcel(Parcel p) { int kind = p.readInt(); - String string = p.readString(); + String string = p.readString8(); if (string == null) { return null; } diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 7f6c0d2077f1b..7016c5cf0de6f 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -1213,7 +1213,7 @@ public class RemoteViews implements Parcelable, Filter { BitmapReflectionAction(Parcel in) { viewId = in.readInt(); - methodName = in.readString(); + methodName = in.readString8(); bitmapId = in.readInt(); bitmap = mBitmapCache.getBitmapForId(bitmapId); } @@ -1221,7 +1221,7 @@ public class RemoteViews implements Parcelable, Filter { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(viewId); - dest.writeString(methodName); + dest.writeString8(methodName); dest.writeInt(bitmapId); } @@ -1282,7 +1282,7 @@ public class RemoteViews implements Parcelable, Filter { ReflectionAction(Parcel in) { this.viewId = in.readInt(); - this.methodName = in.readString(); + this.methodName = in.readString8(); this.type = in.readInt(); //noinspection ConstantIfStatement if (false) { @@ -1318,7 +1318,7 @@ public class RemoteViews implements Parcelable, Filter { this.value = (char)in.readInt(); break; case STRING: - this.value = in.readString(); + this.value = in.readString8(); break; case CHAR_SEQUENCE: this.value = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); @@ -1347,7 +1347,7 @@ public class RemoteViews implements Parcelable, Filter { public void writeToParcel(Parcel out, int flags) { out.writeInt(this.viewId); - out.writeString(this.methodName); + out.writeString8(this.methodName); out.writeInt(this.type); //noinspection ConstantIfStatement if (false) { @@ -1383,7 +1383,7 @@ public class RemoteViews implements Parcelable, Filter { out.writeInt((int)((Character)this.value).charValue()); break; case STRING: - out.writeString((String)this.value); + out.writeString8((String)this.value); break; case CHAR_SEQUENCE: TextUtils.writeToParcel((CharSequence)this.value, out, flags); diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index 483b455965f79..e7a2fb428b508 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -273,7 +273,28 @@ static void android_os_Parcel_writeDouble(JNIEnv* env, jclass clazz, jlong nativ } } -static void android_os_Parcel_writeString(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val) +static void android_os_Parcel_writeString8(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val) +{ + Parcel* parcel = reinterpret_cast(nativePtr); + if (parcel != NULL) { + status_t err = NO_MEMORY; + if (val) { + const size_t len = env->GetStringUTFLength(val); + const char* str = env->GetStringUTFChars(val, 0); + if (str) { + err = parcel->writeString8(str, len); + env->ReleaseStringUTFChars(val, str); + } + } else { + err = parcel->writeString8(NULL, 0); + } + if (err != NO_ERROR) { + signalExceptionForError(env, clazz, err); + } + } +} + +static void android_os_Parcel_writeString16(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val) { Parcel* parcel = reinterpret_cast(nativePtr); if (parcel != NULL) { @@ -444,7 +465,21 @@ static jdouble android_os_Parcel_readDouble(jlong nativePtr) return 0; } -static jstring android_os_Parcel_readString(JNIEnv* env, jclass clazz, jlong nativePtr) +static jstring android_os_Parcel_readString8(JNIEnv* env, jclass clazz, jlong nativePtr) +{ + Parcel* parcel = reinterpret_cast(nativePtr); + if (parcel != NULL) { + size_t len; + const char* str = parcel->readString8Inplace(&len); + if (str) { + return env->NewStringUTF(str); + } + return NULL; + } + return NULL; +} + +static jstring android_os_Parcel_readString16(JNIEnv* env, jclass clazz, jlong nativePtr) { Parcel* parcel = reinterpret_cast(nativePtr); if (parcel != NULL) { @@ -722,7 +757,9 @@ static const JNINativeMethod gParcelMethods[] = { // @FastNative {"nativeWriteDouble", "(JD)V", (void*)android_os_Parcel_writeDouble}, // @FastNative - {"nativeWriteString", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString}, + {"nativeWriteString8", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString8}, + // @FastNative + {"nativeWriteString16", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString16}, // @FastNative {"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder}, // @FastNative @@ -740,7 +777,9 @@ static const JNINativeMethod gParcelMethods[] = { // @CriticalNative {"nativeReadDouble", "(J)D", (void*)android_os_Parcel_readDouble}, // @FastNative - {"nativeReadString", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString}, + {"nativeReadString8", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString8}, + // @FastNative + {"nativeReadString16", "(J)Ljava/lang/String;", (void*)android_os_Parcel_readString16}, // @FastNative {"nativeReadStrongBinder", "(J)Landroid/os/IBinder;", (void*)android_os_Parcel_readStrongBinder}, // @FastNative diff --git a/core/tests/benchmarks/src/android/os/ParcelStringBenchmark.java b/core/tests/benchmarks/src/android/os/ParcelStringBenchmark.java new file mode 100644 index 0000000000000..daa90c28e0c42 --- /dev/null +++ b/core/tests/benchmarks/src/android/os/ParcelStringBenchmark.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import com.google.caliper.AfterExperiment; +import com.google.caliper.BeforeExperiment; +import com.google.caliper.Param; + +public class ParcelStringBenchmark { + + @Param({"com.example.typical_package_name", "從不喜歡孤單一個 - 蘇永康/吳雨霏"}) + String mValue; + + private Parcel mParcel; + + @BeforeExperiment + protected void setUp() { + mParcel = Parcel.obtain(); + } + + @AfterExperiment + protected void tearDown() { + mParcel.recycle(); + mParcel = null; + } + + public void timeWriteString8(int reps) { + for (int i = 0; i < reps; i++) { + mParcel.setDataPosition(0); + mParcel.writeString8(mValue); + } + } + + public void timeReadString8(int reps) { + mParcel.writeString8(mValue); + + for (int i = 0; i < reps; i++) { + mParcel.setDataPosition(0); + mParcel.readString8(); + } + } + + public void timeWriteString16(int reps) { + for (int i = 0; i < reps; i++) { + mParcel.setDataPosition(0); + mParcel.writeString16(mValue); + } + } + + public void timeReadString16(int reps) { + mParcel.writeString16(mValue); + + for (int i = 0; i < reps; i++) { + mParcel.setDataPosition(0); + mParcel.readString16(); + } + } +} diff --git a/core/tests/coretests/src/android/os/ParcelTest.java b/core/tests/coretests/src/android/os/ParcelTest.java index 46873b9eb70bd..dcb3e2f23da8b 100644 --- a/core/tests/coretests/src/android/os/ParcelTest.java +++ b/core/tests/coretests/src/android/os/ParcelTest.java @@ -87,4 +87,27 @@ public class ParcelTest { p.recycle(); } + + /** + * Verify that writing/reading UTF-8 and UTF-16 strings works well. + */ + @Test + public void testStrings() { + final String[] strings = { + null, "", "abc\0def", "com.example.typical_package_name", + "從不喜歡孤單一個 - 蘇永康/吳雨霏", "example" + }; + + final Parcel p = Parcel.obtain(); + for (String string : strings) { + p.writeString8(string); + p.writeString16(string); + } + + p.setDataPosition(0); + for (String string : strings) { + assertEquals(string, p.readString8()); + assertEquals(string, p.readString16()); + } + } }