input系统一 loop线程的创建与运行

Android中input系统的相关代码路径:

frameworks/base/core/java/android/os/ServiceManager.java
frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/java/com/android/server/wm/WindowManagerService.java
frameworks/base/services/java/com/android/server/wm/InputManager.java
frameworks/base/services/jni/com_android_server_InputManager.cpp
frameworks/base/services/input/*
input事件能被实时处理,冥冥之中有某个服务会运行某些监听线程,不停的监测它。我是这样想的。


 

一 loop线程的创建

 

1 SystemServer

android init进程启动SystemServer,负责android服务的启动和管理。/core/java/com/android/internal/os/ZygoteInit.java中private static boolean startSystemServer()启动SystemServer,最后调用env->GetStaticMethodID(clazz, "init2", "()V")启动线程池,并进入它的run方法。
public class SystemServer {
......
   public static final void init2() {
        Slog.i(TAG, "Entered the Android system server!");
        Thread thr = new ServerThread();
        thr.setName("android.server.ServerThread");
        thr.start();
    }
}
那么这个线程对象是一个ServerThread的实例。它的run方法:
public class SystemServer {
    @Override
  public void run() {
  ......
         Slog.i(TAG, "Input Manager");
            inputManager = new InputManagerService(context, wmHandler);

            Slog.i(TAG, "Window Manager");
            wm = WindowManagerService.main(context, power, display, inputManager,
                    uiHandler, wmHandler,
                    factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL,
                    !firstBoot, onlyCore);
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

            ActivityManagerService.self().setWindowManager(wm);

            inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
            inputManager.start();

            display.setWindowManager(wm);
            display.setInputManager(inputManager);
}

(1) 创建了一个java层input设备管理器inputManager。
(2) 运行WindowManagerService.main()方法。

public static WindowManagerService main(final Context context,
            final PowerManagerService pm, final DisplayManagerService dm,
            final InputManagerService im,
            final Handler uiHandler, final Handler wmHandler,
            final boolean haveInputMethods, final boolean showBootMsgs,
            final boolean onlyCore) {
        final WindowManagerService[] holder = new WindowManagerService[1];
        wmHandler.runWithScissors(new Runnable() {
            @Override
            public void run() {
                holder[0] = new WindowManagerService(context, pm, dm, im,
                        uiHandler, haveInputMethods, showBootMsgs, onlyCore);
            }
        }, 0);
        return holder[0];
    }
参数好多,代码不长。runWithScissors() run了一个特殊的同步task,不出意外,可以执行到Runnable.run()。run()里new了一个WindowManagerService,其构造函数也是长又长,不是代码长,是结构名字长;相关的一句是:
mInputManager = inputManager;
mInputManager是class WindowManagerService的一个成员变量,是class InputManagerService的实例。
至此,需要知道的是:创建了一个class WindowManagerService的实例wm,wm的一个成员变量mInputManager是class InputManagerService的实例。
(3) add WINDOW_SERVICE = "window"和INPUT_SERVICE = "input"服务。
(4) 添加WindowManagerService到服务列表。
(5) 设置了mWindowManagerCallbacks = wm.getInputMonitor()。
(6) start (启动)inputManager。
(7) 设置与window manager和input manager相关联的display manager。
至此,需要知道的是:android ini进程启动了一个服务总管SystemServer,它添加了一个WindowManagerService服务,这个服务中有一个mInputManager成员,是class InputManagerService的一个实例,这是与input系统相关的一个结构了。

2 InputManagerService和NativeInputManager

我们只关心input相关的信息,看一下InputManagerService的构造方法。
 public InputManagerService(Context context, Handler handler) {
        this.mContext = context;
        this.mHandler = new InputManagerHandler(handler.getLooper());

        mUseDevInputEventForAudioJack =
                context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
        Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
                + mUseDevInputEventForAudioJack);
        mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
    }

看到了nativeInit()进入native空间了。base/services/jni/com_android_server_input_InputManagerService.cpp 里有一张表可以找到java空间与native空间函数的对应关系。

static JNINativeMethod gInputManagerMethods[] = {
    /* name, signature, funcPtr */
    { "nativeInit",
            "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)I",
            (void*) nativeInit },
