您的位置:首页 > 其它

InputManager 的启动过程

2015-11-10 16:08 211 查看
文章出处:http://blog.csdn.net/shift_wwx/article/details/49761161

请转载的朋友标明出处~~

之前Android input 按键处理过程 中说到将Android 的按键处理分为几个过程,这里根据source code 来分析第一个过程。


android SystemServer详解中将了SystemServer的启动过程,我们知道Android 相关的关键服务都是在这里启动的,其中就包含了InputManagerService 和 WindowManagerServcie。

Slog.i(TAG, "Input Manager");
inputManager = new InputManagerService(context);

Slog.i(TAG, "Window Manager");
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore);
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);

......

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

主要分四部分:InputManagerService的构造、WindowManagerService main 调用、inputManager注册callback、inputManager 的start

一、InputManagerService 构造

public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());

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

LocalServices.addService(InputManagerInternal.class, new LocalService());
}
分三部分:

1、InputManagerHandler

private final class InputManagerHandler extends Handler {
public InputManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
}

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DELIVER_INPUT_DEVICES_CHANGED:
deliverInputDevicesChanged((InputDevice[])msg.obj);
break;
case MSG_SWITCH_KEYBOARD_LAYOUT:
handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
break;
case MSG_RELOAD_KEYBOARD_LAYOUTS:
reloadKeyboardLayouts();
break;
case MSG_UPDATE_KEYBOARD_LAYOUTS:
updateKeyboardLayouts();
break;
case MSG_RELOAD_DEVICE_ALIASES:
reloadDeviceAliases();
break;
}
}
}
从code 看是对Input device 进行一些处理,如nofication等。

注意传进来的参数是一个Looper,这个Looper 是从HandlerThread 来的。详细的可以看一下Android HandlerThread

2、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:

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);
}
这里只要是创建了一个EventHub实例,并且把这个EventHub作为参数来创建InputManager对象。注意,这里的InputManager类是定义在C++层的,和前面在Java层的InputManager不一样,不过它们是对应关系。EventHub类是真正执行监控键盘事件操作的地方,后面我们会进一步分析到,现在我们主要关心InputManager实例的创建过程,它会InputManager类的构造函数里面执行一些初始化操作:

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();
}
这里主要是创建了一个InputDispatcher对象和一个InputReader对象,并且分别保存在成员变量mDispatcher和mReader中。InputDispatcher类是负责把键盘消息分发给当前激活的Activity窗口的,而InputReader类则是通过EventHub类来实现读取键盘事件的,后面我们会进一步分析。创建了这两个对象后,还要调用initialize函数来执行其它的初始化操作:

void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
这个函数创建了一个InputReaderThread线程实例和一个InputDispatcherThread线程实例,并且分别保存在成员变量mReaderThread和mDispatcherThread中。这里的InputReader实列mReader就是通过这里的InputReaderThread线程实列mReaderThread来读取键盘事件的,而InputDispatcher实例mDispatcher则是通过这里的InputDispatcherThread线程实例mDisptacherThread来分发键盘消息的。

小结一下InputManagerService 的构造:

1)构造InputManagerHandler,确认DisplayThread 的Looper,用于input device 一些状态变化的控制

2)构造EventHub 监控按键操作

3)构造InputManager,实例InputReader、InputDispatcher,前者负责读取系统中的键盘消息,后者负责把键盘消息分发出去

4)InputReader对象和一个InputDispatcher对象分别是通过InputReaderThread线程实例和InputDispatcherThread线程实例来实键盘消息的读取和分发的。

二、WindowManagerService main 调用

public static WindowManagerService main(final Context context,
final InputManagerService im,
final boolean haveInputMethods, final boolean showBootMsgs,
final boolean onlyCore) {
final WindowManagerService[] holder = new WindowManagerService[1];
DisplayThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
holder[0] = new WindowManagerService(context, im,
haveInputMethods, showBootMsgs, onlyCore);
}
}, 0);
return holder[0];
}
1、DisplayThread
public final class DisplayThread extends ServiceThread {
private static DisplayThread sInstance;
private static Handler sHandler;

private DisplayThread() {
super("android.display", android.os.Process.THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
}

private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new DisplayThread();
sInstance.start();
sHandler = new Handler(sInstance.getLooper());
}
}

public static DisplayThread get() {
synchronized (DisplayThread.class) {
ensureThreadLocked();
return sInstance;
}
}

