赞
踩
IMMS运行在system server进程中,属于系统服务的一部分,用于控制输入法的显示/隐藏、切换、绑定等操作。 涉及代码文件路径:
IMMS运行在system server进程中,属于系统服务的一部分,用于控制输入法的显示/隐藏、切换、绑定等操作。 涉及代码文件路径: frameworks/base/services/java/com/android/server/SystemServer.java frameworks/base/services/core/java/com/android/server/SystemServiceManager.java frameworks/base/core/java/android/os/SystemService.java frameworks/base/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java frameworks/base/packages/SettingsProvider/res/values/defaults.xml
- # 我们从systemserver的startOtherServices函数开始梳理
- # 此处需要注意,因为我梳理的是IMMS,而Google还提供了一个MultiClientInputMethodManagerService多客户端输入法服务进程,此处不梳理
- # PS:从InputMethodManagerService代码文件中可以看到,Lifecycle是里面的一个内部类,继承systemservice
- SystemServer.java -- startOtherServices,然后通过SystemServiceManager的startService启动IMMS,传入class name:"InputMethodManagerService.Lifecycle.class"
-
- ---> SystemServiceManager.java -- startService有好几个重载的方法,说明下:
- (1)第一个startService方法,入参className即"InputMethodManagerService.Lifecycle.class",将其作为入参调用loadClassFromLoader
- (2)loadClassFromLoader会通过反射方法得到具体的Class类,返回Class<SystemService>类型的服务类,即继承SystemService的Lifecycle
- (3)调用第二个startService方法,入参即serviceClass
- (4)先通过"SystemService.class.isAssignableFrom(serviceClass)"判断该类是否是SysteService的子类
- (5)然后通过反射构造类的实例"service=constructor.newInstance(mContext)",即实例化Lifecycle类(重点)
- (6)调用第三个startService方法,入参该Lifecycle对象
- (2)先将该service添加到mServices列表中,然后调用SystemService.java的onStart函数
-
- ---> InputMethodManagerService.java -- 通过上面的流程看到,此处会先调用Lifecycle类的构造函数,然后调用onStart函数
- (1)构造函数会创建IMMS实例,即"InputMethodManagerService mService=new InputMethodManagerService(context)"
- (2)onStart函数会将该mService通过publishBinderService方法发布到系统服务中,以便其他进行可以进行Binder获取到(即添加到dev/binder域管理)
- # 主要讲述IMMS对象被创建,从构造函数梳理
- ---》 调用构造函数,主要用于注册一些监听事件, 获取必须的系统服务, UI相关的组件等
PS:
- # 我们从systemserver的startOtherServices函数开始梳理
- # startBootPhase在服务startservice后执行,该函数将service分段处理,
- # 例如此处IMMS在SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE(200)和SystemService.PHASE_LOCK_SETTINGS_READY(480)之间
- SystemServer.java -- startOtherServices,然后通过SystemServiceManager的startBootPhase
-
- ---> SystemServiceManager.java -- startBootPhase遍历两个分段之间的服务,然后调用对应service的onBootPhase
-
- ---> InputMethodManagerService.java -- 调用Lifecycle类的onBootPhase函数,然后调用InputMethodManagerService的systemRunning函数,主要内容:
- (1)MyPackageMonitor内部类register注册,监听安装包的变化,包含安装,卸载,更新等
- (2)SettingsObserver注册,监听当前用户的各种输入法相关的settingprovider变化,例如:默认输入法,输入法列表,输入法语言等
- (3)getSelectedInputMethod获取用户设置的输入法default_input_method,此处是查询settings数据库的默认输入法(frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java)
- (4)buildInputMethodListLocked,如果没有默认输入法则入参false,该函数内容如下:
- ---》 查询输入法服务信息,然后将信息储存到mMethodList,mMethodMap,mMyPackageMonitor中;
- ---》 调用chooseNewDefaultIMELocked选择一个新的输入法;
- ---》 updateInputMethodsFromSettingsLocked遍历所有输入法,如果输入法存在被禁用的组件,则重新启用调用setInputMethodLocked方法完成对输入法设置,和输入法发生变化的广播(ACTION_INPUT_METHOD_CHANGED)的发送(该函数中调用setInputMethodLocked)
一般我们修改默认输入法,packages/SettingsProvider/res/values/defaults.xml 数据库配置添加def_input_method和def_enable_input_methods,然后frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java对应添加loadStringSetting加载引用DEFAULT_INPUT_METHOD和ENABLED_INPUT_METHODS
- //SystemServer.java
- private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
- ......
- // Bring up services needed for UI.
- if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
- t.traceBegin("StartInputMethodManagerLifecycle");
- if (InputMethodSystemProperty.MULTI_CLIENT_IME_ENABLED) {
- mSystemServiceManager.startService(
- MultiClientInputMethodManagerService.Lifecycle.class);
- } else {
- //启动IMMS服务
- mSystemServiceManager.startService(InputMethodManagerService.Lifecycle.class);
- }
- t.traceEnd();
- ......
- }
- ...
- }
-
- //SystemServiceManager.java
- //第一个startService函数
- public SystemService startService(String className) {
- //调用loadClassFromLoader
- final Class<SystemService> serviceClass = loadClassFromLoader(className,
- this.getClass().getClassLoader());
- return startService(serviceClass);
- }
-
- private static Class<SystemService> loadClassFromLoader(String className,
- ClassLoader classLoader) {
- try {
- //通过反射方法得到具体的Class类,返回Class<SystemService>类型的服务类,即继承SystemService的Lifecycle
- return (Class<SystemService>) Class.forName(className, true, classLoader);
- } catch (ClassNotFoundException ex) {
- .......
- }
- }
-
- //第二个startService函数
- public <T extends SystemService> T startService(Class<T> serviceClass) {
- try {
- final String name = serviceClass.getName();
- Slog.i(TAG, "Starting " + name);
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
-
- // 判断该class该类是否是SysteService的子类
- if (!SystemService.class.isAssignableFrom(serviceClass)) {
- throw new RuntimeException("Failed to create " + name
- + ": service must extend " + SystemService.class.getName());
- }
- final T service;
- try {
- //通过反射构造类的实例,即实例化Lifecycle类
- Constructor<T> constructor = serviceClass.getConstructor(Context.class);
- //newInstance实例化
- service = constructor.newInstance(mContext);
- } catch (InstantiationException ex) {
- throw new RuntimeException("Failed to create service " + name
- + ": service could not be instantiated", ex);
- } ......
- ......
- //调用第三个startService
- startService(service);
- return service;
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- }
- }
-
- //第三个startService函数
- public void startService(@NonNull final SystemService service) {
- // Register it.将service注册到mServices列表中
- mServices.add(service);
- // Start it.
- long time = SystemClock.elapsedRealtime();
- try {
- //调用该service的onStart函数
- service.onStart();
- } catch (RuntimeException ex) {
- throw new RuntimeException("Failed to start service " + service.getClass().getName()
- + ": onStart threw an exception", ex);
- }
- warnIfTooLong(SystemClock.elapsedRealtime() - time, service, "onStart");
- }
-
- //InputMethodManagerService.java
- public static final class Lifecycle extends SystemService {
- private InputMethodManagerService mService;
- //实例化时调用构造函数
- public Lifecycle(Context context) {
- super(context);
- //创建InputMethodManagerService IMMS对象,然后调用IMMS构造函数
- mService = new InputMethodManagerService(context);
- }
-
- //在startService中调用到此处
- @Override
- public void onStart() {
- //将IMMS service添加到LocalServices
- LocalServices.addService(InputMethodManagerInternal.class,
- new LocalServiceImpl(mService));
- //发布到系统服务中,以便其他进行可以进行Binder获取到(即添加到dev/binder域管理)
- publishBinderService(Context.INPUT_METHOD_SERVICE, mService, false /*allowIsolated*/,
- DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
- }
- .......
- }
-
- public class InputMethodManagerService extends IInputMethodManager.Stub
- implements ServiceConnection, Handler.Callback {
- ....
- //IMMS构造函数
- public InputMethodManagerService(Context context) {
- mIPackageManager = AppGlobals.getPackageManager();
- mContext = context;
- mRes = context.getResources();
- mHandler = new Handler(this);
- // Note: SettingsObserver doesn't register observers in its constructor.
- // SettingsObserver类型,用于监听来自设置的输入法配置, 比如默认输入法, 启用的输入法, 选择的输入法等
- mSettingsObserver = new SettingsObserver(mHandler);
- mIWindowManager = IWindowManager.Stub.asInterface(
- ServiceManager.getService(Context.WINDOW_SERVICE));
- mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
- mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
- mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
- mImeDisplayValidator = displayId -> mWindowManagerInternal.getDisplayImePolicy(displayId);
- .....
- // 状态栏输入法图标名称, 会根据这个名称设置输入法的图标显示
- mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);
- mIsLowRam = ActivityManager.isLowRamDeviceStatic();
- // 切换输入法时的通知
- Bundle extras = new Bundle();
- extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
- .....
- //获取UID
- int userId = 0;
- try {
- userId = ActivityManager.getService().getCurrentUser().id;
- } catch (RemoteException e) {
- Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
- }
- // 最近切换的UID
- mLastSwitchUserId = userId;
-
- //应在buildInputMethodListLocked之前创建mSettings
- //类型InputMethodSettings,输入法设置对象
- mSettings = new InputMethodSettings(
- mRes, context.getContentResolver(), mMethodMap, userId, !mSystemReady);
-
- updateCurrentProfileIds();
- AdditionalSubtypeUtils.load(mAdditionalSubtypeMap, userId);
- mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
- mSettings, context);
- mMenuController = new InputMethodMenuController(this);
- }
- ......
- }
IMMS.java中几个重要的变量:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。