......
};
继续nativeInit()。
static jint nativeInit(JNIEnv* env, jclass clazz,
        jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
    if (messageQueue == NULL) {
        jniThrowRuntimeException(env, "MessageQueue is not initialized.");
        return 0;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());
    im->incStrong(0);
    return reinterpret_cast<jint>(im);
}
创建了一个 NativeInputManager的实例im,其构造函数为:
NativeInputManager::NativeInputManager(jobject contextObj,
        jobject serviceObj, const sp<Looper>& looper) :
        mLooper(looper) {
    JNIEnv* env = jniEnv();

    mContextObj = env->NewGlobalRef(contextObj);
    mServiceObj = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);

        mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
        mLocked.pointerSpeed = 0;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
    }

    sp<EventHub> eventHub = new EventHub();
    mInputManager = new InputManager(eventHub, this, this);
}
这里又出现了两个input系统相关的结构class EventHub和class InputManager。先创建了一个class EventHub的强指针eventHub,并以此为参数创建了一个class InputManager实例mInputManager,要注意的是这个mInputManager是class NativeInputManager的一个成员变量,是class InputManager的实例;前面提到的mInputManager是class WindowManagerService的一个成员变量,是class InputManagerService的实例。至此,创建了一个native层的input设备管理器mInputManage。jint nativeInit()最后return reinterpret_cast<jint>(im)一个NativeInputManager指针到mPtr中,InputManagerService的mPtr成员变量。
至此,需要知道的是:android ini进程启动了一个服务总管SystemServer,它添加了一个WindowManagerService服务,这个服务中有一个mInputManager成员;是class InputManagerService的一个实例,也就是java层的input设备管理器,它和native层的input设备管理器怎么联系的呢?InputManagerService中有一个mPtr成员,保存了native空间input设备管理器mInputManager宿主NativeInputManager的指针。

3 InputManager中线程的创建

native空间的input设备管理器是InputManager的实例,它是input系统的管理者。接着上一节;看一下它的构造函数。
InputManager::InputManager(
        const sp<EventHubInterface>& eventHub,
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = new InputDispatcher(dispatcherPolicy);
    mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
    initialize();
}

InputManager是大管家,怎么会自己干活呢,肯定是找家丁啊。家丁1号mEventHub,是class EventHub的实例。家丁2号mDispatcher,是class InputDispatcher的实例。家丁3号mReader,是class InputReader的实例。构造mReader时需要eventHub和mDispatcher作为参数,看来家丁3号还有点权力。

void InputManager::initialize() {
    mReaderThread = new InputReaderThread(mReader);
    mDispatcherThread = new InputDispatcherThread(mDispatcher);    
}
这就是了,传说中的创建线程对象。这里分别创建了class InputReaderThread(负责input事件的获取)和class InputDispatcherThread(负责input消息的发送)的实例,用于初始化InputManager的mReaderThread和mDispatcherThread成员。class InputDispatcherThread和class InputReaderThread 类似。
class InputReaderThread : public Thread {
public:
    InputReaderThread(const sp<InputReaderInterface>& reader);
    virtual ~InputReaderThread();

private:
    sp<InputReaderInterface> mReader;

    virtual bool threadLoop();
};
看到threadLoop()方法就仿佛看到了希望,为什么这样说?因为我抢先看了threadLoop()实现。
bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}
接着有跟到了void InputReader::loopOnce();果然这个函数就是需要loop的函数。我坚信在代码的某个旮旯深处;会调用这个threadLoop(),至于是哪个旮旯,就先放一放;当务之急是搞明白input系统中的管家和家丁们的职责和特权。正如三国杀,只有了解手中武将牌的能力和特权,才能掌握胜算。接下来的一段是摘抄的。

Eventhub

它是系统中所有事件的中央处理站。它管理所有系统中可以识别的输入设备的输入事件,此外,当设备增加或删除时,EventHub将产生相应的输入事件给系统。EventHub通过getEvents函数,给系统提供一个输入事件流。它也支持查询输入设备当前的状态(如哪些键当前被按下)。而且EventHub还跟踪每个输入调入的能力,比如输入设备的类别,输入设备支持哪些按键。

InputReader

InputReader从EventHub中读取原始事件数据(RawEvent),并由各个InputMapper处理之后输入对应的input listener。
InputReader拥有一个InputMapper集合。它做的大部分工作在InputReader线程中完成,但是InputReader可以接受任意线程的查询。
为了可管理性,InputReader使用一个简单的Mutex来保护它的状态。
InputReader拥有一个EventHub对象,但这个对象不是它创建的,而是在创建InputReader时作为参数传入的。

InputDispatcher

InputDispatcher负责把事件分发给输入目标,其中的一些功能(如识别输入目标)由独立的policy对象控制。

InputManager