public static Handler getHandler() {
synchronized (DisplayThread.class) {
ensureThreadLocked();
return sHandler;
}
}
}
可以看到两个变量都是static,这里的DisplayThread 在第一部分的InputManagerHandler 构造函数中就提到了,显然是共用的一个Thread。

2、WindowManagerService()

private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
......

mInputManager = inputManager; // Must be before createDisplayContentLocked.

......

mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG));

......

}


三、注册callback

public void setWindowManagerCallbacks(WindowManagerCallbacks callbacks) {
mWindowManagerCallbacks = callbacks;
}
参数callbacks 是:wm.getInputMonitor()

public InputMonitor getInputMonitor() {
return mInputMonitor;
}
我们之前说过InputManager 通过InputDispatcher 来分发按键,那么到了上层之后其实完全都是通过InputMonitor 来中转。

final class InputMonitor implements InputManagerService.WindowManagerCallbacks {


public interface WindowManagerCallbacks {
public void notifyConfigurationChanged();

public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen);

public void notifyCameraLensCoverSwitchChanged(long whenNanos, boolean lensCovered);

public void notifyInputChannelBroken(InputWindowHandle inputWindowHandle);

public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason);

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags);

public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags);

public long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags);

public KeyEvent dispatchUnhandledKey(InputWindowHandle focus,
KeyEvent event, int policyFlags);

public int getPointerLayer();
}
例如interceptKeyBeforeDispatching:

InputManager 从native 调用java 的接口是:

private long interceptKeyBeforeDispatching(InputWindowHandle focus,
KeyEvent event, int policyFlags) {
return mWindowManagerCallbacks.interceptKeyBeforeDispatching(focus, event, policyFlags);
}
然后就会通过InputMonitor:

@Override
public long interceptKeyBeforeDispatching(
InputWindowHandle focus, KeyEvent event, int policyFlags) {
WindowState windowState = focus != null ? (WindowState) focus.windowState : null;
return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
}


四、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();
}
1、nativeStart

static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);

status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
就是第一点nativeInt 中的一些实例,这里是实例的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;
}
这个函数主要就是分别启动一个InputDispatcherThread线程和一个InputReaderThread线程来读取和分发键盘消息的了。这里的InputDispatcherThread线程对象mDispatcherThread和InputReaderThread线程对象是在前面的nativeInit 中创建的,调用了它们的run函数后,就会进入到它们的threadLoop函数中去,只要threadLoop函数返回true,函数threadLoop就会一直被循环调用,于是这两个线程就起到了不断地读取和分发键盘消息的作用。

  我们先来分析InputDispatcherThread线程分发消息的过程,然后再回过头来分析InputReaderThread线程读取消息的过程。

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);
}
这个函数就是把键盘消息交给dispatchOnceInnerLocked函数来处理,这个过程我们在后面再详细分析,然后调用mLooper->pollOnce函数等待下一次键盘事件的发生

再来看看InputReaderThread:

bool InputReaderThread::threadLoop() {
mReader->loopOnce();
return true;
}
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();
}
这里通过成员函数mEventHub来负责键盘消息的读取工作,如果当前有键盘事件发生或者有键盘事件等待处理,通过mEventHub的getEvent函数就可以得到这个事件,然后交给process函数进行处理,这个函数主要就是唤醒前面的InputDispatcherThread线程,通知它有新的键盘事件发生了,它需要进行一次键盘消息的分发操作了,这个函数我们后面再进一步详细分析;如果没有键盘事件发生或者没有键盘事件等待处理,那么调用mEventHub的getEvent函数时就会进入等待状态。

下面来看一下mEventHub.getEvent:
因为函数太长,就选择性的说一下,source code 在/framework/native/services/inputflinger/EventHub.cpp

if (mNeedToScanDevices) {
mNeedToScanDevices = false;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
在需要scan  devices 的时候,会做一次:

void EventHub::scanDevicesLocked() {
status_t res = scanDirLocked(DEVICE_PATH);
if(res < 0) {
ALOGE("scan dir failed for %s\n", DEVICE_PATH);
}
if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {
createVirtualKeyboardLocked();
}
}
static const char *DEVICE_PATH = "/dev/input";
在设备目录/dev/input中,一般有三个设备文件存在,分别是event0、mice和mouse0设备文件,其中,键盘事件就包含在event0设备文件中了。

status_t EventHub::scanDirLocked(const char *dirname)
{
char devname[PATH_MAX];
char *filename;
DIR *dir;
struct dirent *de;
dir = opendir(dirname);
if(dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while((de = readdir(dir))) {
if(de->d_name[0] == '.' &&
(de->d_name[1] == '\0' ||
(de->d_name[1] == '.' && de->d_name[2] == '\0')))
continue;
strcpy(filename, de->d_name);
openDeviceLocked(devname);
}
closedir(dir);
return 0;
}

会依次openDeviceLocked:

status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80];

ALOGV("Opening device: %s", devicePath);

int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}

