Merge changes from topic "sep11"
* changes: Remove advisory registerNativeAllocation(). Hand-rolled linked list for Parcel performance.
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2016 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 androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@LargeTest
|
||||
public class ParcelObtainPerfTest {
|
||||
private static final int ITERATIONS = 1_000_000;
|
||||
|
||||
@Test
|
||||
public void timeContention_01() throws Exception {
|
||||
timeContention(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeContention_04() throws Exception {
|
||||
timeContention(4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeContention_16() throws Exception {
|
||||
timeContention(16);
|
||||
}
|
||||
|
||||
private static void timeContention(int numThreads) throws Exception {
|
||||
final long start = SystemClock.elapsedRealtime();
|
||||
{
|
||||
final ObtainThread[] threads = new ObtainThread[numThreads];
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
final ObtainThread thread = new ObtainThread(ITERATIONS / numThreads);
|
||||
thread.start();
|
||||
threads[i] = thread;
|
||||
}
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
final long duration = SystemClock.elapsedRealtime() - start;
|
||||
|
||||
final Bundle results = new Bundle();
|
||||
results.putLong("duration", duration);
|
||||
InstrumentationRegistry.getInstrumentation().sendStatus(0, results);
|
||||
}
|
||||
|
||||
public static class ObtainThread extends Thread {
|
||||
public int iterations;
|
||||
|
||||
public ObtainThread(int iterations) {
|
||||
this.iterations = iterations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (iterations-- > 0) {
|
||||
final Parcel data = Parcel.obtain();
|
||||
final Parcel reply = Parcel.obtain();
|
||||
try {
|
||||
data.writeInt(32);
|
||||
reply.writeInt(32);
|
||||
} finally {
|
||||
reply.recycle();
|
||||
data.recycle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,21 +158,6 @@ public class ParcelPerfTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeObtainRecycle() {
|
||||
// Use up the pooled instances.
|
||||
// A lot bigger than the actual size but in case someone increased it.
|
||||
final int POOL_SIZE = 100;
|
||||
for (int i = 0; i < POOL_SIZE; i++) {
|
||||
Parcel.obtain();
|
||||
}
|
||||
|
||||
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
|
||||
while (state.keepRunning()) {
|
||||
Parcel.obtain().recycle();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeWriteException() {
|
||||
timeWriteException(false);
|
||||
|
||||
@@ -33,9 +33,10 @@ import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import dalvik.annotation.optimization.CriticalNative;
|
||||
import dalvik.annotation.optimization.FastNative;
|
||||
import dalvik.system.VMRuntime;
|
||||
|
||||
import libcore.util.ArrayUtils;
|
||||
import libcore.util.SneakyThrow;
|
||||
@@ -222,9 +223,31 @@ public final class Parcel {
|
||||
*/
|
||||
private static boolean sParcelExceptionStackTrace;
|
||||
|
||||
private static final int POOL_SIZE = 6;
|
||||
private static final Parcel[] sOwnedPool = new Parcel[POOL_SIZE];
|
||||
private static final Parcel[] sHolderPool = new Parcel[POOL_SIZE];
|
||||
private static final Object sPoolSync = new Object();
|
||||
|
||||
/** Next item in the linked list pool, if any */
|
||||
@GuardedBy("sPoolSync")
|
||||
private Parcel mPoolNext;
|
||||
|
||||
/** Head of a linked list pool of {@link Parcel} objects */
|
||||
@GuardedBy("sPoolSync")
|
||||
private static Parcel sOwnedPool;
|
||||
/** Head of a linked list pool of {@link Parcel} objects */
|
||||
@GuardedBy("sPoolSync")
|
||||
private static Parcel sHolderPool;
|
||||
|
||||
/** Total size of pool with head at {@link #sOwnedPool} */
|
||||
@GuardedBy("sPoolSync")
|
||||
private static int sOwnedPoolSize = 0;
|
||||
/** Total size of pool with head at {@link #sHolderPool} */
|
||||
@GuardedBy("sPoolSync")
|
||||
private static int sHolderPoolSize = 0;
|
||||
|
||||
/**
|
||||
* We're willing to pool up to 32 objects, which is sized to accommodate
|
||||
* both a data and reply Parcel for the maximum of 16 Binder threads.
|
||||
*/
|
||||
private static final int POOL_SIZE = 32;
|
||||
|
||||
// Keep in sync with frameworks/native/include/private/binder/ParcelValTypes.h.
|
||||
private static final int VAL_NULL = -1;
|
||||
@@ -285,7 +308,7 @@ public final class Parcel {
|
||||
@CriticalNative
|
||||
private static native int nativeDataCapacity(long nativePtr);
|
||||
@FastNative
|
||||
private static native long nativeSetDataSize(long nativePtr, int size);
|
||||
private static native void nativeSetDataSize(long nativePtr, int size);
|
||||
@CriticalNative
|
||||
private static native void nativeSetDataPosition(long nativePtr, int pos);
|
||||
@FastNative
|
||||
@@ -314,7 +337,7 @@ public final class Parcel {
|
||||
@FastNative
|
||||
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
|
||||
@FastNative
|
||||
private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
|
||||
private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
|
||||
|
||||
private static native byte[] nativeCreateByteArray(long nativePtr);
|
||||
private static native boolean nativeReadByteArray(long nativePtr, byte[] dest, int destLen);
|
||||
@@ -337,14 +360,14 @@ public final class Parcel {
|
||||
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
|
||||
|
||||
private static native long nativeCreate();
|
||||
private static native long nativeFreeBuffer(long nativePtr);
|
||||
private static native void nativeFreeBuffer(long nativePtr);
|
||||
private static native void nativeDestroy(long nativePtr);
|
||||
|
||||
private static native byte[] nativeMarshall(long nativePtr);
|
||||
private static native long nativeUnmarshall(
|
||||
private static native void nativeUnmarshall(
|
||||
long nativePtr, byte[] data, int offset, int length);
|
||||
private static native int nativeCompareData(long thisNativePtr, long otherNativePtr);
|
||||
private static native long nativeAppendFrom(
|
||||
private static native void nativeAppendFrom(
|
||||
long thisNativePtr, long otherNativePtr, int offset, int length);
|
||||
@CriticalNative
|
||||
private static native boolean nativeHasFileDescriptors(long nativePtr);
|
||||
@@ -420,22 +443,27 @@ public final class Parcel {
|
||||
*/
|
||||
@NonNull
|
||||
public static Parcel obtain() {
|
||||
final Parcel[] pool = sOwnedPool;
|
||||
synchronized (pool) {
|
||||
Parcel p;
|
||||
for (int i=0; i<POOL_SIZE; i++) {
|
||||
p = pool[i];
|
||||
if (p != null) {
|
||||
pool[i] = null;
|
||||
if (DEBUG_RECYCLE) {
|
||||
p.mStack = new RuntimeException();
|
||||
}
|
||||
p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
|
||||
return p;
|
||||
}
|
||||
Parcel res = null;
|
||||
synchronized (sPoolSync) {
|
||||
if (sOwnedPool != null) {
|
||||
res = sOwnedPool;
|
||||
sOwnedPool = res.mPoolNext;
|
||||
res.mPoolNext = null;
|
||||
sOwnedPoolSize--;
|
||||
}
|
||||
}
|
||||
return new Parcel(0);
|
||||
|
||||
// When no cache found above, create from scratch; otherwise prepare the
|
||||
// cached object to be used
|
||||
if (res == null) {
|
||||
res = new Parcel(0);
|
||||
} else {
|
||||
if (DEBUG_RECYCLE) {
|
||||
res.mStack = new RuntimeException();
|
||||
}
|
||||
res.mReadWriteHelper = ReadWriteHelper.DEFAULT;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -446,19 +474,21 @@ public final class Parcel {
|
||||
if (DEBUG_RECYCLE) mStack = null;
|
||||
freeBuffer();
|
||||
|
||||
final Parcel[] pool;
|
||||
if (mOwnsNativeParcelObject) {
|
||||
pool = sOwnedPool;
|
||||
synchronized (sPoolSync) {
|
||||
if (sOwnedPoolSize < POOL_SIZE) {
|
||||
mPoolNext = sOwnedPool;
|
||||
sOwnedPool = this;
|
||||
sOwnedPoolSize++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mNativePtr = 0;
|
||||
pool = sHolderPool;
|
||||
}
|
||||
|
||||
synchronized (pool) {
|
||||
for (int i=0; i<POOL_SIZE; i++) {
|
||||
if (pool[i] == null) {
|
||||
pool[i] = this;
|
||||
return;
|
||||
synchronized (sPoolSync) {
|
||||
if (sHolderPoolSize < POOL_SIZE) {
|
||||
mPoolNext = sHolderPool;
|
||||
sHolderPool = this;
|
||||
sHolderPoolSize++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,7 +562,7 @@ public final class Parcel {
|
||||
* @param size The new number of bytes in the Parcel.
|
||||
*/
|
||||
public final void setDataSize(int size) {
|
||||
updateNativeSize(nativeSetDataSize(mNativePtr, size));
|
||||
nativeSetDataSize(mNativePtr, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -584,11 +614,11 @@ public final class Parcel {
|
||||
* Set the bytes in data to be the raw bytes of this Parcel.
|
||||
*/
|
||||
public final void unmarshall(@NonNull byte[] data, int offset, int length) {
|
||||
updateNativeSize(nativeUnmarshall(mNativePtr, data, offset, length));
|
||||
nativeUnmarshall(mNativePtr, data, offset, length);
|
||||
}
|
||||
|
||||
public final void appendFrom(Parcel parcel, int offset, int length) {
|
||||
updateNativeSize(nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length));
|
||||
nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -871,24 +901,7 @@ public final class Parcel {
|
||||
* if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
|
||||
*/
|
||||
public final void writeFileDescriptor(@NonNull FileDescriptor val) {
|
||||
updateNativeSize(nativeWriteFileDescriptor(mNativePtr, val));
|
||||
}
|
||||
|
||||
private void updateNativeSize(long newNativeSize) {
|
||||
if (mOwnsNativeParcelObject) {
|
||||
if (newNativeSize > Integer.MAX_VALUE) {
|
||||
newNativeSize = Integer.MAX_VALUE;
|
||||
}
|
||||
if (newNativeSize != mNativeSize) {
|
||||
int delta = (int) (newNativeSize - mNativeSize);
|
||||
if (delta > 0) {
|
||||
VMRuntime.getRuntime().registerNativeAllocation(delta);
|
||||
} else {
|
||||
VMRuntime.getRuntime().registerNativeFree(-delta);
|
||||
}
|
||||
mNativeSize = newNativeSize;
|
||||
}
|
||||
}
|
||||
nativeWriteFileDescriptor(mNativePtr, val);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3496,22 +3509,27 @@ public final class Parcel {
|
||||
|
||||
/** @hide */
|
||||
static protected final Parcel obtain(long obj) {
|
||||
final Parcel[] pool = sHolderPool;
|
||||
synchronized (pool) {
|
||||
Parcel p;
|
||||
for (int i=0; i<POOL_SIZE; i++) {
|
||||
p = pool[i];
|
||||
if (p != null) {
|
||||
pool[i] = null;
|
||||
if (DEBUG_RECYCLE) {
|
||||
p.mStack = new RuntimeException();
|
||||
}
|
||||
p.init(obj);
|
||||
return p;
|
||||
}
|
||||
Parcel res = null;
|
||||
synchronized (sPoolSync) {
|
||||
if (sHolderPool != null) {
|
||||
res = sHolderPool;
|
||||
sHolderPool = res.mPoolNext;
|
||||
res.mPoolNext = null;
|
||||
sHolderPoolSize--;
|
||||
}
|
||||
}
|
||||
return new Parcel(obj);
|
||||
|
||||
// When no cache found above, create from scratch; otherwise prepare the
|
||||
// cached object to be used
|
||||
if (res == null) {
|
||||
res = new Parcel(obj);
|
||||
} else {
|
||||
if (DEBUG_RECYCLE) {
|
||||
res.mStack = new RuntimeException();
|
||||
}
|
||||
res.init(obj);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private Parcel(long nativePtr) {
|
||||
@@ -3535,7 +3553,7 @@ public final class Parcel {
|
||||
private void freeBuffer() {
|
||||
resetSqaushingState();
|
||||
if (mOwnsNativeParcelObject) {
|
||||
updateNativeSize(nativeFreeBuffer(mNativePtr));
|
||||
nativeFreeBuffer(mNativePtr);
|
||||
}
|
||||
mReadWriteHelper = ReadWriteHelper.DEFAULT;
|
||||
}
|
||||
@@ -3545,7 +3563,6 @@ public final class Parcel {
|
||||
if (mNativePtr != 0) {
|
||||
if (mOwnsNativeParcelObject) {
|
||||
nativeDestroy(mNativePtr);
|
||||
updateNativeSize(0);
|
||||
}
|
||||
mNativePtr = 0;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ static jint android_os_Parcel_dataCapacity(jlong nativePtr)
|
||||
return parcel ? parcel->dataCapacity() : 0;
|
||||
}
|
||||
|
||||
static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
|
||||
static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
|
||||
{
|
||||
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
|
||||
if (parcel != NULL) {
|
||||
@@ -122,9 +122,7 @@ static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nati
|
||||
if (err != NO_ERROR) {
|
||||
signalExceptionForError(env, clazz, err);
|
||||
}
|
||||
return parcel->getOpenAshmemSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void android_os_Parcel_setDataPosition(jlong nativePtr, jint pos)
|
||||
@@ -308,7 +306,7 @@ static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong
|
||||
}
|
||||
}
|
||||
|
||||
static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
|
||||
static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
|
||||
{
|
||||
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
|
||||
if (parcel != NULL) {
|
||||
@@ -317,9 +315,7 @@ static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jl
|
||||
if (err != NO_ERROR) {
|
||||
signalExceptionForError(env, clazz, err);
|
||||
}
|
||||
return parcel->getOpenAshmemSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jlong nativePtr)
|
||||
@@ -506,14 +502,12 @@ static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
|
||||
return reinterpret_cast<jlong>(parcel);
|
||||
}
|
||||
|
||||
static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
|
||||
static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
|
||||
{
|
||||
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
|
||||
if (parcel != NULL) {
|
||||
parcel->freeData();
|
||||
return parcel->getOpenAshmemSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
|
||||
@@ -551,12 +545,12 @@ static jbyteArray android_os_Parcel_marshall(JNIEnv* env, jclass clazz, jlong na
|
||||
return ret;
|
||||
}
|
||||
|
||||
static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
|
||||
static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
|
||||
jbyteArray data, jint offset, jint length)
|
||||
{
|
||||
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
|
||||
if (parcel == NULL || length < 0) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
|
||||
@@ -570,7 +564,6 @@ static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativ
|
||||
|
||||
env->ReleasePrimitiveArrayCritical(data, array, 0);
|
||||
}
|
||||
return parcel->getOpenAshmemSize();
|
||||
}
|
||||
|
||||
static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisNativePtr,
|
||||
@@ -588,23 +581,23 @@ static jint android_os_Parcel_compareData(JNIEnv* env, jclass clazz, jlong thisN
|
||||
return thisParcel->compareData(*otherParcel);
|
||||
}
|
||||
|
||||
static jlong android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
|
||||
static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
|
||||
jlong otherNativePtr, jint offset, jint length)
|
||||
{
|
||||
Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
|
||||
if (thisParcel == NULL) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
|
||||
if (otherParcel == NULL) {
|
||||
return thisParcel->getOpenAshmemSize();
|
||||
return;
|
||||
}
|
||||
|
||||
status_t err = thisParcel->appendFrom(otherParcel, offset, length);
|
||||
if (err != NO_ERROR) {
|
||||
signalExceptionForError(env, clazz, err);
|
||||
}
|
||||
return thisParcel->getOpenAshmemSize();
|
||||
return;
|
||||
}
|
||||
|
||||
static jboolean android_os_Parcel_hasFileDescriptors(jlong nativePtr)
|
||||
@@ -720,7 +713,7 @@ static const JNINativeMethod gParcelMethods[] = {
|
||||
// @CriticalNative
|
||||
{"nativeDataCapacity", "(J)I", (void*)android_os_Parcel_dataCapacity},
|
||||
// @FastNative
|
||||
{"nativeSetDataSize", "(JI)J", (void*)android_os_Parcel_setDataSize},
|
||||
{"nativeSetDataSize", "(JI)V", (void*)android_os_Parcel_setDataSize},
|
||||
// @CriticalNative
|
||||
{"nativeSetDataPosition", "(JI)V", (void*)android_os_Parcel_setDataPosition},
|
||||
// @FastNative
|
||||
@@ -749,7 +742,7 @@ static const JNINativeMethod gParcelMethods[] = {
|
||||
// @FastNative
|
||||
{"nativeWriteStrongBinder", "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
|
||||
// @FastNative
|
||||
{"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
|
||||
{"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
|
||||
|
||||
{"nativeCreateByteArray", "(J)[B", (void*)android_os_Parcel_createByteArray},
|
||||
{"nativeReadByteArray", "(J[BI)Z", (void*)android_os_Parcel_readByteArray},
|
||||
@@ -772,13 +765,13 @@ static const JNINativeMethod gParcelMethods[] = {
|
||||
{"nativeReadFileDescriptor", "(J)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_readFileDescriptor},
|
||||
|
||||
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
|
||||
{"nativeFreeBuffer", "(J)J", (void*)android_os_Parcel_freeBuffer},
|
||||
{"nativeFreeBuffer", "(J)V", (void*)android_os_Parcel_freeBuffer},
|
||||
{"nativeDestroy", "(J)V", (void*)android_os_Parcel_destroy},
|
||||
|
||||
{"nativeMarshall", "(J)[B", (void*)android_os_Parcel_marshall},
|
||||
{"nativeUnmarshall", "(J[BII)J", (void*)android_os_Parcel_unmarshall},
|
||||
{"nativeUnmarshall", "(J[BII)V", (void*)android_os_Parcel_unmarshall},
|
||||
{"nativeCompareData", "(JJ)I", (void*)android_os_Parcel_compareData},
|
||||
{"nativeAppendFrom", "(JJII)J", (void*)android_os_Parcel_appendFrom},
|
||||
{"nativeAppendFrom", "(JJII)V", (void*)android_os_Parcel_appendFrom},
|
||||
// @CriticalNative
|
||||
{"nativeHasFileDescriptors", "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
|
||||
{"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
|
||||
|
||||
Reference in New Issue
Block a user