InputManager是系统事件处理的核心,它虽然不做具体的事,但管理工作还是要做的,比如接受我们客户的投诉和索赔要求,或者老板的出气筒。
InputManager使用两个线程:
1)InputReaderThread叫做"InputReader"线程,它负责读取并预处理RawEvent,applies 
policy并且把消息送入DispatcherThead管理的队列中。
2)InputDispatcherThread叫做"InputDispatcher"线程,它在队列上等待新的输入事件,并且
异步地把这些事件分发给应用程序。
InputReaderThread类与InputDispatcherThread类不共享内部状态,所有的通信都是单向的,
从InputReaderThread到InputDispatcherThread。
两个类可以通过InputDispatchPolicy进行交互。
InputManager类从不与Java交互,而InputDispatchPolicy负责执行所有与系统的外部交互,包括调用DVM业务。

 

二 loop线程的启动

 

1 SystemServer

基本每个启动都是由start完成的,start似曾相识,回到SytemServer的run(),就能找到它的身影。inputManager.start(),这是一段旅程的开始,从此踏上寻找不老泉的征途。

 public void start() {
        Slog.i(TAG, "Starting input manager");
        nativeStart(mPtr);

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

        registerPointerSpeedSettingObserver();
        registerShowTouchesSettingObserver();

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

        updatePointerSpeedFromSettings();
        updateShowTouchesFromSettings();
  }
还记得mPtr吗?那个曾经的它。它是一个锋芒的针,存了一个native空间的input设备管理器的宿主NativeInputManager,这注定了它属于native世界的命运,它要从那里开始nativeStart(mPtr)。好吧,再去它的世界看看;怎么去?求助中转站啊,那里有一张表可以找到native空间的地址。
static JNINativeMethod gInputManagerMethods[] = {
    { "nativeStart", "(I)V",
            (void*) nativeStart },
};
static void nativeStart(JNIEnv* env, jclass clazz, jint ptr) {
    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

    status_t result = im->getInputManager()->start();
    if (result) {
        jniThrowRuntimeException(env, "Input manager could not be started.");
    }
}
im就是mPtr的变身;是NativeInputManager的指针。im->getInputManager()返回的就是native的input设备管理器mInputManager。

2 InputManager中线程的运行