InputDeviceIdentifier identifier;

// Get device name.
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
}

// Check to see if the device is on our excluded list
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
const String8& item = mExcludedDevices.itemAt(i);
if (identifier.name == item) {
ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
close(fd);
return -1;
}
}

// Get device driver version.
int driverVersion;
if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}

// Get device identifier.
struct input_id inputId;
if(ioctl(fd, EVIOCGID, &inputId)) {
ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version;

// Get device physical location.
if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.location.setTo(buffer);
}

// Get device unique id.
if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.uniqueId.setTo(buffer);
}

// Fill in the descriptor.
assignDescriptorLocked(identifier);

// Make file descriptor non-blocking for use with poll().
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
ALOGE("Error %d making device file descriptor non-blocking.", errno);
close(fd);
return -1;
}

// Allocate device.  (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);

ALOGV("add device %d: %s\n", deviceId, devicePath);
ALOGV("  bus:        %04x\n"
"  vendor      %04x\n"
"  product     %04x\n"
"  version     %04x\n",
identifier.bus, identifier.vendor, identifier.product, identifier.version);
ALOGV("  name:       \"%s\"\n", identifier.name.string());
ALOGV("  location:   \"%s\"\n", identifier.location.string());
ALOGV("  unique id:  \"%s\"\n", identifier.uniqueId.string());
ALOGV("  descriptor: \"%s\"\n", identifier.descriptor.string());
ALOGV("  driver:     v%d.%d.%d\n",
driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff);

// Load the configuration file for the device.
loadConfigurationLocked(device);

// Figure out the kinds of events the device reports.
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);
ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);
ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);
ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);
ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);

// See if this is a keyboard.  Ignore everything in the button range except for
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC))
|| containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
sizeof_bit_array(KEY_MAX + 1));
bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
sizeof_bit_array(BTN_MOUSE))
|| containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK),
sizeof_bit_array(BTN_DIGI));
if (haveKeyboardKeys || haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}

// See if this is a cursor device such as a trackball or mouse.
if (test_bit(BTN_MOUSE, device->keyBitmask)
&& test_bit(REL_X, device->relBitmask)
&& test_bit(REL_Y, device->relBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_CURSOR;
}

// See if this is a touch pad.
// Is this a new modern multi-touch driver?
if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
&& test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
// Some joysticks such as the PS3 controller report axes that conflict
// with the ABS_MT range.  Try to confirm that the device really is
// a touch screen.
if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
}
// Is this an old style single-touch driver?
} else if (test_bit(BTN_TOUCH, device->keyBitmask)
&& test_bit(ABS_X, device->absBitmask)
&& test_bit(ABS_Y, device->absBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_TOUCH;
}

// See if this device is a joystick.
// Assumes that joysticks always have gamepad buttons in order to distinguish them
// from other devices such as accelerometers that also have absolute axes.
if (haveGamepadButtons) {
uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
for (int i = 0; i <= ABS_MAX; i++) {
if (test_bit(i, device->absBitmask)
&& (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
device->classes = assumedClasses;
break;
}
}
}

// Check whether this device has switches.
for (int i = 0; i <= SW_MAX; i++) {
if (test_bit(i, device->swBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_SWITCH;
break;
}
}

// Check whether this device supports the vibrator.
if (test_bit(FF_RUMBLE, device->ffBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
}

// Configure virtual keys.
if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
// Load the virtual keys for the touch screen, if any.
// We do this now so that we can make sure to load the keymap if necessary.
status_t status = loadVirtualKeyMapLocked(device);
if (!status) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
}

// Load the key map.
// We need to do this for joysticks too because the key layout may specify axes.
status_t keyMapStatus = NAME_NOT_FOUND;
if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
// Load the keymap for the device.
keyMapStatus = loadKeyMapLocked(device);
}

// Configure the keyboard, gamepad or virtual keyboard.
if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
// Register the keyboard as a built-in keyboard if it is eligible.
if (!keyMapStatus
&& mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD
&& isEligibleBuiltInKeyboard(device->identifier,
device->configuration, &device->keyMap)) {
mBuiltInKeyboardId = device->id;
}

// 'Q' key support = cheap test of whether this is an alpha-capable kbd
if (hasKeycodeLocked(device, AKEYCODE_Q)) {
device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
}

// See if this device has a DPAD.
if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) &&
hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) {
device->classes |= INPUT_DEVICE_CLASS_DPAD;
}

