Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8069174 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce IInputMethodManagerGlobal"

parents 44bdd7fd 7f0c721f
Loading
Loading
Loading
Loading
+158 −0
Original line number Diff line number Diff line
/*
 * 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();
        }
    }
}
+18 −32
Original line number Diff line number Diff line
@@ -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) {
            if (isSystemProcess()) {
                sInstance = new ImeTracingServerImpl();
            } else {
                try {
                sInstance = isSystemProcess()
                        ? new ImeTracingServerImpl() : new ImeTracingClientImpl();
            } catch (RemoteException | ServiceNotFoundException e) {
                Log.e(TAG, "Exception while creating ImeTracing instance", e);
                    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;
    }

    /**
+2 −9
Original line number Diff line number Diff line
@@ -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;
        }
+1 −5
Original line number Diff line number Diff line
@@ -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;
        }
+1 −0
Original line number Diff line number Diff line
@@ -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.