diff --git a/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java b/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java new file mode 100644 index 0000000000000..2b861cb668909 --- /dev/null +++ b/apct-tests/perftests/core/src/android/os/ParcelStringPerfTest.java @@ -0,0 +1,70 @@ +/* + * 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 android.perftests.utils.BenchmarkState; +import android.perftests.utils.PerfStatusReporter; + +import androidx.test.filters.LargeTest; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; + +@LargeTest +@RunWith(Parameterized.class) +public class ParcelStringPerfTest { + @Rule + public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); + + @Parameterized.Parameter(0) + public String mName; + @Parameterized.Parameter(1) + public String mValue; + + @Parameterized.Parameters(name = "{0}") + public static Collection getParameters() { + return Arrays.asList(new Object[][] { + { "simple", "com.example.typical_package_name" }, + { "complex", "從不喜歡孤單一個 - 蘇永康/吳雨霏" }, + }); + } + + @Test + public void timeWriteString8() { + final Parcel parcel = Parcel.obtain(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + parcel.setDataPosition(0); + parcel.writeString8(mValue); + } + } + + @Test + public void timeWriteString16() { + final Parcel parcel = Parcel.obtain(); + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + parcel.setDataPosition(0); + parcel.writeString16(mValue); + } + } +} diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index 355ef0cd6b3f9..f05c6a42c5f72 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -252,20 +252,25 @@ static void android_os_Parcel_nativeSignalExceptionForError(JNIEnv* env, jclass signalExceptionForError(env, clazz, err); } -static void android_os_Parcel_writeString8(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 (parcel != nullptr) { + status_t err = NO_ERROR; 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); + // NOTE: Keep this logic in sync with Parcel.cpp + const size_t len = env->GetStringLength(val); + const size_t allocLen = env->GetStringUTFLength(val); + err = parcel->writeInt32(allocLen); + char *data = reinterpret_cast(parcel->writeInplace(allocLen + sizeof(char))); + if (data != nullptr) { + env->GetStringUTFRegion(val, 0, len, data); + *(data + allocLen) = 0; + } else { + err = NO_MEMORY; } } else { - err = parcel->writeString8(NULL, 0); + err = parcel->writeString8(nullptr, 0); } if (err != NO_ERROR) { signalExceptionForError(env, clazz, err); @@ -273,21 +278,25 @@ static void android_os_Parcel_writeString8(JNIEnv* env, jclass clazz, jlong nati } } -static void android_os_Parcel_writeString16(JNIEnv* env, jclass clazz, jlong nativePtr, jstring val) -{ +static void android_os_Parcel_writeString16(JNIEnv *env, jclass clazz, jlong nativePtr, + jstring val) { Parcel* parcel = reinterpret_cast(nativePtr); - if (parcel != NULL) { - status_t err = NO_MEMORY; + if (parcel != nullptr) { + status_t err = NO_ERROR; if (val) { - const jchar* str = env->GetStringCritical(val, 0); - if (str) { - err = parcel->writeString16( - reinterpret_cast(str), - env->GetStringLength(val)); - env->ReleaseStringCritical(val, str); + // NOTE: Keep this logic in sync with Parcel.cpp + const size_t len = env->GetStringLength(val); + const size_t allocLen = len * sizeof(char16_t); + err = parcel->writeInt32(len); + char *data = reinterpret_cast(parcel->writeInplace(allocLen + sizeof(char16_t))); + if (data != nullptr) { + env->GetStringRegion(val, 0, len, reinterpret_cast(data)); + *reinterpret_cast(data + allocLen) = 0; + } else { + err = NO_MEMORY; } } else { - err = parcel->writeString16(NULL, 0); + err = parcel->writeString16(nullptr, 0); } if (err != NO_ERROR) { signalExceptionForError(env, clazz, err);