// See if this device has a gamepad.
for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) {
if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) {
device->classes |= INPUT_DEVICE_CLASS_GAMEPAD;
break;
}
}

// Disable kernel key repeat since we handle it ourselves
unsigned int repeatRate[] = {0,0};
if (ioctl(fd, EVIOCSREP, repeatRate)) {
ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno));
}
}

// If the device isn't recognized as something we handle, don't monitor it.
if (device->classes == 0) {
ALOGV("Dropping device: id=%d, path='%s', name='%s'",
deviceId, devicePath, device->identifier.name.string());
delete device;
return -1;
}

// Determine whether the device is external or internal.
if (isExternalDeviceLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL;
}

if (device->classes & (INPUT_DEVICE_CLASS_JOYSTICK | INPUT_DEVICE_CLASS_DPAD)
&& device->classes & INPUT_DEVICE_CLASS_GAMEPAD) {
device->controllerNumber = getNextControllerNumberLocked(device);
setLedForController(device);
}

// Register with epoll.
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP;
eventItem.data.u32 = deviceId;
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
delete device;
return -1;
}

String8 wakeMechanism("EPOLLWAKEUP");
if (!mUsingEpollWakeup) {
#ifndef EVIOCSSUSPENDBLOCK
// uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels
// will use an epoll flag instead, so as long as we want to support
// this feature, we need to be prepared to define the ioctl ourselves.
#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
#endif
if (ioctl(fd, EVIOCSSUSPENDBLOCK, 1)) {
wakeMechanism = "<none>";
} else {
wakeMechanism = "EVIOCSSUSPENDBLOCK";
}
}

// Tell the kernel that we want to use the monotonic clock for reporting timestamps
// associated with input events.  This is important because the input system
// uses the timestamps extensively and assumes they were recorded using the monotonic
// clock.
//
// In older kernel, before Linux 3.4, there was no way to tell the kernel which
// clock to use to input event timestamps.  The standard kernel behavior was to
// record a real time timestamp, which isn't what we want.  Android kernels therefore
// contained a patch to the evdev_event() function in drivers/input/evdev.c to
// replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic
// clock to be used instead of the real time clock.
//
// As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock.
// Therefore, we no longer require the Android-specific kernel patch described above
// as long as we make sure to set select the monotonic clock.  We do that here.
int clockId = CLOCK_MONOTONIC;
bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);

ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, "
"wakeMechanism=%s, usingClockIoctl=%s",
deviceId, fd, devicePath, device->identifier.name.string(),
device->classes,
device->configurationFile.string(),
device->keyMap.keyLayoutFile.string(),
device->keyMap.keyCharacterMapFile.string(),
toString(mBuiltInKeyboardId == deviceId),
wakeMechanism.string(), toString(usingClockIoctl));

addDeviceLocked(device);
return 0;
}
函数首先根据文件名来打开这个设备文件:
int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
}
接下来是device 的初始化工作:

if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
if(ioctl(fd, EVIOCGID, &inputId)) {
if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
紧接着初始化config:

loadConfigurationLocked(device);
初始化device 类型:

device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
device->classes |= INPUT_DEVICE_CLASS_CURSOR;
device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
device->classes |= INPUT_DEVICE_CLASS_SWITCH;
device->classes |= INPUT_DEVICE_CLASS_VIBRATOR;
device->classes |= INPUT_DEVICE_CLASS_DPAD;


等等

最后调用:

addDeviceLocked(device);


void EventHub::addDeviceLocked(Device* device) {
mDevices.add(device->id, device);
device->next = mOpeningDevices;
mOpeningDevices = device;
}
KeyedVector<int32_t, Device*> mDevices;

到此scanDevicesLocked(); 大概差不多了,返回getEvents:

while (mOpeningDevices != NULL) {
    Device* device = mOpeningDevices;
    ALOGV("Reporting device opened: id=%d, name=%s\n",
         device->id, device->path.string());
    mOpeningDevices = device->next;
    event->when = now;
    event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
    event->type = DEVICE_ADDED;
    event += 1;
    mNeedToSendFinishedDeviceScan = true;
    if (--capacity == 0) {
        break;
    }
}
检查是否有新设备添加进来,接着结束检查:

if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
if (--capacity == 0) {
break;
}
}
剩下的就是处理event 了。暂时不做介绍了。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: