安卓IMS 原理解析(一、IMS介绍及启动流程)

发布于:2022-10-18 ⋅ 阅读:(492) ⋅ 点赞:(0)

目录

一、安卓输入系统简介

1.1 核心成员

二、IMS启动流程

2.1 初始化流程

2.2 启动流程

2.2.1 inputdispatch启动

2.2.2 inputReader启动


一、安卓输入系统简介

         输入事件的源头是位于dev/input/下的设备节点,即:当我们触摸屏幕或按键后会在该节点下生成数据,而输入系统的终点是由WMS管理的某个窗口。
       最初的输入事件为内核生成的原始事件,而最终交付给窗口的则是KeyEvent或MotionEvent对象。
       Android输入系统的主要工作是读取设备节点中的原始事件,将其加工封装,然后派发给一个指定的窗口以及窗口中的控件。这个过程由InputManagerService系统服务为核心的多个参与者共同完成。

1.1 核心成员

1.Linux内核

       接受输入设备的中断,并将原始事件的输入写入设备节点中;

2.设备节点

       作为内核和IMS的桥梁,将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件;

3.InputManagerService

       Android系统服务,它分为java层和native层两部分;java层负责与WMS通信,native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器;

4.EventHub

       直接访问所有的设备节点。它通过一个名为getEvent()的函数将所有输入系统相关的待处理的底层事件返回给使用者。这些事件包括原始输入事件、设备节点的增删等;

5.InputReader

       IMS中的关键组件之一,它运行于一个独立的线程中,负责管理输入设备的列表与配置,以及进行输入事件的加工处理。它通过其线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理。对于设备节点的增删事件,它会更新输入设备列表与配置。对于原始输入事件,InputReader对其进行翻译、组装、封装为包含更多信息、更具可读性的输入事件,然后交给InputDispatcher进行派发;

6.InputReaderPolicy

       它为InputReader的事件加工处理提供一些策略配置,例如键盘布局信息等;

7.InputDispatcher

       IMS中的另一个关键组件,它也运行于一个独立的线程中。InputDispatcher中保管了来自WMS的所有窗口的信息,其收到来自InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口

8.InputDispatcherPolicy

       它为InputDispatcher的派发过程提供策略控制。例如截取某些特定的输入事件用作特殊用途,或者阻止将某些事件派发给目标窗口。一个典型的例子就是HOME键被InputDispatcherPolicy截取到PhoneWindowManager中进行处理,并阻止窗口收到HOME键按下的事件;

9.WMS

       不是输入系统的一员,但它对InputDispatcher的正常工作起到重要作用。当新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。另外,WMS还将所有窗口的信息,包括窗口的可点击区域,焦点窗口等信息,实时的更新到IMS的InputDispatcher中,使得InputDispatcher可以正确地将事件派发到指定的窗口;

10.ViewRootImpl

       对某些窗口,如壁纸窗口、SurfaceView的窗口来说,窗口就是输入事件派发的终点。而对其他的activity、对话框等使用了Android控件系统的窗口来说,输入事件的终点是控件View。ViewRootImpl将窗口所接收的输入事件沿着控件树将事件派发给感兴趣的控件;

总结:

       内核将原始事件写入设备节点中,InputReader不断地通过EventHub将原始事件取出来并翻译加工成Android输入事件,然后交给InputDispatcher。InputDispatcher根据WMS提供的窗口信息将事件交给合适的窗口。窗口的ViewRootImpl对象再沿着控件树将事件派发给感兴趣的控件。控件对其收到的事件做出响应,更新自己的画面、执行特定的动作。所有这些参与者以IMS为核心,构建Android输入体系。

二、IMS启动流程

2.1 初始化流程

   IMS分为java和native两部分,其启动过程是从java部分的初始化开始,进而完成native部分的初始化;
       同其他核心服务一样,IMS运行在system_server进程里面,在startOtherServices()里面启动:

