Restrict getInputMethodWindowVisibleHeight

Make sure only the app currently interacting with the IME can
query this, and restrict the API to apps targeting SDKs before T

Fixes: 204906124
Test: atest 'InputMethodManagerTest#getInputMethodWindowVisibleHeight_returnsZeroIfNotFocused'
Change-Id: If1da19a3dd8c29542afc970b4b201d87547c27a9
Merged-In: If1da19a3dd8c29542afc970b4b201d87547c27a9
This commit is contained in:
Adrian Roos
2022-02-16 18:57:24 +01:00
parent 3d18a8e050
commit 2ab01736a6
4 changed files with 55 additions and 21 deletions

View File

@@ -2958,7 +2958,7 @@ public final class InputMethodManager {
@UnsupportedAppUsage @UnsupportedAppUsage
public int getInputMethodWindowVisibleHeight() { public int getInputMethodWindowVisibleHeight() {
try { try {
return mService.getInputMethodWindowVisibleHeight(); return mService.getInputMethodWindowVisibleHeight(mClient);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -67,7 +67,7 @@ interface IInputMethodManager {
void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes); void setAdditionalInputMethodSubtypes(String id, in InputMethodSubtype[] subtypes);
// This is kept due to @UnsupportedAppUsage. // This is kept due to @UnsupportedAppUsage.
// TODO(Bug 113914148): Consider removing this. // TODO(Bug 113914148): Consider removing this.
int getInputMethodWindowVisibleHeight(); int getInputMethodWindowVisibleHeight(in IInputMethodClient client);
oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible); oneway void reportPerceptibleAsync(in IBinder windowToken, boolean perceptible);
/** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */ /** Remove the IME surface. Requires INTERNAL_SYSTEM_WINDOW permission. */

View File

@@ -124,6 +124,7 @@ import android.util.Pair;
import android.util.PrintWriterPrinter; import android.util.PrintWriterPrinter;
import android.util.Printer; import android.util.Printer;
import android.util.Slog; import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.imetracing.ImeTracing; import android.util.imetracing.ImeTracing;
import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager; import android.view.IWindowManager;
@@ -300,6 +301,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final InputMethodSettings mSettings; final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver; final SettingsObserver mSettingsObserver;
final IWindowManager mIWindowManager; final IWindowManager mIWindowManager;
private final SparseBooleanArray mLoggedDeniedGetInputMethodWindowVisibleHeightForUid =
new SparseBooleanArray(0);
final WindowManagerInternal mWindowManagerInternal; final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal; final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal; final InputManagerInternal mInputManagerInternal;
@@ -1331,6 +1334,13 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
clearPackageChangeState(); clearPackageChangeState();
} }
@Override
public void onUidRemoved(int uid) {
synchronized (mMethodMap) {
mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.delete(uid);
}
}
private void clearPackageChangeState() { private void clearPackageChangeState() {
// No need to lock them because we access these fields only on getRegisteredHandler(). // No need to lock them because we access these fields only on getRegisteredHandler().
mChangedPackages.clear(); mChangedPackages.clear();
@@ -3055,22 +3065,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
} }
final long ident = Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity();
try { try {
if (mCurClient == null || client == null if (!canInteractWithImeLocked(uid, client, "showSoftInput")) {
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException(
"unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
Slog.w(TAG, "Ignoring showSoftInput of uid " + uid + ": " + client);
return false; return false;
} }
}
if (DEBUG) Slog.v(TAG, "Client requesting input be shown"); if (DEBUG) Slog.v(TAG, "Client requesting input be shown");
return showCurrentInputLocked(windowToken, flags, resultReceiver, reason); return showCurrentInputLocked(windowToken, flags, resultReceiver, reason);
} finally { } finally {
@@ -3894,9 +3891,46 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
* @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)} * @return {@link WindowManagerInternal#getInputMethodWindowVisibleHeight(int)}
*/ */
@Override @Override
public int getInputMethodWindowVisibleHeight() { @Deprecated
// TODO(yukawa): Should we verify the display ID? public int getInputMethodWindowVisibleHeight(@NonNull IInputMethodClient client) {
return mWindowManagerInternal.getInputMethodWindowVisibleHeight(mCurTokenDisplayId); int callingUid = Binder.getCallingUid();
return Binder.withCleanCallingIdentity(() -> {
final int curTokenDisplayId;
synchronized (mMethodMap) {
if (!canInteractWithImeLocked(callingUid, client,
"getInputMethodWindowVisibleHeight")) {
if (!mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.get(callingUid)) {
EventLog.writeEvent(0x534e4554, "204906124", callingUid, "");
mLoggedDeniedGetInputMethodWindowVisibleHeightForUid.put(callingUid, true);
}
return 0;
}
// This should probably use the caller's display id, but because this is unsupported
// and maintained only for compatibility, there's no point in fixing it.
curTokenDisplayId = mCurTokenDisplayId;
}
return mWindowManagerInternal.getInputMethodWindowVisibleHeight(curTokenDisplayId);
});
}
private boolean canInteractWithImeLocked(int callingUid, IInputMethodClient client,
String method) {
if (mCurClient == null || client == null
|| mCurClient.client.asBinder() != client.asBinder()) {
// We need to check if this is the current client with
// focus in the window manager, to allow this call to
// be made before input is started in it.
final ClientState cs = mClients.get(client.asBinder());
if (cs == null) {
throw new IllegalArgumentException("unknown client " + client.asBinder());
}
if (!mWindowManagerInternal.isInputMethodClientFocus(cs.uid, cs.pid,
cs.selfReportedDisplayId)) {
Slog.w(TAG, "Ignoring " + method + " of uid " + callingUid + ": " + client);
return false;
}
}
return true;
} }
@Override @Override

View File

@@ -1803,7 +1803,7 @@ public final class MultiClientInputMethodManagerService {
@BinderThread @BinderThread
@Override @Override
public int getInputMethodWindowVisibleHeight() { public int getInputMethodWindowVisibleHeight(IInputMethodClient client) {
reportNotSupported(); reportNotSupported();
return 0; return 0;
} }