diff options
| author | 2022-10-14 07:41:42 -0700 | |
|---|---|---|
| committer | 2022-10-14 07:41:42 -0700 | |
| commit | 7f0c721fc714d12bb9f302ae039c35aac37dfa99 (patch) | |
| tree | 78d8e950f1fd5ede681e1fb37bda8d7d1a3dafc9 | |
| parent | e16dbabf16f1d54a8c46e63cdf7416b4cb7ce963 (diff) | |
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
5 files changed, 180 insertions, 46 deletions
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodManagerGlobal.java b/core/java/com/android/internal/inputmethod/IInputMethodManagerGlobal.java new file mode 100644 index 000000000000..f0fe573d20e0 --- /dev/null +++ b/core/java/com/android/internal/inputmethod/IInputMethodManagerGlobal.java @@ -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(); + } + } +} diff --git a/core/java/com/android/internal/inputmethod/ImeTracing.java b/core/java/com/android/internal/inputmethod/ImeTracing.java index ee6713118f75..a4328cc14aa0 100644 --- a/core/java/com/android/internal/inputmethod/ImeTracing.java +++ b/core/java/com/android/internal/inputmethod/ImeTracing.java @@ -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; } /** diff --git a/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java index 31d278b5ca54..4caca84d76c7 100644 --- a/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java +++ b/core/java/com/android/internal/inputmethod/ImeTracingClientImpl.java @@ -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; } diff --git a/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java index f885a7e775ed..2a242a5369b0 100644 --- a/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java +++ b/core/java/com/android/internal/inputmethod/ImeTracingServerImpl.java @@ -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; } diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl index 955895ffdae2..423642acf2f7 100644 --- a/core/java/com/android/internal/view/IInputMethodManager.aidl +++ b/core/java/com/android/internal/view/IInputMethodManager.aidl @@ -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. |