mInputManager是一个class InputManager的实例,继续到它的start()都做了什么?
status_t InputManager::start() {
    status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputDispatcher thread due to error %d.", result);
        return result;
    }

    result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
    if (result) {
        ALOGE("Could not start InputReader thread due to error %d.", result);

        mDispatcherThread->requestExit();
        return result;
    }
   
    return OK;
}
还记得InputManager()->initialize()创建的两个线程对象吗?现在走到了他们的run()方法。貌似这两个线程对象没有run()啊,那就找他的爸爸呗,它们是Thread的子类,自然继承了Thread的run()方法。找到了run(),就可以接着启动了。
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
    Mutex::Autolock _l(mLock);

    if (mRunning) {
        // thread already started
        return INVALID_OPERATION;
    }

    // reset status and exitPending to their default value, so we can
    // try again after an error happened (either below, or in readyToRun())
    mStatus = NO_ERROR;
    mExitPending = false;
    mThread = thread_id_t(-1);
    
    // hold a strong reference on ourself
    mHoldSelf = this;

    mRunning = true;

    bool res;
    if (mCanCallJava) {
        res = createThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    } else {
        res = androidCreateRawThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    }
    
    if (res == false) {
        mStatus = UNKNOWN_ERROR;   // something happened!
        mRunning = false;
        mThread = thread_id_t(-1);
        mHoldSelf.clear();  // "this" may have gone away after this.

        return UNKNOWN_ERROR;
    }
    
    // Do not refer to mStatus here: The thread is already running (may, in fact
    // already have exited with a valid mStatus result). The NO_ERROR indication
    // here merely indicates successfully starting the thread and does not
    // imply successful termination/execution.
    return NO_ERROR;

    // Exiting scope of mLock is a memory barrier and allows new thread to run
}
查找关键字_threadLoop,createThreadEtc()负责创建android线程;其中,int Thread::_threadLoop(void* user)函数最为线程函数,this传给线程函数的参数user;this是什么?就是mDispatcherThread或mReaderThread,谁用了这,这个run()就是谁了,不是都不行。
int Thread::_threadLoop(void* user)
{
    Thread* const self = static_cast<Thread*>(user);

    sp<Thread> strong(self->mHoldSelf);
    wp<Thread> weak(strong);
    self->mHoldSelf.clear();

#ifdef HAVE_ANDROID_OS
    // this is very useful for debugging with gdb
    self->mTid = gettid();
#endif

    bool first = true;

    do {
        bool result;
        if (first) {
            first = false;
            self->mStatus = self->readyToRun();
            result = (self->mStatus == NO_ERROR);

            if (result && !self->exitPending()) {
                // Binder threads (and maybe others) rely on threadLoop
                // running at least once after a successful ::readyToRun()
                // (unless, of course, the thread has already been asked to exit
                // at that point).
                // This is because threads are essentially used like this:
                //   (new ThreadSubclass())->run();
                // The caller therefore does not retain a strong reference to
                // the thread and the thread would simply disappear after the
                // successful ::readyToRun() call instead of entering the
                // threadLoop at least once.
                result = self->threadLoop();
            }
        } else {
            result = self->threadLoop();
        }

        // establish a scope for mLock
        {
        Mutex::Autolock _l(self->mLock);
        if (result == false || self->mExitPending) {
            self->mExitPending = true;
            self->mRunning = false;
            // clear thread ID so that requestExitAndWait() does not exit if
            // called by a new thread using the same thread ID as this one.
            self->mThread = thread_id_t(-1);
            // note that interested observers blocked in requestExitAndWait are
            // awoken by broadcast, but blocked on mLock until break exits scope
            self->mThreadExitedCondition.broadcast();
            break;
        }
        }
        
        // Release our strong reference, to let a chance to the thread
        // to die a peaceful death.
        strong.clear();
        // And immediately, re-acquire a strong reference for the next loop
        strong = weak.promote();
    } while(strong != 0);
    
    return 0;
}
selt是user的一个变身了,假设user是mReaderThread,先不管mDispatcherThread。我说的变身一般是只类型转换,java中有很多形式的类型转换,有待研究。
毫无悬念的调用了result = self->threadLoop(),在Thread中 virtual bool threadLoop() = 0;是一个纯虚函数,需要子类重写;那回到孩子身上吧。
bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}
这个不是之前抢先看的东东吗?现在是DVD版的了,要清楚很多了。
void InputReader::loopOnce() {
    int32_t oldGeneration;
    int32_t timeoutMillis;
    bool inputDevicesChanged = false;
    Vector<InputDeviceInfo> inputDevices;
    { // acquire lock
        AutoMutex _l(mLock);

        oldGeneration = mGeneration;
        timeoutMillis = -1;

        uint32_t changes = mConfigurationChangesToRefresh;
        if (changes) {
            mConfigurationChangesToRefresh = 0;
            timeoutMillis = 0;
            refreshConfigurationLocked(changes);
        } else if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
        }
    } // release lock

    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);

    { // acquire lock
        AutoMutex _l(mLock);
        mReaderIsAliveCondition.broadcast();

        if (count) {
            processEventsLocked(mEventBuffer, count);
        }

        if (mNextTimeout != LLONG_MAX) {
            nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
            if (now >= mNextTimeout) {
#if DEBUG_RAW_EVENTS
                ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
#endif
                mNextTimeout = LLONG_MAX;
                timeoutExpiredLocked(now);
            }
        }

        if (oldGeneration != mGeneration) {
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);
        }
    } // release lock

    // Send out a message that the describes the changed input devices.
    if (inputDevicesChanged) {
        mPolicy->notifyInputDevicesChanged(inputDevices);
    }

    // Flush queued events out to the listener.
    // This must happen outside of the lock because the listener could potentially call
    // back into the InputReader's methods, such as getScanCodeState, or become blocked
    // on another thread similarly waiting to acquire the InputReader lock thereby
    // resulting in a deadlock.  This situation is actually quite plausible because the
    // listener is actually the input dispatcher, which calls into the window manager,
    // which occasionally calls into the input reader.
    mQueuedListener->flush();
}
(1) mEventHub->getEvents()获取input事件。
(2) processEventsLocked(mEventBuffer, count);处理input事件。
现在回过头看看user是mDispatcherThread的情况,都说了和InputReaderThread差不多。
bool InputReaderThread::threadLoop() {
    mReader->loopOnce();
    return true;
}
bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce();
    return true;
}
void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    { // acquire lock
        AutoMutex _l(mLock);
        mDispatcherIsAliveCondition.broadcast();

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

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

    // Wait for callback or timeout or wake.  (make sure we round up, not down)
    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis);
}
(1) dispatchOnceInnerLocked(&nextWakeupTime)对input输入消息进行分发。
(2) mLooper->pollOnce(timeoutMillis)等待下一次输入事件,会调用Looper::pollOnce(),据说Looper里主要通过linux管道方式实现进程间通信,通过epoll机制实现外界事件请求作出响应。

你可能感兴趣的:(android)