Merge "Fix error swallowing in InputConnectionCommand unparcelling"

This commit is contained in:
Yohei Yukawa
2021-07-27 16:11:53 +00:00
committed by Android (Google) Code Review
2 changed files with 68 additions and 21 deletions

View File

@@ -23,12 +23,12 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.BadParcelableException;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
@@ -356,14 +356,24 @@ public final class InputConnectionCommand implements Parcelable {
| (mResultCallbackType != ResultCallbackType.NULL ? FieldMask.CALLBACK : 0);
}
/**
* A utility method to unparcel {@link InputConnectionCommand} from the given {@link Parcel}.
*
* <p>When this method throws any {@link RuntimeException} or its derived class, notably
* {@link BadParcelableException}, {@code source} is considered to be in an unexpected state and
* unsafe to continue reading any subsequent data.</p>
*
* @param source {@link Parcel} to read the data from.
* @return {@link InputConnectionCommand} that is parcelled from {@code source}.
*/
@AnyThread
@Nullable
@NonNull
private static InputConnectionCommand createFromParcel(@NonNull Parcel source) {
final int type = source.readInt();
if (type < InputConnectionCommandType.FIRST_COMMAND
|| InputConnectionCommandType.LAST_COMMAND < type) {
Log.e(TAG, "Invalid InputConnectionCommand type=" + type);
return null;
throw new BadParcelableException("Invalid InputConnectionCommandType=" + type);
}
@FieldMask final int fieldMask = source.readInt();
@@ -380,9 +390,6 @@ public final class InputConnectionCommand implements Parcelable {
if ((fieldMask & FieldMask.PARCELABLE) != 0) {
parcelableType = source.readInt();
switch (parcelableType) {
case ParcelableType.NULL:
Log.e(TAG, "Unexpected ParcelableType=NULL");
return null;
case ParcelableType.EXTRACTED_TEXT_REQUEST:
parcelable = source.readTypedObject(ExtractedTextRequest.CREATOR);
break;
@@ -399,8 +406,8 @@ public final class InputConnectionCommand implements Parcelable {
parcelable = source.readTypedObject(InputContentInfo.CREATOR);
break;
default:
Log.e(TAG, "Unknown ParcelableType=" + parcelableType);
return null;
throw new BadParcelableException(
"Invalid InputConnectionCommand.ParcelableType=" + parcelableType);
}
} else {
parcelableType = ParcelableType.NULL;
@@ -411,9 +418,6 @@ public final class InputConnectionCommand implements Parcelable {
if ((fieldMask & FieldMask.CALLBACK) != 0) {
resultCallbackType = source.readInt();
switch (resultCallbackType) {
case ResultCallbackType.NULL:
Log.e(TAG, "Unexpected ResultCallbackType=NULL");
return null;
case ResultCallbackType.BOOLEAN:
case ResultCallbackType.INT:
case ResultCallbackType.CHAR_SEQUENCE:
@@ -422,8 +426,9 @@ public final class InputConnectionCommand implements Parcelable {
resultCallback = source.readStrongBinder();
break;
default:
Log.e(TAG, "Unknown ResultCallbackType=" + resultCallbackType);
return null;
throw new BadParcelableException(
"Invalid InputConnectionCommand.ResultCallbackType="
+ resultCallbackType);
}
} else {
resultCallbackType = ResultCallbackType.NULL;
@@ -439,15 +444,10 @@ public final class InputConnectionCommand implements Parcelable {
public static final Parcelable.Creator<InputConnectionCommand> CREATOR =
new Parcelable.Creator<InputConnectionCommand>() {
@AnyThread
@Nullable
@NonNull
@Override
public InputConnectionCommand createFromParcel(Parcel source) {
try {
return InputConnectionCommand.createFromParcel(source);
} catch (Exception e) {
Log.e(TAG, "Returning null due to exception.", e);
return null;
}
return InputConnectionCommand.createFromParcel(source);
}
@AnyThread

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2021 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 com.android.internal.inputmethod;
import static org.junit.Assert.assertThrows;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class InputConnectionCommandTest {
@Test
public void testCreateFromParcelDoesNotSwallowExceptions() {
final Parcel parcel = Parcel.obtain();
try {
parcel.writeInt(InputConnectionCommandType.FIRST_COMMAND);
parcel.writeInt(InputConnectionCommand.FieldMask.PARCELABLE);
parcel.writeInt(InputConnectionCommand.ParcelableType.NULL); // invalid
assertThrows(RuntimeException.class,
() -> InputConnectionCommand.CREATOR.createFromParcel(parcel));
} finally {
parcel.recycle();
}
}
}