Introduce IInputMethodManagerGlobal
In reality methods defined in IInputMethodManager are no more or less
than a set of global methods, because you can write the following
logic anywhere.
var service = IInputMethodManager.Stub.asInterface(
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
if (service != null) {
try {
service.doSomething();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
With above observation, this CL introduces IInputMethodManagerGlobal
as a collection of static methods that invoke methods defined in
IInputMethodManager so that other framework classes do not need to
write the same piece of code.
public final class IInputMethodManagerGlobal {
public static void doSomething() {
final var service = getService();
if (service != null) {
try {
service.doSomething();
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
}
}
......
}
This CL then simplifies ImeTracing to demonstrate how
IInputMethodManagerGlobal can be used.
Basically this is a mechanical refactoring. There should be no
observable behavior change.
Bug: 234882948
Test: presubmit
Change-Id: I5412eb1d44e3d515ca955f00a2e777b659a15b14
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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 android.annotation.AnyThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresNoPermission;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
|
||||
import com.android.internal.view.IInputMethodManager;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* A global wrapper to directly invoke {@link IInputMethodManager} IPCs.
|
||||
*
|
||||
* <p>All public static methods are guaranteed to be thread-safe.</p>
|
||||
*
|
||||
* <p>All public methods are guaranteed to do nothing when {@link IInputMethodManager} is
|
||||
* unavailable.</p>
|
||||
*/
|
||||
public final class IInputMethodManagerGlobal {
|
||||
@Nullable
|
||||
private static volatile IInputMethodManager sServiceCache = null;
|
||||
|
||||
/**
|
||||
* @return {@code true} if {@link IInputMethodManager} is available.
|
||||
*/
|
||||
@AnyThread
|
||||
public static boolean isAvailable() {
|
||||
return getService() != null;
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
@Nullable
|
||||
private static IInputMethodManager getService() {
|
||||
IInputMethodManager service = sServiceCache;
|
||||
if (service == null) {
|
||||
service = IInputMethodManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.INPUT_METHOD_SERVICE));
|
||||
if (service == null) {
|
||||
return null;
|
||||
}
|
||||
sServiceCache = service;
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
private static void handleRemoteExceptionOrRethrow(@NonNull RemoteException e,
|
||||
@Nullable Consumer<RemoteException> exceptionHandler) {
|
||||
if (exceptionHandler != null) {
|
||||
exceptionHandler.accept(e);
|
||||
} else {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IInputMethodManager#startProtoDump(byte[], int, String)}.
|
||||
*
|
||||
* @param protoDump client or service side information to be stored by the server
|
||||
* @param source where the information is coming from, refer to
|
||||
* {@link ImeTracing#IME_TRACING_FROM_CLIENT} and
|
||||
* {@link ImeTracing#IME_TRACING_FROM_IMS}
|
||||
* @param where where the information is coming from.
|
||||
* @param exceptionHandler an optional {@link RemoteException} handler.
|
||||
*/
|
||||
@RequiresNoPermission
|
||||
@AnyThread
|
||||
public static void startProtoDump(byte[] protoDump, int source, String where,
|
||||
@Nullable Consumer<RemoteException> exceptionHandler) {
|
||||
final IInputMethodManager service = getService();
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
service.startProtoDump(protoDump, source, where);
|
||||
} catch (RemoteException e) {
|
||||
handleRemoteExceptionOrRethrow(e, exceptionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IInputMethodManager#startImeTrace()}.
|
||||
*
|
||||
* @param exceptionHandler an optional {@link RemoteException} handler.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
|
||||
@AnyThread
|
||||
public static void startImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) {
|
||||
final IInputMethodManager service = getService();
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
service.startImeTrace();
|
||||
} catch (RemoteException e) {
|
||||
handleRemoteExceptionOrRethrow(e, exceptionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IInputMethodManager#stopImeTrace()}.
|
||||
*
|
||||
* @param exceptionHandler an optional {@link RemoteException} handler.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
|
||||
@AnyThread
|
||||
public static void stopImeTrace(@Nullable Consumer<RemoteException> exceptionHandler) {
|
||||
final IInputMethodManager service = getService();
|
||||
if (service == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
service.stopImeTrace();
|
||||
} catch (RemoteException e) {
|
||||
handleRemoteExceptionOrRethrow(e, exceptionHandler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link IInputMethodManager#isImeTraceEnabled()}.
|
||||
*
|
||||
* @return The return value of {@link IInputMethodManager#isImeTraceEnabled()}.
|
||||
*/
|
||||
@RequiresNoPermission
|
||||
@AnyThread
|
||||
public static boolean isImeTraceEnabled() {
|
||||
final IInputMethodManager service = getService();
|
||||
if (service == null) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return service.isImeTraceEnabled();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,16 +19,10 @@ package com.android.internal.inputmethod;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.app.ActivityThread;
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.android.internal.view.IInputMethodManager;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
@@ -49,16 +43,12 @@ public abstract class ImeTracing {
|
||||
|
||||
private static ImeTracing sInstance;
|
||||
static boolean sEnabled = false;
|
||||
IInputMethodManager mService;
|
||||
|
||||
private final boolean mIsAvailable = IInputMethodManagerGlobal.isAvailable();
|
||||
|
||||
protected boolean mDumpInProgress;
|
||||
protected final Object mDumpInProgressLock = new Object();
|
||||
|
||||
ImeTracing() throws ServiceNotFoundException {
|
||||
mService = IInputMethodManager.Stub.asInterface(
|
||||
ServiceManager.getServiceOrThrow(Context.INPUT_METHOD_SERVICE));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of {@link ImeTracingServerImpl} when called from a server side class
|
||||
* and an instance of {@link ImeTracingClientImpl} when called from a client side class.
|
||||
@@ -68,11 +58,14 @@ public abstract class ImeTracing {
|
||||
*/
|
||||
public static ImeTracing getInstance() {
|
||||
if (sInstance == null) {
|
||||
try {
|
||||
sInstance = isSystemProcess()
|
||||
? new ImeTracingServerImpl() : new ImeTracingClientImpl();
|
||||
} catch (RemoteException | ServiceNotFoundException e) {
|
||||
Log.e(TAG, "Exception while creating ImeTracing instance", e);
|
||||
if (isSystemProcess()) {
|
||||
sInstance = new ImeTracingServerImpl();
|
||||
} else {
|
||||
try {
|
||||
sInstance = new ImeTracingClientImpl();
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(TAG, "Exception while creating ImeTracingClientImpl instance", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sInstance;
|
||||
@@ -87,32 +80,25 @@ public abstract class ImeTracing {
|
||||
* and {@see #IME_TRACING_FROM_IMS}
|
||||
* @param where
|
||||
*/
|
||||
public void sendToService(byte[] protoDump, int source, String where) throws RemoteException {
|
||||
mService.startProtoDump(protoDump, source, where);
|
||||
public void sendToService(byte[] protoDump, int source, String where) {
|
||||
IInputMethodManagerGlobal.startProtoDump(protoDump, source, where,
|
||||
e -> Log.e(TAG, "Exception while sending ime-related dump to server", e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling {@link IInputMethodManager#startImeTrace()}} to capture IME trace.
|
||||
* Start IME trace.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
|
||||
public final void startImeTrace() {
|
||||
try {
|
||||
mService.startImeTrace();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not start ime trace." + e);
|
||||
}
|
||||
IInputMethodManagerGlobal.startImeTrace(e -> Log.e(TAG, "Could not start ime trace.", e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling {@link IInputMethodManager#stopImeTrace()} to stop IME trace.
|
||||
* Stop IME trace.
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.CONTROL_UI_TRACING)
|
||||
public final void stopImeTrace() {
|
||||
try {
|
||||
mService.stopImeTrace();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not stop ime trace." + e);
|
||||
}
|
||||
IInputMethodManagerGlobal.stopImeTrace(e -> Log.e(TAG, "Could not stop ime trace.", e));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +179,7 @@ public abstract class ImeTracing {
|
||||
* @return {@code true} if tracing is available, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isAvailable() {
|
||||
return mService != null;
|
||||
return mIsAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,9 +18,6 @@ package com.android.internal.inputmethod;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
@@ -30,8 +27,8 @@ import java.io.PrintWriter;
|
||||
* An implementation of {@link ImeTracing} for non system_server processes.
|
||||
*/
|
||||
class ImeTracingClientImpl extends ImeTracing {
|
||||
ImeTracingClientImpl() throws ServiceNotFoundException, RemoteException {
|
||||
sEnabled = mService.isImeTraceEnabled();
|
||||
ImeTracingClientImpl() {
|
||||
sEnabled = IInputMethodManagerGlobal.isImeTraceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,8 +53,6 @@ class ImeTracingClientImpl extends ImeTracing {
|
||||
ProtoOutputStream proto = new ProtoOutputStream();
|
||||
immInstance.dumpDebug(proto, icProto);
|
||||
sendToService(proto.getBytes(), IME_TRACING_FROM_CLIENT, where);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Exception while sending ime-related client dump to server", e);
|
||||
} finally {
|
||||
mDumpInProgress = false;
|
||||
}
|
||||
@@ -81,8 +76,6 @@ class ImeTracingClientImpl extends ImeTracing {
|
||||
ProtoOutputStream proto = new ProtoOutputStream();
|
||||
dumper.dumpToProto(proto, icProto);
|
||||
sendToService(proto.getBytes(), IME_TRACING_FROM_IMS, where);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Exception while sending ime-related service dump to server", e);
|
||||
} finally {
|
||||
mDumpInProgress = false;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ package com.android.internal.inputmethod;
|
||||
import static android.os.Build.IS_USER;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager.ServiceNotFoundException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.util.proto.ProtoOutputStream;
|
||||
@@ -71,7 +69,7 @@ class ImeTracingServerImpl extends ImeTracing {
|
||||
|
||||
private final Object mEnabledLock = new Object();
|
||||
|
||||
ImeTracingServerImpl() throws ServiceNotFoundException {
|
||||
ImeTracingServerImpl() {
|
||||
mBufferClients = new TraceBuffer<>(BUFFER_CAPACITY);
|
||||
mTraceFileClients = new File(TRACE_DIRNAME + TRACE_FILENAME_CLIENTS);
|
||||
mBufferIms = new TraceBuffer<>(BUFFER_CAPACITY);
|
||||
@@ -132,8 +130,6 @@ class ImeTracingServerImpl extends ImeTracing {
|
||||
|
||||
try {
|
||||
sendToService(null, IME_TRACING_FROM_IMMS, where);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Exception while sending ime-related manager service dump to server", e);
|
||||
} finally {
|
||||
mDumpInProgress = false;
|
||||
}
|
||||
|
||||
@@ -123,6 +123,7 @@ interface IInputMethodManager {
|
||||
@JavaPassthrough(annotation="@android.annotation.RequiresNoPermission")
|
||||
void startProtoDump(in byte[] protoDump, int source, String where);
|
||||
|
||||
@JavaPassthrough(annotation="@android.annotation.RequiresNoPermission")
|
||||
boolean isImeTraceEnabled();
|
||||
|
||||
// Starts an ime trace.
|
||||
|
||||
Reference in New Issue
Block a user