private void startOtherServices() {
     .......
     .......
     traceBeginAndSlog("StartInputManagerService");
     inputManager = new InputManagerService(context);
     traceEnd();

     traceBeginAndSlog("StartInputManager");
     inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
     inputManager.start();
     traceEnd();
     .......
     ......
}

通过启动逻辑可以看到,在创建完IMS实例后,先执行了setWindowManagerCallbacks然后执行了start(),接下来进入InputManagerService源码中一起看一下内部实现逻辑:

325      public InputManagerService(Context context) {
326          this.mContext = context;
327          this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
328  
329          mStaticAssociations = loadStaticInputPortAssociations();
330          mUseDevInputEventForAudioJack =
331                  context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
332          Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
333                  + mUseDevInputEventForAudioJack);
334          mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
335  
336          String doubleTouchGestureEnablePath = context.getResources().getString(
337                  R.string.config_doubleTouchGestureEnableFile);
338          mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
339              new File(doubleTouchGestureEnablePath);
340  
341          LocalServices.addService(InputManagerInternal.class, new LocalService());
342      }

          ......


352      public void start() {
353          Slog.i(TAG, "Starting input manager");
354          nativeStart(mPtr);
355  
            .......
378      }

在构造方法内,执行了nativeInit(),在start()中执行了nativeStart(),以上两个方法都是native方法,具体的逻辑是在native层实现的,对应的类路径为:

base/services/core/jni/com_android_server_input_InputManagerService.cpp

1261  static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
1262          jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
1263      sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
1264      if (messageQueue == nullptr) {
1265          jniThrowRuntimeException(env, "MessageQueue is not initialized.");
1266          return 0;
1267      }
1268  
1269      NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
1270              messageQueue->getLooper());
1271      im->incStrong(0);
1272      return reinterpret_cast<jlong>(im);
1273  }

            .......

87  class NativeInputManager : public virtual RefBase,
188      public virtual InputReaderPolicyInterface,
189      public virtual InputDispatcherPolicyInterface,
190      public virtual PointerControllerPolicyInterface {
        
           ......
}

327  NativeInputManager::NativeInputManager(jobject contextObj,
328          jobject serviceObj, const sp<Looper>& looper) :
329          mLooper(looper), mInteractive(true) {
330      JNIEnv* env = jniEnv();
331  
332      mServiceObj = env->NewGlobalRef(serviceObj);
333  
334      {
335          AutoMutex _l(mLock);
336          mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
337          mLocked.pointerSpeed = 0;
338          mLocked.pointerGesturesEnabled = true;
339          mLocked.showTouches = false;
340          mLocked.pointerCapture = false;
341          mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
342      }
343      mInteractive = true;
344  
345      mInputManager = new InputManager(this, this);
346      defaultServiceManager()->addService(String16("inputflinger"),
347              mInputManager, false);
348  }

NativeInputManager继承了InputReaderPolicyInterface、InputDispatcherPolicyInterface等,后续会讲到,然后回到构造方法,在构造方法内部,创建了InputManager,再看一下InputManager,位于frameworks/native/services/inputflinger/InputManager.cpp

34  InputManager::InputManager(
35          const sp<InputReaderPolicyInterface>& readerPolicy,
36          const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
37      mDispatcher = createInputDispatcher(dispatcherPolicy);
38      mClassifier = new InputClassifier(mDispatcher);
39      mReader = createInputReader(readerPolicy, mClassifier);
40  }

1.初始化InputDispatcher:

frameworks/native/services/inputflinger/dispatcher/InputDispatcherFactory.cpp

std::unique_ptr<InputDispatcherInterface> createInputDispatcher(
        const sp<InputDispatcherPolicyInterface>& policy) {
    return std::make_unique<android::inputdispatcher::InputDispatcher>(policy);
}

使用std:make_unique调用InputDispatcher的构造函数,其构造函数如下:

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

