做網(wǎng)站用什么軟件知乎google瀏覽器下載
2.2. IME管理端(IMMS)初始化流程
IMMS運(yùn)行在system server進(jìn)程中,屬于系統(tǒng)服務(wù)的一部分,用于控制輸入法的顯示/隱藏、切換、綁定等操作。 涉及代碼文件路徑:
IMMS運(yùn)行在system server進(jìn)程中,屬于系統(tǒng)服務(wù)的一部分,用于控制輸入法的顯示/隱藏、切換、綁定等操作。 涉及代碼文件路徑: 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
2.2.1. 初始化函數(shù)流程梳理
# 我們從systemserver的startOtherServices函數(shù)開(kāi)始梳理
# 此處需要注意,因?yàn)槲沂崂淼氖荌MMS,而Google還提供了一個(gè)MultiClientInputMethodManagerService多客戶端輸入法服務(wù)進(jìn)程,此處不梳理
# PS:從InputMethodManagerService代碼文件中可以看到,Lifecycle是里面的一個(gè)內(nèi)部類,繼承systemservice
SystemServer.java -- startOtherServices,然后通過(guò)SystemServiceManager的startService啟動(dòng)IMMS,傳入class name:"InputMethodManagerService.Lifecycle.class"---> SystemServiceManager.java -- startService有好幾個(gè)重載的方法,說(shuō)明下:(1)第一個(gè)startService方法,入?yún)lassName即"InputMethodManagerService.Lifecycle.class",將其作為入?yún)⒄{(diào)用loadClassFromLoader(2)loadClassFromLoader會(huì)通過(guò)反射方法得到具體的Class類,返回Class<SystemService>類型的服務(wù)類,即繼承SystemService的Lifecycle(3)調(diào)用第二個(gè)startService方法,入?yún)⒓磗erviceClass(4)先通過(guò)"SystemService.class.isAssignableFrom(serviceClass)"判斷該類是否是SysteService的子類(5)然后通過(guò)反射構(gòu)造類的實(shí)例"service=constructor.newInstance(mContext)",即實(shí)例化Lifecycle類(重點(diǎn))(6)調(diào)用第三個(gè)startService方法,入?yún)⒃揕ifecycle對(duì)象(2)先將該service添加到mServices列表中,然后調(diào)用SystemService.java的onStart函數(shù)---> InputMethodManagerService.java -- 通過(guò)上面的流程看到,此處會(huì)先調(diào)用Lifecycle類的構(gòu)造函數(shù),然后調(diào)用onStart函數(shù)(1)構(gòu)造函數(shù)會(huì)創(chuàng)建IMMS實(shí)例,即"InputMethodManagerService mService=new InputMethodManagerService(context)"(2)onStart函數(shù)會(huì)將該mService通過(guò)publishBinderService方法發(fā)布到系統(tǒng)服務(wù)中,以便其他進(jìn)行可以進(jìn)行Binder獲取到(即添加到dev/binder域管理)# 主要講述IMMS對(duì)象被創(chuàng)建,從構(gòu)造函數(shù)梳理---》 調(diào)用構(gòu)造函數(shù),主要用于注冊(cè)一些監(jiān)聽(tīng)事件, 獲取必須的系統(tǒng)服務(wù), UI相關(guān)的組件等
PS:
- SystemService啟動(dòng)輸入法服務(wù)時(shí),會(huì)有個(gè)判斷啟動(dòng)IMMS還是MCIMMS。MULTI_CLIENT_IME_ENABLED(即persist.debug.multi_client_ime或ro.sys.multi_client_ime)開(kāi)啟,啟動(dòng)MultiClientInputMethodManagerService服務(wù),否則啟動(dòng)InputMethodManagerService服務(wù)
- 關(guān)于MultiClientInputMethodManagerService就是多會(huì)話輸入法,支持每屏幕焦點(diǎn)是啟用此功能的前提。如果不支持,則無(wú)法啟用此功能。由于安全限制,每屏幕焦點(diǎn)限制規(guī)定只有一小部分設(shè)備支持此功能。(詳細(xì)參考Google官方文檔和源碼)
2.2.2. systemRunning函數(shù)流程梳理
# 我們從systemserver的startOtherServices函數(shù)開(kāi)始梳理
# startBootPhase在服務(wù)startservice后執(zhí)行,該函數(shù)將service分段處理,
# 例如此處IMMS在SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE(200)和SystemService.PHASE_LOCK_SETTINGS_READY(480)之間
SystemServer.java -- startOtherServices,然后通過(guò)SystemServiceManager的startBootPhase---> SystemServiceManager.java -- startBootPhase遍歷兩個(gè)分段之間的服務(wù),然后調(diào)用對(duì)應(yīng)service的onBootPhase---> InputMethodManagerService.java -- 調(diào)用Lifecycle類的onBootPhase函數(shù),然后調(diào)用InputMethodManagerService的systemRunning函數(shù),主要內(nèi)容:(1)MyPackageMonitor內(nèi)部類register注冊(cè),監(jiān)聽(tīng)安裝包的變化,包含安裝,卸載,更新等(2)SettingsObserver注冊(cè),監(jiān)聽(tīng)當(dāng)前用戶的各種輸入法相關(guān)的settingprovider變化,例如:默認(rèn)輸入法,輸入法列表,輸入法語(yǔ)言等(3)getSelectedInputMethod獲取用戶設(shè)置的輸入法default_input_method,此處是查詢settings數(shù)據(jù)庫(kù)的默認(rèn)輸入法(frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java)(4)buildInputMethodListLocked,如果沒(méi)有默認(rèn)輸入法則入?yún)alse,該函數(shù)內(nèi)容如下:---》 查詢輸入法服務(wù)信息,然后將信息儲(chǔ)存到mMethodList,mMethodMap,mMyPackageMonitor中;---》 調(diào)用chooseNewDefaultIMELocked選擇一個(gè)新的輸入法;---》 updateInputMethodsFromSettingsLocked遍歷所有輸入法,如果輸入法存在被禁用的組件,則重新啟用調(diào)用setInputMethodLocked方法完成對(duì)輸入法設(shè)置,和輸入法發(fā)生變化的廣播(ACTION_INPUT_METHOD_CHANGED)的發(fā)送(該函數(shù)中調(diào)用setInputMethodLocked)
一般我們修改默認(rèn)輸入法,packages/SettingsProvider/res/values/defaults.xml 數(shù)據(jù)庫(kù)配置添加def_input_method和def_enable_input_methods,然后frameworks/base/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java對(duì)應(yīng)添加loadStringSetting加載引用DEFAULT_INPUT_METHOD和ENABLED_INPUT_METHODS
2.2.3. 代碼詳細(xì)說(shuō)明
//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 {//啟動(dòng)IMMS服務(wù)mSystemServiceManager.startService(InputMethodManagerService.Lifecycle.class);}t.traceEnd();......}...
}//SystemServiceManager.java//第一個(gè)startService函數(shù)public SystemService startService(String className) {//調(diào)用loadClassFromLoaderfinal Class<SystemService> serviceClass = loadClassFromLoader(className,this.getClass().getClassLoader());return startService(serviceClass);}private static Class<SystemService> loadClassFromLoader(String className,ClassLoader classLoader) {try {//通過(guò)反射方法得到具體的Class類,返回Class<SystemService>類型的服務(wù)類,即繼承SystemService的Lifecyclereturn (Class<SystemService>) Class.forName(className, true, classLoader);} catch (ClassNotFoundException ex) {.......}}//第二個(gè)startService函數(shù)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 {//通過(guò)反射構(gòu)造類的實(shí)例,即實(shí)例化Lifecycle類Constructor<T> constructor = serviceClass.getConstructor(Context.class);//newInstance實(shí)例化service = constructor.newInstance(mContext);} catch (InstantiationException ex) {throw new RuntimeException("Failed to create service " + name+ ": service could not be instantiated", ex);} ............//調(diào)用第三個(gè)startServicestartService(service);return service;} finally {Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);}}//第三個(gè)startService函數(shù)public void startService(@NonNull final SystemService service) {// Register it.將service注冊(cè)到mServices列表中mServices.add(service);// Start it.long time = SystemClock.elapsedRealtime();try {//調(diào)用該service的onStart函數(shù)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.javapublic static final class Lifecycle extends SystemService {private InputMethodManagerService mService;//實(shí)例化時(shí)調(diào)用構(gòu)造函數(shù)public Lifecycle(Context context) {super(context);//創(chuàng)建InputMethodManagerService IMMS對(duì)象,然后調(diào)用IMMS構(gòu)造函數(shù)mService = new InputMethodManagerService(context);}//在startService中調(diào)用到此處@Overridepublic void onStart() {//將IMMS service添加到LocalServicesLocalServices.addService(InputMethodManagerInternal.class,new LocalServiceImpl(mService));//發(fā)布到系統(tǒng)服務(wù)中,以便其他進(jìn)行可以進(jìn)行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.Stubimplements ServiceConnection, Handler.Callback {....//IMMS構(gòu)造函數(shù)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類型,用于監(jiān)聽(tīng)來(lái)自設(shè)置的輸入法配置, 比如默認(rèn)輸入法, 啟用的輸入法, 選擇的輸入法等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);.....// 狀態(tài)欄輸入法圖標(biāo)名稱, 會(huì)根據(jù)這個(gè)名稱設(shè)置輸入法的圖標(biāo)顯示mSlotIme = mContext.getString(com.android.internal.R.string.status_bar_ime);mIsLowRam = ActivityManager.isLowRamDeviceStatic();// 切換輸入法時(shí)的通知Bundle extras = new Bundle();extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);.....//獲取UIDint 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);}// 最近切換的UIDmLastSwitchUserId = userId;//應(yīng)在buildInputMethodListLocked之前創(chuàng)建mSettings//類型InputMethodSettings,輸入法設(shè)置對(duì)象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中幾個(gè)重要的變量:
- String mCurMethodId:系統(tǒng)當(dāng)前默認(rèn)的輸入法id, 可能為空, 與Settings.Secure#DEFAULT_INPUT_METHOD值保持一致,在setInputMethodLocked中賦值
- String mCurId:當(dāng)前已經(jīng)綁定的輸入法id, 如果沒(méi)有輸入法綁定上的話, 值為null
- ClientState mCurClient:用于當(dāng)前激活的IME, 只有持有這個(gè)令牌的IME才被系統(tǒng)認(rèn)可
- IInputMethod mCurMethod:當(dāng)前已經(jīng)綁定的輸入法接口, 如果為null, 說(shuō)明沒(méi)有任何輸入法連接上