From d5f402bd0b7fcaa7904a209192d830480bee6217 Mon Sep 17 00:00:00 2001 From: Yohei Yukawa Date: Fri, 15 May 2020 10:23:32 -0700 Subject: [PATCH] Have IMMS report IME UID to AudioService This is a follow up CL to our previous CL [1], which enabled AudioService to be notified about the UID of the currently used IME. Although there is no change in the overall approach, with the help from InputMethodManagerService AuditoService can be notified new IME UIDs more quickly especially when IMEs are switching to other ones (e.g. due to user switching or profile switching). [1]: I11e17b13513627c88ccb8e4db66c5359e9ee7f7b ed4e8c3fab1443220de713cbbb92d526f68c7700 Bug: 147037345 Test: use voice input with Gboard 9.5.0 during a simulated RTT call. Change-Id: I44e3331a7bad6d36227f7e2d0523dd14d933b6a1 --- .../android/media/AudioManagerInternal.java | 13 +++++ .../android/server/audio/AudioService.java | 57 +++++++------------ .../InputMethodManagerService.java | 50 ++++++++++++++++ 3 files changed, 83 insertions(+), 37 deletions(-) diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java index 98c2d7fdd55f5..357c3332fe105 100644 --- a/media/java/android/media/AudioManagerInternal.java +++ b/media/java/android/media/AudioManagerInternal.java @@ -16,6 +16,7 @@ package android.media; import android.util.IntArray; + import com.android.server.LocalServices; /** @@ -48,6 +49,18 @@ public abstract class AudioManagerInternal { public abstract void setAccessibilityServiceUids(IntArray uids); + /** + * Called by {@link com.android.server.inputmethod.InputMethodManagerService} to notify the UID + * of the currently used {@link android.inputmethodservice.InputMethodService}. + * + *

The caller is expected to take care of any performance implications, e.g. by using a + * background thread to call this method.

+ * + * @param uid UID of the currently used {@link android.inputmethodservice.InputMethodService}. + * {@link android.os.Process#INVALID_UID} if no IME is active. + */ + public abstract void setInputMethodServiceUid(int uid); + public interface RingerModeDelegate { /** Called when external ringer mode is evaluated, returns the new internal ringer mode */ int onSetRingerModeExternal(int ringerModeOld, int ringerModeNew, String caller, diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 8068e378f2e36..e5a7daf9d1d3d 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -52,7 +52,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; @@ -570,6 +569,10 @@ public class AudioService extends IAudioService.Stub private int[] mAccessibilityServiceUids; private final Object mAccessibilityServiceUidsLock = new Object(); + // Uid of the active input method service to check if caller is the one or not. + private int mInputMethodServiceUid = android.os.Process.INVALID_UID; + private final Object mInputMethodServiceUidLock = new Object(); + private int mEncodedSurroundMode; private String mEnabledSurroundFormats; private boolean mSurroundModeChanged; @@ -1078,12 +1081,14 @@ public class AudioService extends IAudioService.Stub sendEncodedSurroundMode(mContentResolver, "onAudioServerDied"); sendEnabledSurroundFormats(mContentResolver, true); updateAssistantUId(true); - updateCurrentImeUid(true); AudioSystem.setRttEnabled(mRttEnabled); } synchronized (mAccessibilityServiceUidsLock) { AudioSystem.setA11yServicesUids(mAccessibilityServiceUids); } + synchronized (mInputMethodServiceUidLock) { + mAudioSystem.setCurrentImeUid(mInputMethodServiceUid); + } synchronized (mHdmiClientLock) { if (mHdmiManager != null && mHdmiTvClient != null) { setHdmiSystemAudioSupported(mHdmiSystemAudioSupported); @@ -1629,37 +1634,6 @@ public class AudioService extends IAudioService.Stub } } - @GuardedBy("mSettingsLock") - private void updateCurrentImeUid(boolean forceUpdate) { - String imeId = Settings.Secure.getStringForUser( - mContentResolver, - Settings.Secure.DEFAULT_INPUT_METHOD, UserHandle.USER_CURRENT); - if (TextUtils.isEmpty(imeId)) { - Log.e(TAG, "updateCurrentImeUid() could not find current IME"); - return; - } - ComponentName componentName = ComponentName.unflattenFromString(imeId); - if (componentName == null) { - Log.e(TAG, "updateCurrentImeUid() got invalid service name for " - + Settings.Secure.DEFAULT_INPUT_METHOD + ": " + imeId); - return; - } - String packageName = componentName.getPackageName(); - int currentUserId = LocalServices.getService(ActivityManagerInternal.class) - .getCurrentUserId(); - int currentImeUid = LocalServices.getService(PackageManagerInternal.class) - .getPackageUidInternal(packageName, 0 /* flags */, currentUserId); - if (currentImeUid < 0) { - Log.e(TAG, "updateCurrentImeUid() could not find UID for package: " + packageName); - return; - } - - if (currentImeUid != mCurrentImeUid || forceUpdate) { - mAudioSystem.setCurrentImeUid(currentImeUid); - mCurrentImeUid = currentImeUid; - } - } - private void readPersistedSettings() { if (!mSystemServer.isPrivileged()) { return; @@ -1707,7 +1681,6 @@ public class AudioService extends IAudioService.Stub sendEncodedSurroundMode(cr, "readPersistedSettings"); sendEnabledSurroundFormats(cr, true); updateAssistantUId(true); - updateCurrentImeUid(true); AudioSystem.setRttEnabled(mRttEnabled); } @@ -6217,8 +6190,6 @@ public class AudioService extends IAudioService.Stub mContentResolver.registerContentObserver(Settings.Secure.getUriFor( Settings.Secure.VOICE_INTERACTION_SERVICE), false, this); - mContentResolver.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.DEFAULT_INPUT_METHOD), false, this); } @Override @@ -6242,7 +6213,6 @@ public class AudioService extends IAudioService.Stub updateEncodedSurroundOutput(); sendEnabledSurroundFormats(mContentResolver, mSurroundModeChanged); updateAssistantUId(false); - updateCurrentImeUid(false); } } @@ -7584,6 +7554,19 @@ public class AudioService extends IAudioService.Stub AudioSystem.setA11yServicesUids(mAccessibilityServiceUids); } } + + /** + * {@inheritDoc} + */ + @Override + public void setInputMethodServiceUid(int uid) { + synchronized (mInputMethodServiceUidLock) { + if (mInputMethodServiceUid != uid) { + mAudioSystem.setCurrentImeUid(uid); + mInputMethodServiceUid = uid; + } + } + } } //========================================================================================== diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 93ef1264755b1..52116a07e8e6a 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -56,6 +56,7 @@ import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Configuration; @@ -67,6 +68,7 @@ import android.graphics.drawable.Drawable; import android.hardware.display.DisplayManagerInternal; import android.hardware.input.InputManagerInternal; import android.inputmethodservice.InputMethodService; +import android.media.AudioManagerInternal; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -223,6 +225,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000; + static final int MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE = 7000; + static final long TIME_TO_RECONNECT = 3 * 1000; static final int SECURE_SUGGESTION_SPANS_MAX_SIZE = 20; @@ -308,6 +312,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final SettingsObserver mSettingsObserver; final IWindowManager mIWindowManager; final WindowManagerInternal mWindowManagerInternal; + final PackageManagerInternal mPackageManagerInternal; final InputManagerInternal mInputManagerInternal; private final DisplayManagerInternal mDisplayManagerInternal; final HandlerCaller mCaller; @@ -320,6 +325,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final UserManager mUserManager; private final UserManagerInternal mUserManagerInternal; + /** + * Cache the result of {@code LocalServices.getService(AudioManagerInternal.class)}. + * + *

This field is used only within {@link #handleMessage(Message)} hence synchronization is + * not necessary.

+ */ + @Nullable + private AudioManagerInternal mAudioManagerInternal = null; + + // All known input methods. mMethodMap also serves as the global // lock for this class. final ArrayList mMethodList = new ArrayList<>(); @@ -642,6 +657,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub */ IInputMethod mCurMethod; + /** + * If not {@link Process#INVALID_UID}, then the UID of {@link #mCurIntent}. + */ + int mCurMethodUid = Process.INVALID_UID; + /** * Time that we last initiated a bind to the input method, to determine * if we should try to disconnect and reconnect to it. @@ -1625,6 +1645,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mIWindowManager = IWindowManager.Stub.asInterface( ServiceManager.getService(Context.WINDOW_SERVICE)); mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class); + mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mInputManagerInternal = LocalServices.getService(InputManagerInternal.class); mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class); mImeDisplayValidator = displayId -> mWindowManagerInternal.shouldShowIme(displayId); @@ -2521,11 +2542,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return checker.displayCanShowIme(displayId) ? displayId : FALLBACK_DISPLAY_ID; } + @AnyThread + private void scheduleNotifyImeUidToAudioService(int uid) { + mCaller.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE); + mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget(); + } + @Override public void onServiceConnected(ComponentName name, IBinder service) { synchronized (mMethodMap) { if (mCurIntent != null && name.equals(mCurIntent.getComponent())) { mCurMethod = IInputMethod.Stub.asInterface(service); + final String curMethodPackage = mCurIntent.getComponent().getPackageName(); + final int curMethodUid = mPackageManagerInternal.getPackageUidInternal( + curMethodPackage, 0 /* flags */, mSettings.getCurrentUserId()); + if (curMethodUid < 0) { + Slog.e(TAG, "Failed to get UID for package=" + curMethodPackage); + mCurMethodUid = Process.INVALID_UID; + } else { + mCurMethodUid = curMethodUid; + } if (mCurToken == null) { Slog.w(TAG, "Service connected without a token!"); unbindCurrentMethodLocked(); @@ -2535,6 +2571,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Dispatch display id for InputMethodService to update context display. executeOrSendMessage(mCurMethod, mCaller.obtainMessageIOO( MSG_INITIALIZE_IME, mCurTokenDisplayId, mCurMethod, mCurToken)); + scheduleNotifyImeUidToAudioService(mCurMethodUid); if (mCurClient != null) { clearClientSessionLocked(mCurClient); requestClientSessionLocked(mCurClient); @@ -2656,6 +2693,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub finishSessionLocked(mEnabledSession); mEnabledSession = null; mCurMethod = null; + mCurMethodUid = Process.INVALID_UID; + scheduleNotifyImeUidToAudioService(mCurMethodUid); } if (mStatusBar != null) { mStatusBar.setIconVisibility(mSlotIme, false); @@ -4277,6 +4316,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub args.recycle(); return true; } + + // --------------------------------------------------------------- + case MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE: { + if (mAudioManagerInternal == null) { + mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class); + } + if (mAudioManagerInternal != null) { + mAudioManagerInternal.setInputMethodServiceUid(msg.arg1 /* uid */); + } + return true; + } } return false; }