389  // --- InputDispatcher ---
390  
391  InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
392        : mPolicy(policy),
393          mPendingEvent(nullptr),
394          mLastDropReason(DropReason::NOT_DROPPED),
395          mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
396          mAppSwitchSawKeyDown(false),
397          mAppSwitchDueTime(LONG_LONG_MAX),
398          mNextUnblockedEvent(nullptr),
399          mDispatchEnabled(false),
400          mDispatchFrozen(false),
401          mInputFilterEnabled(false),
402          // mInTouchMode will be initialized by the WindowManager to the default device config.
403          // To avoid leaking stack in case that call never comes, and for tests,
404          // initialize it here anyways.
405          mInTouchMode(true),
406          mFocusedDisplayId(ADISPLAY_ID_DEFAULT) {
407      mLooper = new Looper(false);
408      mReporter = createInputReporter();
409  
410      mKeyRepeatState.lastKeyEntry = nullptr;
411  
412      policy->getDispatcherConfiguration(&mConfig);
413  }
  • (407行)mLooper = new Looper(false) 用于唤起InputDispatcher中的InputThread

2.初始化InputReader:

frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp

std::unique_ptr<InputReaderInterface> createInputReader(
        const sp<InputReaderPolicyInterface>& policy, InputListenerInterface& listener) {
    return std::make_unique<InputReader>(std::make_unique<EventHub>(), policy, listener);
}

frameworks/native/services/inputflinger/reader/InputReader.cpp

41  // --- InputReader ---
42  
43  InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
44                           const sp<InputReaderPolicyInterface>& policy,
45                           const sp<InputListenerInterface>& listener)
46        : mContext(this),
47          mEventHub(eventHub),
48          mPolicy(policy),
49          mGlobalMetaState(0),
50          mGeneration(1),
51          mNextInputDeviceId(END_RESERVED_ID),
52          mDisableVirtualKeysTimeout(LLONG_MIN),
53          mNextTimeout(LLONG_MAX),
54          mConfigurationChangesToRefresh(0) {
55      mQueuedListener = new QueuedInputListener(listener);
56  
57      { // acquire lock
58          AutoMutex _l(mLock);
59  
60          refreshConfigurationLocked(0);
61          updateGlobalMetaStateLocked();
62      } // release lock
63  }
64  

 mEventHub(eventHub)用于读取/dev/input事件,其中mEventHub->wake()用于唤起InputDispatcher中的InputThread
mQueuedListener = new QueuedInputListener(listener)连接InputDispatcher\InputReader,就是mClassifier

总结一下:在执行nativeInit()后,会创建NativeInputManager对象,然后在NativeInputManager内部创建InputManager对象,接着在InputManager内部创建了InputReader和InputDispatcher对象,用一张图概况一下:

2.2 启动流程

        接着上面分析,在执行nativeInit()后,会执行nativeStart():IMS的启动还是从SystemServer的startOtherServices方法中启动的。

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
	...
	t.traceBegin("StartInputManager");
	inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
	inputManager.start();
	t.traceEnd();
	...
}

这里调用InputManagerService的start方法。

/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java

public void start() {
    Slog.i(TAG, "Starting input manager");
    mNative.start(); //1

    // Add ourselves to the Watchdog monitors.
    Watchdog.getInstance().addMonitor(this); //2

    registerPointerSpeedSettingObserver();
    registerShowTouchesSettingObserver();
    registerAccessibilityLargePointerSettingObserver();
    registerLongPressTimeoutObserver();
    registerMaximumObscuringOpacityForTouchSettingObserver();
    registerBlockUntrustedTouchesModeSettingObserver();

    mContext.registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            updatePointerSpeedFromSettings();
            updateShowTouchesFromSettings();
            updateAccessibilityLargePointerFromSettings();
            updateDeepPressStatusFromSettings("user switched");
        }
    }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);

    updatePointerSpeedFromSettings();
    updateShowTouchesFromSettings();
    updateAccessibilityLargePointerFromSettings();
    updateDeepPressStatusFromSettings("just booted");
    updateMaximumObscuringOpacityForTouchFromSettings();
    updateBlockUntrustedTouchesModeFromSettings();
}

注释1处调用native的start方法,注释2处将自身添加到watchdog中进行监测。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static void nativeStart(JNIEnv* env, jobject nativeImplObj) {
    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}

这里获取native中的InputManager对象,并调用其中的start方法。
frameworks/native/services/inputflinger/InputManager.cpp

status_t InputManager::start() {
    status_t result = mDispatcher->start(); //1
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReader->start(); //2
    if (result) {
        ALOGE("Could not start InputReader due to error %d.", result);

        mDispatcher->stop();
        return result;
    }

    return OK;
}

注释1处调用了InputDispatcher的start函数,注释2处调用了InputReader的start函数

2.2.1 inputdispatch启动

由上面的InputManager的start方法中调用了InputDispatcher的start函数。
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

status_t InputDispatcher::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
    return OK;
}

创建了单独的线程运行,InputThread构造函数接收三个参数,第一个参数是线程名,第二个参数是执行threadLoop时的回调函数,第三个参数是线程销毁前唤醒线程的回调。

dispatchOnce()函数

/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        if (!haveCommandsLocked()) { //1
            dispatchOnceInnerLocked(&nextWakeupTime); //2
        }

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptable()) {
            nextWakeupTime = LONG_LONG_MIN;
        }

        // If we are still waiting for ack on some events,
        // we might have to wake up earlier to check if an app is anr'ing.
        const nsecs_t nextAnrCheck = processAnrsLocked();
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

        // We are about to enter an infinitely long sleep, because we have no commands or
        // pending or queued events
        if (nextWakeupTime == LONG_LONG_MAX) {
            mDispatcherEnteredIdle.notify_all();
        }
    } // release lock

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now(); //3
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); //4
    mLooper->pollOnce(timeoutMillis);
}

注释1处用于检查InputDispatcher的缓存队列中是否有等待处理的命令,如果没有就会调用注释2处的dispatchOnceInnerLocked函数进行窗口的分发。注释3处获取当前时间,注释4处得出休眠时间,然后调用pollOnce进入休眠,当InputReader有输入事件时,会唤醒InputDispatcher,重新进行事件的分发。
 

2.2.2 inputReader启动

InputReader也是在InputManager的start方法中启动的,与InputDispatcher一样,会创建一个InputThread在单独的线程中运行。
frameworks/native/services/inputflinger/reader/InputReader.cpp

status_t InputReader::start() {
    if (mThread) {
        return ALREADY_EXISTS;
    }
    mThread = std::make_unique<InputThread>(
            "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
    return OK;
}

threadLoop中执行的是loopOnce函数
frameworks/native/services/inputflinger/reader/InputReader.cpp

void InputReader::loopOnce() {
	...
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); //1

    { // acquire lock
       std::scoped_lock _l(mLock);
       mReaderIsAliveCondition.notify_all();

       if (count) {
           processEventsLocked(mEventBuffer, count); //2
     }
       ...
}

注释1处调用EvnetHub的getEvents函数获取事件信息,存储到mEventBuffer中。事件信息主要有两种,一种是设备节点的增删事件,一种是原始输入事件。注释2处processEventsLocked函数用于处理原始输入事件,并将其交给InputDispatcher来处理。

线程处理流程:

当两个线程启动后,InputReader在其线程循环中不断地从EventHub中抽取原始输入事件,进行加工处理后将加工所得的事件放入InputDispatcher的派发队列中;InputDispatcher则在其线程循环中将派发队列中的事件取出,查找合适的窗口,将事件写入窗口的事件接收管道中;窗口事件接收线程的Looper从管道中将事件取出,交由事件处理函数进行事件响应。


网站公告

今日签到

点亮在社区的每一天
去签到