安卓Input功能学习笔记
1 文章导读
1.1 文档面向的人群
面向安卓应用和系统开发人员,能够了解Input系统相关内容,如Input事件的生产、传递、消费流程;
1.2 整理文档的目的
作为Input系统的学习笔记,记录并整理相关内容,经常回顾,加深对Input系统的理解;
1.3 文档内容简介
本文介绍安卓系统驱动以上的整体流程,包括InputManagerService,InputFlinger,App层相关内容;
2 功能学习计划
2.1 目的和学习内容
了解安卓系统Input子系统的设计和实现方法,期望能够提出对某个系统的输入框架的理解,具备Input子系统的架构能力;
能够解决Input相关问题,实现Input相关功能定制,如多屏控制(监护模式)、硬按键、多输入法等功能。
2.2 抛出问题,带着问题学习
1.Input事件/对象是从哪里生产的?如何转换为MotionEvent和KeyEvent等事件?
2.系统会将Input事件传递给前台窗口,是如何判断前台窗口的?
3.系统和App进程的Input交互通道是什么,如何建立的?
4.Input事件在系统侧的传递流程是什么样的?
5.App进程是如何接收到Input事件的?
6.Input事件在App侧的传递流程是什么样的?
7.Input事件有哪些类型,分别有什么用途?
8.输入法是如何工作的(可以另开章节,本篇不涉及)?
9.如何创建一个Input驱动文件,开发流程是什么样的?
10.系统是如何拦截Home/Volume等按键的?
11.Input事件处理超时会产生ANR,系统是如何实现的?
12.按键ScanCode和KeyCode转换方法;
2.3 预期的学习顺序和方法
1.阅读Input相关博客或文档,对模块和整体流程有模糊认知;
2.通过阅读AOSP中跟InputManagerService相关代码,了解IMS的初始化过程;
3.在App-View的onClickListener中打印堆栈信息,学习App侧Input事件传递流程;
4.阅读InputDispatcher/InputReader/EventHub相关代码,了解Input事件的生产流程和对象转换流程;
5.阅读IMS中事件传递相关代码,了解IMS传递事件时,如何选择目标App;
6.尝试编写测试App,确认不同输入事件的用途;
3 Input模块整体介绍
3.1 模块介绍和架构图
参考4.2.2和4.3.2章节图示;
3.2 模块关键类图
参考4.2.3和4.3.3章节类图;
3.4 子模块划分和介绍
Input系统可以划分以下子模块/流程,本篇会跟进调查这些流程,来对Input功能有完整的认识:
1.IMS服务初始化流程:
指系统在system_server进程创建InputManagerService时,初始化InputReader、InputDispatcher,准备读取Input事件的流程;
2.App创建InputChannel和注册到IMS的流程;
App和IMS的交互依赖InputChannel,需要调查App创建InputChannel对象的流程;
3.IMS读取和传递Input事件的流程;
IMS通过EventHub对象从驱动读取数据,并将这些数据进行传递的过程;
4.App接收Input事件的流程;
App从InputChannel中读取Input事件的流程;
5.App传递Input事件的流程;
App接收到Input事件时,将Input事件进行分类,传递给对应的Activity和View的流程;
4 子模块详细分析
4.1 IMS服务初始化流程
4.1.1 流程介绍
此处会介绍system_server进程启动后,初始化framework层Input框架的流程;
包括创建InputManagerServer及native层的InputReader,InputDispatcher的流程。
从InputManagerService对象创建,到InputReader线程启动,尝试读取输入数据为止,是本章节的主要流程;
4.1.2 相关模块架构图
4.1.3 类图
4.1.4 时序图
4.1.4.1 InputManagerService初始化流程
4.1.4.2 InputManagerService开始工作流程
4.1.5 代码解读
IMS初始化流程代码:
IMS的初始化流程,是在SystemServer.java中开始的,IMS服务也存活于system_server进程中;SystemServer在开机过程中会初始化IMS服务:
frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
...
InputManagerService inputManager = null;
..
// 调用IMS的构造方法
inputManager = new InputManagerService(context);
// MWS和IMS的关联关系
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
...
// 调用了start方法;
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
inputManager.start();
...
// 在AMS的systemReady中,调用inputManagerF.systemRunning();
mActivityManagerService.systemReady(() -> {
final InputManagerService inputManagerF = inputManager;
if (inputManagerF != null) {
inputManagerF.systemRunning();
}
以上代码,调用了IMS的以下三个关键方法: new InputManagerService(context);
inputManager.start(); inputManagerF.systemRunning();
接下来我们围绕这三个方法,确认IMS的初始化流程;
4.1.5.1 IMS构造方法
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// 由此可见,IMS本身是一个binder对象;
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {
public InputManagerService(Context context) {
this.mContext = context;
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
// 读取input 和display port的对应关系,此处好像决定了触屏事件和触屏id的对应关系,TODO;
mStaticAssociations = loadStaticInputPortAssociations();
mUseDevInputEventForAudioJack =
context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
+ mUseDevInputEventForAudioJack);
// 调用nativeinit方法,注意变量,service自身,context引用,还有messageQueue!
// 注意此处mPtr,是native层一个c++对象的内存地址。
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
String doubleTouchGestureEnablePath = context.getResources().getString(
R.string.config_doubleTouchGestureEnableFile);
mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
new File(doubleTouchGestureEnablePath);
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
来看下nativeInit方法的作用,入参是this-IMS对象,将一个java对象传入jni方法中,可能会有c++和java的相互调用;
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
private static native long nativeInit(InputManagerService service,
Context context, MessageQueue messageQueue);
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//创建了NativeIM对象,并返回此对象的内存地址;注意传参,java层的context,service和messagequeue!
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
// 返回im的内存地址,这样java就可以持有im的对象,并调用im对象的方法了;
return reinterpret_cast<jlong>(im);
}
来看下NativeInputManager的构造方法:
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
// mServiceObj是成员变量,NativeInputManager持有Java IMS对象的引用,可以调用java层的接口;
mServiceObj = env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
mLocked.pointerCapture = false;
mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
}
mInteractive = true;
//*
* 这里创建了native层的一个对象InputManager,注意传参为两个this!,
* 分别对应了NativeInputManager的两个不同的父类readerPolicy和dispatcherPolicy!
* 所以InputManager中的readerPolicy和dispatcherPolicy,都是指NativeInputManager对象;
*/
mInputManager = new InputManager(this, this);
/// 将mInputManager作为binder服务,添加到ServiceManager中,SurfaceFlinger里会用到。
defaultServiceManager()->addService(String16("inputflinger"),
mInputManager, false);
}
继续跟进new InputManager(this, this)的流程,NativeInputManager相当于java层的IMS和Native层的InputManager之间通信的桥梁:
frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
// 创建InputDispatcher对象,持有dispatcherPolicy-即NativeInputManager
mDispatcher = createInputDispatcher(dispatcherPolicy);
// 创建InputClassifier对象,持有mDispatcher
mClassifier = new InputClassifier(mDispatcher);
// 创建InputReader对象,持有readerPolicy和InputClassifier;
// 相当于持有了NativeInputManager和mDispatcher;
mReader = createInputReader(readerPolicy, mClassifier);
}
注意此处出现了耳熟能详的两个模块,InputDispatcher、InputReader; 我们来对以下三个关键方法进行一一分析
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
frameworks/native/services/inputflinger/dispatcher/InputDispatcherFactory.cpp
sp<InputDispatcherInterface> createInputDispatcher(
const sp<InputDispatcherPolicyInterface>& policy) {
// 创建InputDispatcher 对象;
return new android::inputdispatcher::InputDispatcher(policy);
}
构造方法:
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
: mPolicy(policy), // 注意这几处赋值;
mPendingEvent(nullptr),
mLastDropReason(DropReason::NOT_DROPPED),
mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
mAppSwitchSawKeyDown(false),
mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(nullptr),
mDispatchEnabled(false),
mDispatchFrozen(false),
mInputFilterEnabled(false),
// mInTouchMode will be initialized by the WindowManager to the default device config.
// To avoid leaking stack in case that call never comes, and for tests,
// initialize it here anyways.
mInTouchMode(true),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT) {
mLooper = new Looper(false);
mReporter = createInputReporter();
mKeyRepeatState.lastKeyEntry = nullptr;
// policy指向NativeInputManager,
// 此处通过NativeInputManager调用了Java层的方法,从java config文件中读取一些配置信息;
policy->getDispatcherConfiguration(&mConfig);
}
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
ATRACE_CALL();
JNIEnv* env = jniEnv();
// 此处从IMS中读取到了两个配置信息,并保存到了InputDispatcher的outConfig中;
jint keyRepeatTimeout = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getKeyRepeatTimeout);
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);// 查询keyRepeatTimeout
}
jint keyRepeatDelay = env->CallIntMethod(mServiceObj,
gServiceClassInfo.getKeyRepeatDelay);
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay); // 查询keyRepeatDelay
}
}
createInputDispatcher流程至此结束;
此处创建了InputDispatcher对象,并从java层读取了两个配置属性;
来继续看下mClassifier = new InputClassifier(mDispatcher);的流程
先来看下几个关键类的继承关系,以便对这些类的多重身份有一定的了解:
// InputDispatcher继承关系如下:
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.h
class InputDispatcher : public android::InputDispatcherInterface {
// 重要的函数声明;
frameworks/native/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface {
// 说明InputDispatcher会接收这些方法调用。
// 可能是通过InputReader->InputListener->InputDispatcher的流程进行调用;
frameworks/native/services/inputflinger/include/InputListener.h
class InputListenerInterface : public virtual RefBase {
protected:
InputListenerInterface() { }
virtual ~InputListenerInterface() { }
public:
virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0;
virtual void notifyKey(const NotifyKeyArgs* args) = 0;
virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
};
// 创建InputClassifier,这里的代码很简单,把mListener指向了listener,也就是InputDispatcher
frameworks/native/services/inputflinger/InputClassifier.cpp
InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener)
: mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
来看下关键的代码,根据名字也能猜出,此类跟Input事件和读取相关:
mReader = createInputReader(readerPolicy, mClassifier);
// 注意此处,是先通过make_unique创建了EventHub对象,然后在调用了InputReader的构造方法!
// 注意InputReader的三个入参:
// 一个是EventHud对象,一个是readerPilicy(也就是NativeInputManager),一个是InputClassifier;
frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy, const sp<InputListenerInterface>& listener) {
return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
来看下EventHub的创建流程,确认EventHub的功能,分析后再跟进InputReader的创建过程.
frameworks/native/services/inputflinger/reader/include/EventHub.h
/*
* Input device classes.
*/
enum {
/* The input device is a keyboard or has buttons. */
INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001,
/* The input device is an alpha-numeric keyboard (not just a dial pad). */
INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002,
/* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */
INPUT_DEVICE_CLASS_TOUCH = 0x00000004,
/* The input device is a cursor device such as a trackball or mouse. */
INPUT_DEVICE_CLASS_CURSOR = 0x00000008,
/* The input device is a multi-touch touchscreen. */
INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010,
/* The input device is a directional pad (implies keyboard, has DPAD keys). */
INPUT_DEVICE_CLASS_DPAD = 0x00000020,
/* The input device is a gamepad (implies keyboard, has BUTTON keys). */
INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040,
/* The input device has switches. */
INPUT_DEVICE_CLASS_SWITCH = 0x00000080,
/* The input device is a joystick (implies gamepad, has joystick absolute axes). */
INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100,
/* The input device has a vibrator (supports FF_RUMBLE). */
INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200,
/* The input device has a microphone. */
INPUT_DEVICE_CLASS_MIC = 0x00000400,
/* The input device is an external stylus (has data we want to fuse with touch data). */
INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800,
/* The input device has a rotary encoder */
INPUT_DEVICE_CLASS_ROTARY_ENCODER = 0x00001000,
/* The input device is virtual (not a real device, not part of UI configuration). */
INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000,
/* The input device is external (not built-in). */
INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
};
class EventHub : public EventHubInterface {
public:
EventHub();
class EventHubInterface {
public:
EventHubInterface() {}
...
}
class EventHub : public EventHubInterface {
public:
EventHub();
virtual uint32_t getDeviceClasses(int32_t deviceId) const override;
virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override;
virtual int32_t getDeviceControllerNumber(int32_t deviceId) const override;
virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override;
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const override;
virtual bool hasRelativeAxis(int32_t deviceId, int axis) const override;
virtual bool hasInputProperty(int32_t deviceId, int property) const override;
virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const override;
virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const override;
virtual void setExcludedDevices(const std::vector<std::string>& devices) override;
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override;
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const override;
virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
int32_t* outValue) const override;
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const override;
virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override;
virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override;
virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const override;
virtual bool hasLed(int32_t deviceId, int32_t led) const override;
virtual void setLedState(int32_t deviceId, int32_t led, bool on) override;
virtual void getVirtualKeyDefinitions(int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override;
virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const override;
virtual bool setKeyboardLayoutOverlay(int32_t deviceId,
const sp<KeyCharacterMap>& map) override;
virtual void vibrate(int32_t deviceId, nsecs_t duration) override;
virtual void cancelVibrate(int32_t deviceId) override;
virtual void requestReopenDevices() override;
virtual void wake() override;
virtual void dump(std::string& dump) override;
virtual void monitor() override;
virtual ~EventHub() override;
private:
// EventHub中定义了一个Device类型的结构体,根据next可以看到,这个是一个链表类型的数据结构;
// 每个Device的path,都在/dev/input下有对应的驱动文件;
struct Device {
Device* next;
int fd; // may be -1 if device is closed
const int32_t id;
const std::string path;
const InputDeviceIdentifier identifier;
std::unique_ptr<TouchVideoDevice> videoDevice;
uint32_t classes;
uint8_t keyBitmask[(KEY_MAX + 1) / 8];
uint8_t absBitmask[(ABS_MAX + 1) / 8];
uint8_t relBitmask[(REL_MAX + 1) / 8];
uint8_t swBitmask[(SW_MAX + 1) / 8];
uint8_t ledBitmask[(LED_MAX + 1) / 8];
uint8_t ffBitmask[(FF_MAX + 1) / 8];
uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
std::string configurationFile;
PropertyMap* configuration;
std::unique_ptr<VirtualKeyMap> virtualKeyMap;
KeyMap keyMap;
sp<KeyCharacterMap> overlayKeyMap;
sp<KeyCharacterMap> combinedKeyMap;
bool ffEffectPlaying;
int16_t ffEffectId; // initially -1
int32_t controllerNumber;
Device(int fd, int32_t id, const std::string& path,
const InputDeviceIdentifier& identifier);
~Device();
void close();
bool enabled; // initially true
status_t enable();
status_t disable();
bool hasValidFd();
const bool isVirtual; // set if fd < 0 is passed to constructor
const sp<KeyCharacterMap>& getKeyCharacterMap() const {
if (combinedKeyMap != nullptr) {
return combinedKeyMap;
}
return keyMap.keyCharacterMap;
}
};
// EventHub操作Device的一些方法;
status_t openDeviceLocked(const char* devicePath);
void openVideoDeviceLocked(const std::string& devicePath);
void createVirtualKeyboardLocked();
...
int32_t mNextDeviceId;
BitSet32 mControllerNumbers;
KeyedVector<int32_t, Device*> mDevices;
/**
* Video devices that report touchscreen heatmap, but have not (yet) been paired
* with a specific input device. Video device discovery is independent from input device
* discovery, so the two types of devices could be found in any order.
* Ideally, video devices in this queue do not have an open fd, or at least aren't
* actively streaming.
*/
std::vector<std::unique_ptr<TouchVideoDevice>> mUnattachedVideoDevices;
Device* mOpeningDevices;
Device* mClosingDevices;
bool mNeedToSendFinishedDeviceScan;
bool mNeedToReopenDevices;
bool mNeedToScanDevices;
std::vector<std::string> mExcludedDevices;
int mEpollFd;
int mINotifyFd;
int mWakeReadPipeFd;
int mWakeWritePipeFd;
...
};
EventHub的构造方法,我们看到make_unique方法,没有任何入参,所以EventHub是不依赖外部对象的,只会对外提供开放接口:
frameworks/native/services/inputflinger/reader/EventHub.cpp
// EventHub扫描Device的路径:
static const char* DEVICE_PATH = "/dev/input";
// v4l2 devices go directly into /dev
static const char* VIDEO_DEVICE_PATH = "/dev";
EventHub::EventHub(void)
: mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
mNextDeviceId(1),
mControllerNumbers(),
mOpeningDevices(nullptr),
mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false),
mNeedToScanDevices(true),
mPendingEventCount(0),
mPendingEventIndex(0),
mPendingINotify(false) {
ensureProcessCanBlockSuspend();
// 跟驱动交互相关的函数,看不懂~~~
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
// 初始化跟/dev/input/相关的数据;
mINotifyFd = inotify_init();
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
strerror(errno));
if (isV4lScanningEnabled()) {
mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
VIDEO_DEVICE_PATH, strerror(errno));
} else {
mVideoWd = -1;
ALOGI("Video device scanning disabled");
}
struct epoll_event eventItem = {};
eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = mINotifyFd;
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
// 创建并初始化用于线程唤醒的两个pipe,mWakeReadPipeFd,mWakeWritePipeFd;
int wakeFds[2];
result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
errno);
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
来看下初始化InputReader的流程new InputReader(std::make_unique(), policy, listener);
frameworks/native/services/inputflinger/reader/InputReader.cpp
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
: mContext(this), // 注意此处不是赋值,是调用了mContext的构造方法;
mEventHub(eventHub),//赋值,将EventHub跟InputReader进行关联!
mPolicy(policy), // 赋值!NativeInputManager;
mGlobalMetaState(0),
mGeneration(1),
mNextInputDeviceId(END_RESERVED_ID),
mDisableVirtualKeysTimeout(LLONG_MIN),
mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
// 通过InputManagerService读取系统res配置信息,存储到InputReader的mConfig中,如excludedDevice,portAssociations
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
5.1.5.2 IMS_start方法解析
IMS的初始化流程中,IMS构造方法和nativeInit方法执行完成后,初始化了IMS、NativeInputManager、InputManager、InputDispatcher、InputClassifier、InputReader、EventHub等对象;
来看下IMS的start方法的作用:
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void start() {
Slog.i(TAG, "Starting input manager");
// 通知native层开始工作,估计跟reader和dispatcher线程启动相关;
nativeStart(mPtr);
// Add ourself to the Watchdog monitors.
Watchdog.getInstance().addMonitor(this);
// 注册一些数据的设置变化监听;
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
registerAccessibilityLargePointerSettingObserver();
registerLongPressTimeoutObserver();
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");
}
nativeStart方法:
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// 调用InputManager的start方法;
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
inline sp<InputManager> getInputManager() const { return mInputManager; }
来看下im->getInputManager()->start()方法:
frameworks/native/services/inputflinger/InputManager.cpp
status_t InputManager::start() {
// 调用InputDispatcher的start方法方法;
status_t result = mDispatcher->start();
if (result) {
ALOGE("Could not start InputDispatcher thread due to error %d.", result);
return result;
}
// 调用InputReader的start方法;
result = mReader->start();
if (result) {
ALOGE("Could not start InputReader due to error %d.", result);
mDispatcher->stop();
return result;
}
return OK;
}
IMS的start方法,调用到InputManager的start方法,然后通知mDispatcher和mReader进行start,调用到了InputDispatcher和InputReader的start方法;
猜测start方法会让mDispatcher和mReader开始工作,进行输入事件的读取和传递工作;
先来看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;
}
上面的make_unique,会创建线程并调用dispatchOnce方法,来看下代码:
// InputThread的定义:
frameworks/native/services/inputflinger/include/InputThread.h
class InputThread {
public:
explicit InputThread(std::string name, std::function<void()> loop,
std::function<void()> wake = nullptr);
virtual ~InputThread();
bool isCallingThread();
private:
std::string mName;
std::function<void()> mThreadWake;
sp<Thread> mThread;
};
// InputThread和InputThreadImpl的实现:
frameworks/native/services/inputflinger/InputThread.cpp // InputThread线程
// 继承自Thread对象
// Implementation of Thread from libutils.
class InputThreadImpl : public Thread {
public:
explicit InputThreadImpl(std::function<void()> loop)
: Thread(/* canCallJava */ true), mThreadLoop(loop) {}
~InputThreadImpl() {}
private:
std::function<void()> mThreadLoop;
bool threadLoop() override { // 猜测线程启动后执行threadLoop()方法,然后调用到mThreadLoop(),也就是dispatchOnce方法。
mThreadLoop();
return true;
}
};
} // namespace
// make_unique创建InputThread对象,会触发此处的构造方法;
InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
: mName(name), mThreadWake(wake) {// 赋值,mThreadWake指向了mLooper->wake();
// 创建线程,传入InputDispatcher的dispatchOnce方法;mThreadLoop就指向了此方法;
mThread = new InputThreadImpl(loop);
//开始线程run,会持续调用InputThreadImpl的threadLoop方法,直到返回false或调用exit;
mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
}
Thread.h对run和threadLoop的解释:
system/core/libutils/include/utils/Thread.h
class Thread : virtual public RefBase
{
public:
// Create a Thread object, but doesn't create or start the associated
// thread. See the run() method.
explicit Thread(bool canCallJava = true);
virtual ~Thread();
// 用threadLoop执行线程!
// Start the thread in threadLoop() which needs to be implemented.
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t run( const char* name,
int32_t priority = PRIORITY_DEFAULT,
size_t stack = 0);
// Ask this object's thread to exit. This function is asynchronous, when the
// function returns the thread might still be running. Of course, this
// function can be called from a different thread.
virtual void requestExit();
......
private:
// 派生类/子类必须重写threadLoop方法,当threadLoop返回true时,会重新调用threadLoop;
// threadLoop此循环直到requestExit才停止!
// Derived class must implement threadLoop(). The thread starts its life
// here. There are two ways of using the Thread object:
// 1) loop: if threadLoop() returns true, it will be called again if
// requestExit() wasn't called.
// 2) once: if threadLoop() returns false, the thread will exit upon return.
virtual bool threadLoop() = 0;
private:
Thread& operator=(const Thread&);
static int _threadLoop(void* user);
const bool mCanCallJava;
...
};
} // namespace android
总结:
至此InputDispatcher的start方法初始化完成,创建了一个线程,并会持续调用InputDispatcher的dispatchOnce方法;
dispatcherOnce方法是对Input事件的传递流程,会在4.4章节“IMS读取和传递INput事件流程”中进行解读;
来看下InputReader的start方法,也是一样的流程!
frameworks/native/services/inputflinger/reader/InputReader.cpp
status_t InputReader::start() {
if (mThread) {
return ALREADY_EXISTS;
}
// 可以看到InputReader::start()方法,也是创建了一个线程,持续调用loopOnce方法;
// loopOnce方法会尝试从EventHub中读取Input事件;
mThread = std::make_unique<InputThread>(
"InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); }); // 这里会执行loopOnce方法,来跟进下;
return OK;
}
frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
......
// 读取各种事件,包括Input事件,放入mEventBuffer中;
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); // 从EventHub读取输入事件;
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
// 若读取到了输入事件,则处理输入事件(readerPolicy或传给InputDispatcher);
}
if (count) {
processEventsLocked(mEventBuffer, count);
......
} // 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(); // 通知listener输入事件到来
}
InputReader-start方法总结:
InputReader的start方法,也是创建了一个线程,并循环调用InputReader的loopOnce方法;
loopOnce方法会从EventHub中读取事件,并进行传递;
loopOnce方法,会在4.4章节“IMS读取和传递INput事件流程”中进行解读;IMS_start方法总结:
InputManagerService的start方法,会调用到native层InputManager的start方法,然后分别创建InputDispatcher和InputReader的线程;
在这两个线程中,持续调用dispatcheOnce和loopOnce方法,进行Input事件的读取和传递流程;
4.2 App初始化输入框架的流程
4.2.1 流程简介
在Activity执行onResume的流程中,会创建一对InputChannel对象,两个InputChannel分别注册到IMS和APP进程中;
IMS读取到的输入数据,通过InputChannel传递给APP进程;
4.2.2 相关模块数据流图
以下图示,体现了输入事件的数据,在App进程中的数据流向。
4.2.3 类图
此流程相关类图,包含app和system_server进程相关类;
可以了解到App初始化Input功能的对象关联关系和方法调用;
4.2.4 时序图
4.2.4.1 App初始化Input功能流程
4.2.4.2 WMS注册InputChannel流程
此处流程,是App初始化Input功能的一部分;
通过WMS创建一对InputChannel,WMS将其中一个InputChannel注册到InputManagerService作为数据发送端,将另一个InputChannel传递给App,作为输入事件的接收端。
4.2.4.3 openInputChannelPair流程
4.2.5 代码解读
4.2.5.1 创建InputChannel流程:
输入管道的创建起源,可以从AMS通知Activity进行resume开始:
frameworks/base/core/java/android/app/servertransaction/ResumeActivityItem.java
@Override
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
// resume某个Activiy
client.handleResumeActivity(token, true /* finalStateRequest */, mIsForward,
"RESUME_ACTIVITY");
Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
}
frameworks/base/core/java/android/app/ActivityThread.java
@Override
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
......
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
...
r.activity.mVisibleFromServer = true;
mNumVisibleActivities++;
if (r.activity.mVisibleFromClient) {
// makeVisible使activity显示到界面上,过程中会创建InputChannel对象.
// makeVisible会调用WMS的addView方法;
r.activity.makeVisible();
}
}
...
}
makeVisible->addView流程:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/java/android/app/Activity.java
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
// 注意此处mDecor传入了WindowManagerGlobal,是ViewRootImpl中的mView对象;
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
frameworks/base/core/java/android/view/WindowManagerImpl.java
@Override
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
// WindowManagerGlobal的addView流程;
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
// 创建ViewRootImpl对象
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
// do this last because it fires off messages to start doing things
try {
// 调用ViewRootImpl 的 setView方法,会触发new InputChannel流程
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
ViewRootImpl-setView触发的创建和注册InputChannel流程:
frameworks/base/core/java/android/view/ViewRootImpl.java
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
......
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
InputChannel inputChannel = null;
// 创建InputChannel
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
// 初始化一个空的本地InputChannel,暂时不能用于接收数据;
inputChannel = new InputChannel();
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
// 调用wms进程中,WindowSession的addToDisplayAsUser方法;
// 此处是一次binder跨进程调用;
// inputChannel是一个inout类型参数,在binder调用后,会赋予此channel读取输入数据的能力。;
// wms进程中会创建一对InputChannel,其中一个会反向赋值给此inputChannel
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
adjustLayoutParamsForCompatibility(mWindowAttributes);
res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
setFrame(mTmpFrame);
} catch (RemoteException e) {
......
} finally {
if (restore) {
attrs.restore();
}
}
......
if (inputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 将inputChannel和WindowInputEventReceiver进行关联;
// 猜测InputChannel读取到的Input数据,
// 会触发WindowInputEventReceiver 的onInputEvent(InputEvent event)回调!
mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper());
}
....
}
注意此处有三个关键行为: inputChannel = new InputChannel();
mWindowSession.addToDisplayAsUser…; mInputEventReceiver = new
WindowInputEventReceiver(inputChannel, Looper.myLooper());
下面会跟进这三个关键行为,来分析InputChannel的创建和注册到IMS的流程:
InputChannel构造方法:
frameworks/base/core/java/android/view/InputChannel.java
public final class InputChannel implements Parcelable {
...
@SuppressWarnings("unused")
@UnsupportedAppUsage
private long mPtr; // used by native code
private static native InputChannel[] nativeOpenInputChannelPair(String name);
...
private native void nativeTransferTo(InputChannel other);
...
private native String nativeGetName();
/**
* Creates an uninitialized input channel.注意此处的注释,创建的是未初始化的对象。
* It can be initialized by reading from a Parcel or by transferring the state of
* another input channel into this one.
*/
@UnsupportedAppUsage
public InputChannel() {// 啥也没干,注意此时mPtr 为 0!
}
}
来看下非常重要的mWindowSession.addToDisplayAsUser流程;
先来看下mWindowSession是什么:
frameworks/base/core/java/android/view/WindowManagerGlobal.java
@UnsupportedAppUsage
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
// Emulate the legacy behavior. The global instance of InputMethodManager
// was instantiated here.
// TODO(b/116157766): Remove this hack after cleaning up @UnsupportedAppUsage
InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
IWindowManager windowManager = getWindowManagerService();
// mWindowSession是wms返回的一个session对象;是一个binder对象;
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
});
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
}
}
// wms进程openSession方法:
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
@Override
public IWindowSession openSession(IWindowSessionCallback callback) {
return new Session(this, callback);
}
// Session的构造方法
frameworks/base/services/core/java/com/android/server/wm/Session.java
public Session(WindowManagerService service, IWindowSessionCallback callback) {
mService = service; // wms
mCallback = callback; // app端的new IWindowSessionCallback.Stub()
mUid = Binder.getCallingUid(); // app 进程相关uid
mPid = Binder.getCallingPid(); // app 进程相关pid
mLastReportedAnimatorScale = service.getCurrentAnimatorScale();
mCanAddInternalSystemWindow = service.mContext.checkCallingOrSelfPermission(
INTERNAL_SYSTEM_WINDOW) == PERMISSION_GRANTED;
mCanHideNonSystemOverlayWindows = service.mContext.checkCallingOrSelfPermission(
HIDE_NON_SYSTEM_OVERLAY_WINDOWS) == PERMISSION_GRANTED;
mCanAcquireSleepToken = service.mContext.checkCallingOrSelfPermission(DEVICE_POWER)
== PERMISSION_GRANTED;
mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications;
mDragDropController = mService.mDragDropController;
StringBuilder sb = new StringBuilder();
sb.append("Session{");
sb.append(Integer.toHexString(System.identityHashCode(this))); // 当前对象hash
sb.append(" ");
sb.append(mPid);
if (mUid < Process.FIRST_APPLICATION_UID) {
sb.append(":");
sb.append(mUid);
} else {
sb.append(":u");
sb.append(UserHandle.getUserId(mUid));
sb.append('a');
sb.append(UserHandle.getAppId(mUid));
}
sb.append("}");
// mStringName带有this的hashCode,是每个activity/window唯一标识;
mStringName = sb.toString();
try {
mCallback.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) {
// The caller has died, so we can just forget about this.
// Hmmm, should we call killSessionLocked()??
}
}
看到mWindowSession是WMS里new Session的binder类型的对象;
来继续跟进mWindowSession.addToDisplayAsUser流程:
frameworks/base/services/core/java/com/android/server/wm/Session.java
// 注意入参,app侧创建的inputChannel对象,在这里是InputChannel outInputChannel;
// 此对象在aidl中声明了inout方向,说明对于此数据的修改,可以影响到app侧;
@Override
public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, int userId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame,
outContentInsets, outStableInsets, outDisplayCutout, outInputChannel,
outInsetsState, outActiveControls, userId);
}
// win.openInputChannel,创建可以互相通信的InputChannel对;
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
int requestUserId) {
...
ActivityRecord activity = null;
final boolean hasParent = parentWindow != null;
// Use existing parent window token for child windows since they go in the same token
// as there parent window so we can apply the same policy on them.
WindowToken token = displayContent.getWindowToken(
hasParent ? parentWindow.mAttrs.token : attrs.token);
...
if (token == null) {
if (!unprivilegedAppCanCreateTokenWith(parentWindow, callingUid, type,
rootType, attrs.token, attrs.packageName)) {
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
if (hasParent) {
// Use existing parent window token for child windows.
token = parentWindow.mToken;
} else {
final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
token = new WindowToken(this, binder, type, false, displayContent,
session.mCanAddInternalSystemWindow, isRoundedCornerOverlay);
}
} else if (rootType >= FIRST_APPLICATION_WINDOW
...
} else if (token.asActivityRecord() != null) {
ProtoLog.w(WM_ERROR, "Non-null activity for system window of rootType=%d",
rootType);
// It is not valid to use an app token with other system types; we will
// instead make a new token for it (as if null had been passed in for the token).
attrs.token = null;
token = new WindowToken(this, client.asBinder(), type, false, displayContent,
session.mCanAddInternalSystemWindow);
}
// 创建WindowState对象;
final WindowState win = new WindowState(this, session, client, token, parentWindow,
appOp[0], seq, attrs, viewVisibility, session.mUid, userId,
session.mCanAddInternalSystemWindow);
......
// 通过WindowState对象尝试openInputChannel,创建通信通道;
final boolean openInputChannels = (outInputChannel != null
&& (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
if (openInputChannels) {
win.openInputChannel(outInputChannel);
}
......
win.attach();
mWindowMap.put(client.asBinder(), win);
win.initAppOpsState();
...
win.mToken.addWindow(win);
displayPolicy.addWindowLw(win, attrs);
...
outInsetsState.set(win.getInsetsState(), win.isClientLocal());
if (mInTouchMode) {
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
}
if (win.mActivityRecord == null || win.mActivityRecord.isClientVisible()) {
res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
}
displayContent.getInputMonitor().setUpdateInputWindowsNeededLw();
boolean focusChanged = false;
if (win.canReceiveKeys()) {// 可以接收按键值
// 更新WindowFocuse?
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
if (focusChanged) {
imMayMove = false;
}
}
...
// 更新InputFocus?
if (focusChanged) {
displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
false /*updateInputWindows*/);
}
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
...
}
以上代码,看到以下关键流程: WindowState-openInputChannel(outInputChannel);
focusChanged =
updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /updateInputWindows/); displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
false /updateInputWindows/); displayContent.getInputMonitor().updateInputWindowsLw(false
/force/);
先来分析WindowState-openInputChannel(outInputChannel)方法:
frameworks/base/services/core/java/com/android/server/wm/WindowState.java
void openInputChannel(InputChannel outInputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
String name = getName();
// 通过InputChannel的静态方法,创建一对InputChannel,注意入参为name;
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);///重要!!!
mInputChannel = inputChannels[0];
mClientChannel = inputChannels[1];
// 将inputChannels[0]注册到IMS,作为服务端;
mWmService.mInputManager.registerInputChannel(mInputChannel);
mInputWindowHandle.token = mInputChannel.getToken();
if (outInputChannel != null) {
// 将inputChannels[1]复制到入参outInputChannel中,传到app中。
// app就可以从outInputChannel中读取Input数据;
mClientChannel.transferTo(outInputChannel);
mClientChannel.dispose();
mClientChannel = null;
} else {
// If the window died visible, we setup a dummy input channel, so that taps
// can still detected by input monitor channel, and we can relaunch the app.
// Create dummy event receiver that simply reports all events as handled.
mDeadWindowEventReceiver = new DeadWindowEventReceiver(mClientChannel);
}
mWmService.mInputToWindowMap.put(mInputWindowHandle.token, this);
}
InputChannel.openInputChannelPair创建了一对儿可以相互通信的socket,具备一一对应的关联关系,并持有一个共同的BBinder对象。
openInputChannelPair流程在4.2.5.4章节有详细介绍,这里不再赘述,可以理解为创建了一对InputChannel(socket通信),这一对InputChannel可以相互通信。
来看下mClientChannel.transferTo(outInputChannel)方法,是如何将socket转移给outInputChannel的:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/java/android/view/InputChannel.java
public void transferTo(InputChannel outParameter) {
if (outParameter == null) {
throw new IllegalArgumentException("outParameter must not be null");
}
nativeTransferTo(outParameter);
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputChannel.cpp
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
jobject otherObj) {
if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != nullptr) {
jniThrowException(env, "java/lang/IllegalStateException",
"Other object already has a native input channel.");
return;
}
// 获取NativeInputChannel指针对象;
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, obj);
// 将此NativeInputChannel指针对象赋予App端的InputChannel-mPtr中;
android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
// 释放System_server层的NativeInputChannel指向的指针,置为null; android_view_InputChannel_setNativeInputChannel(env, obj, nullptr);
}
// 获取NativeInputChannel指针
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
jobject inputChannelObj) {
// 对象的地址;
jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
return reinterpret_cast<NativeInputChannel*>(longPtr);
}
设置java层InputChannel的mPtr的数值,指向native指针。
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj, NativeInputChannel* nativeInputChannel) {
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast<jlong>(nativeInputChannel));
}
至此,经过binder调用进system_server进程-mWindowSession.addToDisplayAsUse,回到App进程后,App端的InputChannel的mPtr已经被赋值;
4.2.5.2 InputChannel注册到IMS的流程
来看下WindowState-openInputChannel方法里的mInputManager.registerInputChannel(mInputChannel)流程;
server端的socket添加到了IMS中;我们猜测IMS进程获取输入事件后,通过这个server端socket对象,同App进程中的client端对象(InputChannel)进行通信;
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void registerInputChannel(InputChannel inputChannel) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
// 注意入参mPtr,以及inputChannel;
// mPtr是IMS初始化阶段,创建的NativeInputManager对象的指针;
nativeRegisterInputChannel(mPtr, inputChannel);
}
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass /* clazz */,
jlong ptr, jobject inputChannelObj) {
// 将mPtr转换为NativeInputManager对象;
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
// 将jobject对象转变为native层的InputChannel对象;
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == nullptr) {
throwInputChannelNotInitialized(env);
return;
}
// InputManager.cpp的registerInputChannel方法;
status_t status = im->registerInputChannel(env, inputChannel);
if (status) {
std::string message;
message += StringPrintf("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.c_str());
return;
}
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
我们看到以上流程,是将InputChannel对象,注册到IMS的native层中; 以上代码有两个关键函数:
sp inputChannel =
android_view_InputChannel_getInputChannel(env,
inputChannelObj); status_t status = im->registerInputChannel(env, inputChannel);
android_view_InputChannel_getInputChannel方法:
frameworks/base/core/jni/android_view_InputChannel.cpp
sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {
// 将inputChannelObj 转变为NativeInputChannel对象;
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);
// 从NativeInputChannel获取InputChannel并返回
nativeInputChannel != nullptr ? nativeInputChannel->getInputChannel() : nullptr;
}
// android_view_InputChannel_getNativeInputChannel 方法:
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
jobject inputChannelObj) {
// 获取NativeInputChannel的内存指针:
jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
return reinterpret_cast<NativeInputChannel*>(longPtr);
}
// NativeInputChannel的声明;
// InputChannel中包含new InputChannel(name, std::move(fd), token);
frameworks/base/core/jni/android_view_InputChannel.cpp
class NativeInputChannel {
public:
explicit NativeInputChannel(const sp<InputChannel>& inputChannel);
~NativeInputChannel();
inline sp<InputChannel> getInputChannel() { return mInputChannel; }
void setDisposeCallback(InputChannelObjDisposeCallback callback, void* data);
void invokeAndRemoveDisposeCallback(JNIEnv* env, jobject obj);
private:
sp<InputChannel> mInputChannel;
InputChannelObjDisposeCallback mDisposeCallback;
void* mDisposeData;
};
im->registerInputChannel(env, inputChannel)流程:
frameworks/native/services/inputflinger/InputManager.cpp
void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid != AID_SHELL && uid != AID_ROOT) {
ALOGE("Invalid attempt to register input channel over IPC"
"from non shell/root entity (PID: %d)", ipc->getCallingPid());
return;
}
// 调用InputDispatcher的注册方法,将InputChannel注册到InputDispatcher中;
mDispatcher->registerInputChannel(channel);
}
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATION
ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif
{ // acquire lock
std::scoped_lock _l(mLock);
sp<Connection> existingConnection = getConnectionLocked(inputChannel->getConnectionToken());
if (existingConnection != nullptr) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
}
// 将inputChannel封装在了Connection对象中;
sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator); // InputChannel封装到了Connection中
// socket的fd;
int fd = inputChannel->getFd();
// 将封装了InputChannel的Connection,保存在mConnectionsByFd中;
mConnectionsByFd[fd] = connection; // fd和connection的对应关系
// token和inputChannel的对应关系,保存在了mInputChannelsByToken中;
mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel; // token 和 inputChannel的对应关系;
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return OK;
}
// handleReceiveCallback方法,此方法在其他章节进行分析,属于事件传递流程的一部分:
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
...
}
//mConnectionsByFd和mInputChannelsByToken的数据声明:
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.h
// All registered connections mapped by channel file descriptor.
std::unordered_map<int, sp<Connection>> mConnectionsByFd GUARDED_BY(mLock);
std::unordered_map<sp<IBinder>, sp<InputChannel>, IBinderHash> mInputChannelsByToken
GUARDED_BY(mLock);
至此WindowState-openInputChannel(outInputChannel)方法结束;
以上流程,把一个InputChannel注册到了system_server进程,保存在了IMS-InputDispatcher对象中的两个map数据结构中mConnectionsByFd、mInputChannelsByToken。
我们猜测IMS收到InputEvent输入事件后,会将数据传入InputChannel中;另一个InputChannel会传递给app侧,作为通信通道的另一端,来接收输入事件;
4.2.5.3 Window和焦点display变更流程
WindowManagerService-addWindow中,WindowState-openInputChannel(outInputChannel)创建并注册InputChannel到IMS中;
之后调用了以下方法,来更新焦点屏幕和焦点window:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
public int addWindow(Session session, IWindow client, int seq,
LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame,
Rect outContentInsets, Rect outStableInsets,
DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel,
InsetsState outInsetsState, InsetsSourceControl[] outActiveControls,
int requestUserId) {
......
创建和注册InputChannel;
......
//1-1流程
displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
false /*updateInputWindows*/);
//1-2流程
focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,
false /*updateInputWindows*/);
//1-3流程
displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/);
...
}
1-1,来看下第二个关键方法调用,即WMS-addView-addWindow中的以下关键方法调用:
displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus, false /updateInputWindows/);
先来看displayContent和getInputMonitor都分别指向什么类型的对象,才能知道displayContent.mCurrentFocus是什么类型.
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
final DisplayContent displayContent = win.getDisplayContent();
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowState.java
@Override
DisplayContent getDisplayContent() {
return mToken.getDisplayContent();
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
token = new WindowToken(this, client.asBinder(), type, false, displayContent, session.mCanAddInternalSystemWindow);
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java-WindowToken.class-getDisplayContent()方法:
final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private DisplayContent getDisplayContentOrCreate(int displayId, IBinder token) {
if (token != null) {
final WindowToken wToken = mRoot.getWindowToken(token);
if (wToken != null) {
return wToken.getDisplayContent();
}
}
// 创建或获取DisplayContent.
return mRoot.getDisplayContentOrCreate(displayId);
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
mRoot = new RootWindowContainer(this);
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
/**
* Get an existing instance of {@link DisplayContent} or create new if there is a
* corresponding record in display manager.
*/
// TODO: Look into consolidating with getDisplayContent()
@Nullable DisplayContent getDisplayContentOrCreate(int displayId) {
DisplayContent displayContent = getDisplayContent(displayId);
if (displayContent != null) {
return displayContent;
}
if (mDisplayManager == null) {
// The system isn't fully initialized yet.
return null;
}
// 根据displayId,获取display信息
final Display display = mDisplayManager.getDisplay(displayId);
if (display == null) {
// The display is not registered in DisplayManager.
return null;
}
// 根据displayId,创建新的displayContent。
// The display hasn't been added to ActivityManager yet, create a new record now.
displayContent = new DisplayContent(display, this);
addChild(displayContent, POSITION_BOTTOM);
return displayContent;
}
可见displayContent就是跟displayId一一对应的DisplayContent对象。
DisplayContent.getInputMonitor返回的是什么对象呢?
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
mInputMonitor = new InputMonitor(mWmService, this);
InputMonitor是跟WMS和DisplayContent相关的一个对象;
setInputFocusLw的入参是如下类型的WindowState对象,代表了一个交互的window,入参还包含一个false变量;
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/DisplayContent.java
/**
* Window that is currently interacting with the user. This window is responsible for receiving
* key events and pointer events from the user.
*/
WindowState mCurrentFocus = null;
// Current window with input focus for keys and other non-touch events. May be null.
private WindowState mInputFocus;
来分析1-1的函数调用:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
/**
* Called when the current input focus changes.
* Layer assignment is assumed to be complete by the time this is called.
* 当此方法调用后,层级分配就会完成。
*/
public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
ProtoLog.d(WM_DEBUG_FOCUS_LIGHT, "Input focus has changed to %s", newWindow);
if (newWindow != mInputFocus) {
if (newWindow != null && newWindow.canReceiveKeys()) {
// Displaying a window implicitly causes dispatching to be unpaused.
// This is to protect against bugs if someone pauses dispatching but
// forgets to resume.
newWindow.mToken.paused = false;
}
// 更新当前输入焦点窗口,注意当前对象是跟某个屏幕对应的DisplayContent-InputMonitor对象;
mInputFocus = newWindow;
// 关键方法调用1-1-1;
setUpdateInputWindowsNeededLw();
if (updateInputWindows) { // 此处为false,不执行此处
updateInputWindowsLw(false /*force*/);
}
}
}
1-1-1,setUpdateInputWindowsNeededLw():
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
void setUpdateInputWindowsNeededLw() {
mUpdateInputWindowsNeeded = true;
}
setUpdateInputWindowsNeededLw这个只是设置了一个变量mUpdateInputWindowsNeeded 为true,没有调用其他方法;
总结:
displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
false /updateInputWindows/);
以上方法的作用,为某个屏幕DisplayContent赋值了mInputFocus(WindowState类型),并且将mUpdateInputWindowsNeeded赋值为了true;
1-2,来分析WMS-updateFocusedWindowLocked方法.
updateFocusedWindowLocked方法会是更新焦点Window吗?
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
...
boolean changed = mRoot.updateFocusedWindowLocked(mode, updateInputWindows);
...
return changed;
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
mTopFocusedAppByProcess.clear();
boolean changed = false;
int topFocusedDisplayId = INVALID_DISPLAY;
for (int i = mChildren.size() - 1; i >= 0; --i) {
final DisplayContent dc = mChildren.get(i);// dc是某个屏幕的代理?
// 让每个屏幕updateFocusedWindowLocked;
changed |= dc.updateFocusedWindowLocked(mode, updateInputWindows, topFocusedDisplayId);
final WindowState newFocus = dc.mCurrentFocus;
if (newFocus != null) {
final int pidOfNewFocus = newFocus.mSession.mPid;
if (mTopFocusedAppByProcess.get(pidOfNewFocus) == null) {
mTopFocusedAppByProcess.put(pidOfNewFocus, newFocus.mActivityRecord);
}
if (topFocusedDisplayId == INVALID_DISPLAY) {
topFocusedDisplayId = dc.getDisplayId();
}
} else if (topFocusedDisplayId == INVALID_DISPLAY && dc.mFocusedApp != null) {
// The top-most display that has a focused app should still be the top focused
// display even when the app window is not ready yet (process not attached or
// window not added yet).
topFocusedDisplayId = dc.getDisplayId();
}
}
// 遍历确认焦点屏幕topFocusedDisplayId
if (topFocusedDisplayId == INVALID_DISPLAY) {
topFocusedDisplayId = DEFAULT_DISPLAY;
}
if (mTopFocusedDisplayId != topFocusedDisplayId) {
// 更新 mTopFocusedDisplayId .
mTopFocusedDisplayId = topFocusedDisplayId;
// 更新IMS-InputDispatcher中的mFocusedDisplayId;
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
// 更新wms-PhoneWindowManager中的mTopFocusedDisplayId;
mWmService.mPolicy.setTopFocusedDisplay(topFocusedDisplayId);
ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "New topFocusedDisplayId=%d",
topFocusedDisplayId);
}
return changed;
}
此处updateFocusedWindowLocked会去更新IMS和WMS里的mFocusedDisplayId和mTopFocusedDisplayId;
来看下setFocusedDisplay的流程;
此处会更新IMS-InputDispatcher中的mFocusedDisplayId:
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public void setFocusedDisplay(int displayId) {
// jni调用
nativeSetFocusedDisplay(mPtr, displayId);
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeSetFocusedDisplay(JNIEnv* env, jclass /* clazz /,
jlong ptr, jint displayId) {
NativeInputManager im = reinterpret_cast<NativeInputManager*>(ptr);
im->setFocusedDisplay(env, displayId);
}
// 通知InputDispatcher输入时间分发者更新焦点屏幕;
void NativeInputManager::setFocusedDisplay(JNIEnv* env, int32_t displayId) {
mInputManager->getDispatcher()->setFocusedDisplay(displayId);
}
// 设置焦点屏幕,用于赋值给未指定屏幕id的输入事件的displayId;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
/**
* Sets the focused display, which is responsible for receiving focus-dispatched input events where
* the display not specified.
*
* We track any unreleased events for each window. If a window loses the ability to receive the
* released event, we will send a cancel event to it. So when the focused display is changed, we
* cancel all the unreleased display-unspecified events for the focused window on the old focused
* display. The display-specified events won't be affected.
* 屏幕焦点变更时,对旧的焦点屏幕,取消所有未指定屏幕ID的事件,指定了ID的事件不受影响;
*/
void InputDispatcher::setFocusedDisplay(int32_t displayId) {
if (DEBUG_FOCUS) {
ALOGD("setFocusedDisplay displayId=%" PRId32, displayId);
}
{ // acquire lock
std::scoped_lock _l(mLock);
if (mFocusedDisplayId != displayId) {
sp<InputWindowHandle> oldFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
// 对旧的windowHandle发送取消的消息;
if (oldFocusedWindowHandle != nullptr) {
sp<InputChannel> inputChannel =
getInputChannelLocked(oldFocusedWindowHandle->getToken());
if (inputChannel != nullptr) {
CancelationOptions
options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
"The display which contains this window no longer has focus.");
options.displayId = ADISPLAY_ID_NONE;
synthesizeCancelationEventsForInputChannelLocked(inputChannel, options);
}
}
// 更新焦点屏幕Id-mFocusedDisplayId;
mFocusedDisplayId = displayId;
// Sanity check
sp<InputWindowHandle> newFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
// 通知焦点窗口变更;
onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
// 此处判断只打印了一些log?
if (newFocusedWindowHandle == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
if (!mFocusedWindowHandlesByDisplay.empty()) {
ALOGE("But another display has a focused window:");
for (auto& it : mFocusedWindowHandlesByDisplay) {
const int32_t displayId = it.first;
const sp<InputWindowHandle>& windowHandle = it.second;
ALOGE("Display #%" PRId32 " has focused window: '%s'\n", displayId,
windowHandle->getName().c_str());
}
}
}
}
if (DEBUG_FOCUS) {
logDispatchStateLocked();
}
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
// 通知焦点窗口变更;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
const sp<InputWindowHandle>& newFocus) {
sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doNotifyFocusChangedLockedInterruptible);
commandEntry->oldToken = oldToken;
commandEntry->newToken = newToken;
postCommandLocked(std::move(commandEntry));
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::doNotifyFocusChangedLockedInterruptible(CommandEntry* commandEntry) {
sp<IBinder> oldToken = commandEntry->oldToken;
sp<IBinder> newToken = commandEntry->newToken;
mLock.unlock();
// 调用NativeInputManagerService的notifyFocusChanged,通知到上层。
mPolicy->notifyFocusChanged(oldToken, newToken);
mLock.lock();
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
void NativeInputManager::notifyFocusChanged(const sp<IBinder>& oldToken,
const sp<IBinder>& newToken) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("notifyFocusChanged");
#endif
ATRACE_CALL();
JNIEnv* env = jniEnv();
ScopedLocalFrame localFrame(env);
jobject oldTokenObj = javaObjectForIBinder(env, oldToken);
jobject newTokenObj = javaObjectForIBinder(env, newToken);
// 调用上层IMS的notifyFocusChanged方法。
env->CallVoidMethod(mServiceObj, gServiceClassInfo.notifyFocusChanged,
oldTokenObj, newTokenObj);
checkAndClearExceptionFromCallback(env, "notifyFocusChanged");
}
// 此处未看出跟IMS的关系,暂不跟进,暂时忽略此处的作用;
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
// Native callback
private void notifyFocusChanged(IBinder oldToken, IBinder newToken) {
final boolean requestConfigurationRefresh =
mWindowManagerCallbacks.notifyFocusChanged(oldToken, newToken);
if (requestConfigurationRefresh) {
nativeSetPointerCapture(mPtr, false);
}
}
总结:
mWmService.mInputManager.setFocusedDisplay(topFocusedDisplayId);更新了InputDispatcher中的焦点屏幕;并通知了Java层window焦点变更的消息;
#来分析上面的1-3方法:
displayContent.getInputMonitor().updateInputWindowsLw(false /force/);
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
/* Updates the cached window information provided to the input dispatcher. */
void updateInputWindowsLw(boolean force) {
if (!force && !mUpdateInputWindowsNeeded) {
return;// mUpdateInputWindowsNeeded为true,则不会走到此处的return逻辑;
}
scheduleUpdateInputWindows();
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
private void scheduleUpdateInputWindows() {
if (mDisplayRemoved) {
return;
}
if (!mUpdateInputWindowsPending) { // 初始为false
mUpdateInputWindowsPending = true;
mHandler.post(mUpdateInputWindows);
}
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
private final UpdateInputWindows mUpdateInputWindows = new UpdateInputWindows();
通过handler执行mUpdateInputWindows 此runable的run方法;
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
private class UpdateInputWindows implements Runnable {
@Override
public void run() {
synchronized (mService.mGlobalLock) {
mUpdateInputWindowsPending = false;
mUpdateInputWindowsNeeded = false;
if (mDisplayRemoved) {
return;
}
// Populate the input window list with information about all of the windows that
// could potentially receive input.
// As an optimization, we could try to prune the list of windows but this turns
// out to be difficult because only the native code knows for sure which window
// currently has touch focus.
// If there's a drag in flight, provide a pseudo-window to catch drag input
final boolean inDrag = mService.mDragDropController.dragDropActiveLocked();
// Add all windows on the default display.
mUpdateInputForAllWindowsConsumer.updateInputWindows(inDrag);
}
}
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
private void updateInputWindows(boolean inDrag) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateInputWindows");
mNavInputConsumer = getInputConsumer(INPUT_CONSUMER_NAVIGATION);
mPipInputConsumer = getInputConsumer(INPUT_CONSUMER_PIP);
mWallpaperInputConsumer = getInputConsumer(INPUT_CONSUMER_WALLPAPER);
mRecentsAnimationInputConsumer = getInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
mAddNavInputConsumerHandle = mNavInputConsumer != null;
mAddPipInputConsumerHandle = mPipInputConsumer != null;
mAddWallpaperInputConsumerHandle = mWallpaperInputConsumer != null;
mAddRecentsAnimationInputConsumerHandle = mRecentsAnimationInputConsumer != null;
mTmpRect.setEmpty();
mDisableWallpaperTouchEvents = false;
mInDrag = inDrag;
mWallpaperController = mDisplayContent.mWallpaperController;
resetInputConsumers(mInputTransaction);
// 重新计算层级?
mDisplayContent.forAllWindows(this,
true /* traverseTopToBottom */);
if (!mUpdateInputWindowsImmediately) {
mDisplayContent.getPendingTransaction().merge(mInputTransaction);
mDisplayContent.scheduleAnimation();
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/java/android/view/WindowManager.java
/** @hide */
String INPUT_CONSUMER_PIP = "pip_input_consumer";
/** @hide */
String INPUT_CONSUMER_NAVIGATION = "nav_input_consumer";
/** @hide */
String INPUT_CONSUMER_WALLPAPER = "wallpaper_input_consumer";
/** @hide */
String INPUT_CONSUMER_RECENTS_ANIMATION = "recents_animation_input_consumer";
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
void forAllWindows(Consumer<WindowState> callback, boolean traverseTopToBottom) {
ForAllWindowsConsumerWrapper wrapper = obtainConsumerWrapper(callback);
forAllWindows(wrapper, traverseTopToBottom); // wrapper, true
wrapper.release();
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowContainer.java
/**
* For all windows at or below this container call the callback.
* @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and
* stops the search if {@link ToBooleanFunction#apply} returns true.
* @param traverseTopToBottom If true traverses the hierarchy from top-to-bottom in terms of
* z-order, else from bottom-to-top.
* @return True if the search ended before we reached the end of the hierarchy due to
* {@link ToBooleanFunction#apply} returning true.
*/
boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
if (traverseTopToBottom) {
for (int i = mChildren.size() - 1; i >= 0; --i) {
// 调用mChildren中的每个WindowState的forAllWindows方法,callback在InputMonitor中,traverseTopToBottom为true;
if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
return true;
}
}
} else {
final int count = mChildren.size();
for (int i = 0; i < count; i++) {
if (mChildren.get(i).forAllWindows(callback, traverseTopToBottom)) {
return true;
}
}
}
return false;
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowState.java
@Override
boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
if (mChildren.isEmpty()) {
// The window has no children so we just return it.
return applyInOrderWithImeWindows(callback, traverseTopToBottom);// 假设无子window;
}
if (traverseTopToBottom) {
return forAllWindowTopToBottom(callback);
} else {
return forAllWindowBottomToTop(callback);
}
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/WindowState.java
private boolean applyInOrderWithImeWindows(ToBooleanFunction<WindowState> callback,
boolean traverseTopToBottom) {
if (traverseTopToBottom) {
// 调用applyImeWindowsIfNeeded 和 callback.apply(this),调用applyImeWindowsIfNeeded跟IME相关,暂不关注。
if (applyImeWindowsIfNeeded(callback, traverseTopToBottom)
|| callback.apply(this)) {
return true;
}
} else {
if (callback.apply(this)
|| applyImeWindowsIfNeeded(callback, traverseTopToBottom)) {
return true;
}
}
return false;
}
来分析ForAllWindowsConsumerWrapper-callback.apply(this)方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/services/core/java/com/android/server/wm/InputMonitor.java
@Override
public void accept(WindowState w) {
final InputChannel inputChannel = w.mInputChannel; // windowState的InputChannel;
final InputWindowHandle inputWindowHandle = w.mInputWindowHandle; // windowState的mInputWindowHandle
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
final boolean shouldApplyRecentsInputConsumer = recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(w.mActivityRecord);
final int type = w.mAttrs.type;
final boolean isVisible = w.isVisibleLw();
if (inputChannel == null || inputWindowHandle == null || w.mRemoved
|| (w.cantReceiveTouchInput() && !shouldApplyRecentsInputConsumer)) {
......
// Skip this window because it cannot possibly receive input.
return;
}
final int flags = w.mAttrs.flags;
final int privateFlags = w.mAttrs.privateFlags;
final boolean hasFocus = w.isFocused();
......
// 为inputWindowHandle赋予各种属性,如name,flag,type,canReceivekeys,displayId,left/right/top/bottom,surface,scale等属性。
// 将InputMonitor的mFocusedInputWindowHandle指向此inputWindowHandle;
populateInputWindowHandle(
inputWindowHandle, w, flags, type, isVisible, hasFocus, hasWallpaper);
// 将KeyInterceptionInfo放入wms的一个map中;
// register key interception info
mService.mKeyInterceptionInfoForToken.put(inputWindowHandle.token,
w.getKeyInterceptionInfo());
// 如果存在surface,则执行此信息;认为对事件传递影响不大,暂不跟进此流程;
if (w.mWinAnimator.hasSurface()) {
mInputTransaction.setInputWindowInfo(
w.mWinAnimator.mSurfaceController.getClientViewRootSurface(),
inputWindowHandle);
}
}
}
总结:
WMS-addWindow-displayContent.getInputMonitor().setInputFocusLw(displayContent.mCurrentFocus,
false)方法的作用,是遍历WindowState,然后给每个InputWindowHandle赋值,并将InputMonitor的mFocusedInputWindowHandle指向唯一一个inputWindowHandle;至此addWindow方法分析完毕!
系统在这里创建并关联了一对InputChannel,更新了IMS中的焦点displayId,更新了WMS-DisplayContent-InputMonitor中的焦点InputWIndowHandle。
4.2.5.4 openInputChannelPair流程
来看下openInputChannelPair方法,理解InputChannel的内部原理:
frameworks/base/core/java/android/view/InputChannel.java
public static InputChannel[] openInputChannelPair(String name) {
if (name == null) {
throw new IllegalArgumentException("name must not be null");
}
if (DEBUG) {
Slog.d(TAG, "Opening input channel pair '" + name + "'");
}
return nativeOpenInputChannelPair(name);
}
frameworks/base/core/jni/android_view_InputChannel.cpp
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
ScopedUtfChars nameChars(env, nameObj);
std::string name = nameChars.c_str();
sp<InputChannel> serverChannel;
sp<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel); // 打开管道,创建InputChannel数组,并赋值给serverChannel和clientChannel
if (result) {
std::string message = android::base::StringPrintf(
"Could not open input channel pair : %s", strerror(-result));
jniThrowRuntimeException(env, message.c_str());
return nullptr;
}
// 创建java object数组;
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, nullptr);
if (env->ExceptionCheck()) {
return nullptr;
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env, serverChannel);
if (env->ExceptionCheck()) {
return nullptr;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env, clientChannel);
if (env->ExceptionCheck()) {
return nullptr;
}
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
// 把服务端管道和客户端管道放在jobjectArray数组中并返回给java层;
return channelPair;
}
此处我们需要分析以下两个关键方法: 1,InputChannel::openInputChannelPair(name,
serverChannel, clientChannel);
2,android_view_InputChannel_createInputChannel(env, serverChannel);
InputChannel类的定义在以下.h文件中:
frameworks/native/include/input/InputTransport.h
```cpp
frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
int sockets[2];
// socketpair方法的注释如下,是在sockey.h中定义的通用方法:
/* Create two new sockets, of type TYPE in domain DOMAIN and using
protocol PROTOCOL, which are connected to each other, and put file
descriptors for them in FDS[0] and FDS[1]. If PROTOCOL is zero,
one will be chosen automatically. Returns 0 on success, -1 for errors. */
// extern int socketpair (int __domain, int __type, int __protocol,int __fds[2]) __THROW;
// 创建可相互通信的socket0 和socket1,也就是我们常说的server和client。
// server传递给了IMS,client传递给了App.
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.c_str(), errno);
outServerChannel.clear();
outClientChannel.clear();
return result;
}
// 设置socket的读写配置?
int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
// binder 对象;
sp<IBinder> token = new BBinder();
std::string serverChannelName = name + " (server)";
android::base::unique_fd serverFd(sockets[0]);
// 创建InputChannelPair中的一个,入参是一个socket的fd;
outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
std::string clientChannelName = name + " (client)";
android::base::unique_fd clientFd(sockets[1]);
// 创建InputChannelPair中的另一个,入参是另一个socket的fd文件描述符;
// 实际是通过共享内容通信?
outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
return OK;
}
frameworks/native/libs/input/InputTransport.cpp
sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd,
sp<IBinder> token) {
// 设置文件标志为O_NONBLOCK
// 非阻塞I/O;如果read(2)调用没有可读取的数据,或者如果write(2)操作将阻塞
const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
if (result != 0) {
LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(), strerror(errno));
return nullptr;
}
return new InputChannel(name, std::move(fd), token);
}
InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
: mName(name), mFd(std::move(fd)), mToken(token) {
...
}
至此InputChannel::openInputChannelPair方法分析完成,此处创建了一对可以相互通信的socket,然后将两个socket的fd分别赋值给了两个InputChannel,这样两个InputChannel就可以依赖socket相互通信了。
来分析android_view_InputChannel_createInputChannel(env, serverChannel)创建java层对象的流程:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputChannel.cpp
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
sp<InputChannel> inputChannel) {
std::unique_ptr<NativeInputChannel> nativeInputChannel =
std::make_unique<NativeInputChannel>(inputChannel);
// 创建java层对象
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
nativeInputChannel.release());
}
return inputChannelObj;
}
//NativeInputChannel的构造
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputChannel.cpp
class NativeInputChannel {
public:
explicit NativeInputChannel(const sp<InputChannel>& inputChannel);
~NativeInputChannel();
inline sp<InputChannel> getInputChannel() { return mInputChannel; }
void setDisposeCallback(InputChannelObjDisposeCallback callback, void* data);
void invokeAndRemoveDisposeCallback(JNIEnv* env, jobject obj);
private:
sp<InputChannel> mInputChannel;
InputChannelObjDisposeCallback mDisposeCallback;
void* mDisposeData;
};
// 给Java层InputChannel-mPtr赋值,将nativeInputChannel的地址,传给inputChannelObj-mPtr;
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj, NativeInputChannel* nativeInputChannel) {
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast<jlong>(nativeInputChannel));
}
至此,我们知道了InputChannel.openInputChannelPair的原理,是在native层创建了一对可以相互通信的socket,然后又创建了一对InputChannel对象,每个InputChannel持有了一个socket的fd,依赖socket的能力来达到互相通信的目的!
4.2.5.5 App初始化InputEventReceiver流程
这里分析下ViewRootImpl-setView里,WindowSession.addToDisplayAsUser的后续流程;
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/java/android/view/ViewRootImpl.java
/**
* We have one child
*/
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
mView = view;
......
// Schedule the first layout -before- adding to the window
// manager, to make sure we do the relayout before receiving
// any other events from the system.
requestLayout();
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
inputChannel = new InputChannel(); // 创建一个空的InputChannel,在下面的addToDisplayAsUser方法中,会给此InputChannel赋值。
}
mForceDecorViewVisibility = (mWindowAttributes.privateFlags
& PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
adjustLayoutParamsForCompatibility(mWindowAttributes);
res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
setFrame(mTmpFrame);
} catch (RemoteException e) {
...
} finally {
......
if (inputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 创建WindowInputEventReceiver对象,此对象会从inputChannel中读取输入事件数据,并传递给ViewRootImpl中的view对象;
mInputEventReceiver = new WindowInputEventReceiver(inputChannel, Looper.myLooper());
}
....
}
来看下WindowInputEventReceiver的构造和方法实现:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/java/android/view/ViewRootImpl.java
final class WindowInputEventReceiver extends InputEventReceiver {
// 构造方法,继承自InputEventReceiver
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper);
}
// 注意此处重写的onInputEvent方法!!
@Override
public void onInputEvent(InputEvent event) {
......
// 开始传递InputEvent队列,注意参数;
enqueueInputEvent(event, this, 0, true);
}
}
来分析InputEventReceiver 的构造方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/java/android/view/InputEventReceiver.java
/**
* Creates an input event receiver bound to the specified input channel.
*
* @param inputChannel The input channel.
* @param looper The looper to use when invoking callbacks.
*/
public InputEventReceiver(InputChannel inputChannel, Looper looper) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null");
}
if (looper == null) {
throw new IllegalArgumentException("looper must not be null");
}
mInputChannel = inputChannel;
mMessageQueue = looper.getQueue();
// // 调用nativeInit,返回一个native层的NativeInputEventReceiver指针对象;
mReceiverPtr = nativeInit(new WeakReference<InputEventReceiver>(this),
inputChannel, mMessageQueue);
mCloseGuard.open("dispose");
}
看下nativeInit的功能:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputEventReceiver.cpp
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj); // 获取mPtr代表的native层InputChannel对象;
if (inputChannel == nullptr) {
jniThrowRuntimeException(env, "InputChannel is not initialized.");
return 0;
}
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == nullptr) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//创建NativeInputEventReceiver对象
sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
//初始化,此处开始InputChannel的事件回调监听;
status_t status = receiver->initialize();
if (status) {
String8 message;
message.appendFormat("Failed to initialize input event receiver. status=%d", status);
jniThrowRuntimeException(env, message.string());
return 0;
}
receiver->incStrong(gInputEventReceiverClassInfo.clazz); // retain a reference for the object
return reinterpret_cast<jlong>(receiver.get());
}
来分析NativeInputEventReceiver的构造方法和initialize方法:
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<InputChannel>& inputChannel,
const sp<MessageQueue>& messageQueue) :
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mInputConsumer(inputChannel), mMessageQueue(messageQueue),
mBatchedInputEventPending(false), mFdEvents(0) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName().c_str());
}
}
mInputConsumer(inputChannel);inputChannel赋值给了mInputConsumer;注意此处的进程是App进程;
// initialize 方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
// 通过ALOOPER_EVENT_INPUT消息,开始循环监听输入事件;
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputEventReceiver.cpp
void NativeInputEventReceiver::setFdEvents(int events) {
if (mFdEvents != events) {
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) {
mMessageQueue->getLooper()->addFd(fd, 0, events, this, nullptr);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
NativeInputEventReceiver继承了LooperCallback,在以下方法中,回调ALOOPER_EVENT_INPUT事件;
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputEventReceiver.cpp
int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
// This error typically occurs when the publisher has closed the input channel
......
return 0; // remove the callback
}
// 是Input事件,则通过consumeEvents方法开始接收事件;
// mInputConsumer(inputChannel)对象会读取到这些数据
if (events & ALOOPER_EVENT_INPUT) { ;
JNIEnv* env = AndroidRuntime::getJNIEnv();
status_t status = consumeEvents(env, false /*consumeBatches*/, -1, nullptr);
mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
return status == OK || status == NO_MEMORY ? 1 : 0;
}
// 异常msg
if (events & ALOOPER_EVENT_OUTPUT) {
......
mFinishQueue.clear();
setFdEvents(ALOOPER_EVENT_INPUT);
return 1;
}
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
"events=0x%x", getInputChannelName().c_str(), events);
return 1;
}
关键的consumeEvents方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/core/jni/android_view_InputEventReceiver.cpp
status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s, frameTime=%" PRId64,
getInputChannelName().c_str(), toString(consumeBatches), frameTime);
}
if (consumeBatches) {
mBatchedInputEventPending = false;
}
if (outConsumedBatch) {
*outConsumedBatch = false;
}
ScopedLocalRef<jobject> receiverObj(env, nullptr);
bool skipCallbacks = false;
// 循环接收InputChannel中的数据,并发给上层逻辑;
for (;;) {
uint32_t seq;
InputEvent* inputEvent; // inputEvent指针
// InputChannel的consume方法,将输入事件读取到inputEvent中;
status_t status = mInputConsumer.consume(&mInputEventFactory,
consumeBatches, frameTime, &seq, &inputEvent);
if (status != OK && status != WOULD_BLOCK) {
ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
getInputChannelName().c_str(), status);
return status;
}
if (status == WOULD_BLOCK) {
......
return OK;
}
assert(inputEvent);
if (!skipCallbacks) {
if (!receiverObj.get()) {
......
}
jobject inputEventObj;
// 判断输入事件类型,motion事件,key事件,focus事件等类型。
switch (inputEvent->getType()) {
case AINPUT_EVENT_TYPE_KEY:
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received key event.", getInputChannelName().c_str());
}
// 将inputEvent转化为java的KeyEvent类型object按键对象;
inputEventObj = android_view_KeyEvent_fromNative(env,
static_cast<KeyEvent*>(inputEvent));
break;
case AINPUT_EVENT_TYPE_MOTION: {
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received motion event.", getInputChannelName().c_str());
}
MotionEvent* motionEvent = static_cast<MotionEvent*>(inputEvent);
if ((motionEvent->getAction() & AMOTION_EVENT_ACTION_MOVE) && outConsumedBatch) {
*outConsumedBatch = true;
}
inputEventObj = android_view_MotionEvent_obtainAsCopy(env, motionEvent);
break;
}
case AINPUT_EVENT_TYPE_FOCUS: {
FocusEvent* focusEvent = static_cast<FocusEvent*>(inputEvent);
if (kDebugDispatchCycle) {
ALOGD("channel '%s' ~ Received focus event: hasFocus=%s, inTouchMode=%s.", getInputChannelName().c_str(), toString(focusEvent->getHasFocus()), toString(focusEvent->getInTouchMode()));
}
env->CallVoidMethod(receiverObj.get(), gInputEventReceiverClassInfo.onFocusEvent, jboolean(focusEvent->getHasFocus()), jboolean(focusEvent->getInTouchMode()));
finishInputEvent(seq, true /* handled */);
continue;
}
default:
assert(false); // InputConsumer should prevent this from ever happening
inputEventObj = nullptr;
}
// 若inputEventObj不为空,则通过CallVoidMethod方法,
// 调用上层的gInputEventReceiverClassInfo.dispatchInputEvent方法,
// 来将输入事件传递到java层。
if (inputEventObj) {
...
env->CallVoidMethod(receiverObj.get(),
gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
if (env->ExceptionCheck()) {
ALOGE("Exception dispatching input event.");
skipCallbacks = true;
}
env->DeleteLocalRef(inputEventObj);
} else {
ALOGW("channel '%s' ~ Failed to obtain event object.",
getInputChannelName().c_str());
skipCallbacks = true;
}
}
if (skipCallbacks) {
mInputConsumer.sendFinishedSignal(seq, false);
}
}
}
这里我们只分析mInputConsumer.consume方法,看App是如何读取到输入事件数据的;
其他流程如android_view_KeyEvent_fromNative和dispatchInputEvent,会在其他章节会进行分析;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/InputTransport.cpp
status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consumeBatches,
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
mChannel->getName().c_str(), toString(consumeBatches), frameTime);
}
*outSeq = 0;
*outEvent = nullptr;
// Fetch the next input message.
// Loop until an event can be returned or no additional events are received.
while (!*outEvent) {
if (mMsgDeferred) {
// mMsg contains a valid input message from the previous call to consume
// that has not yet been processed.
mMsgDeferred = false;
} else {
// system_server进程会通过对端InputChannel的sendMessage方法发送数据;
// 这里app进程中的InputChannel,通过receiveMessage方法读取输入事件;
// Receive a fresh message.
status_t result = mChannel->receiveMessage(&mMsg);
if (result) {
// Consume the next batched event unless batches are being held for later.
if (consumeBatches || result != WOULD_BLOCK) {
// 调用consumeBatch方法,将
result = consumeBatch(factory, frameTime, outSeq, outEvent);
if (*outEvent) {
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
mChannel->getName().c_str(), *outSeq);
}
break;
}
}
return result;
}
}
// 判断输入事件类型,将InputMessage数据转换为keyEvent等数据类型;
switch (mMsg.header.type) {
case InputMessage::Type::KEY: {
KeyEvent* keyEvent = factory->createKeyEvent();
if (!keyEvent) return NO_MEMORY;
// 将mMsg数据,转换为KeyEvent数据,并存入outEvent;
initializeKeyEvent(keyEvent, &mMsg);
*outSeq = mMsg.body.key.seq;
*outEvent = keyEvent;
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
mChannel->getName().c_str(), *outSeq);
}
break;
}
case InputMessage::Type::MOTION: {
.........
break;
}
case InputMessage::Type::FINISHED: {
LOG_ALWAYS_FATAL("Consumed a FINISHED message, which should never be seen by "
"InputConsumer!");
break;
}
case InputMessage::Type::FOCUS: {
FocusEvent* focusEvent = factory->createFocusEvent();
if (!focusEvent) return NO_MEMORY;
initializeFocusEvent(focusEvent, &mMsg);
*outSeq = mMsg.body.focus.seq;
*outEvent = focusEvent;
break;
}
}
}
return OK;
}
InputChannel读取数据:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
// 从socket的mFd共享内存中读取数据,应该是阻塞在此处;
nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {
int error = errno;
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno);
#endif
if (error == EAGAIN || error == EWOULDBLOCK) {
return WOULD_BLOCK;
}
if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
return DEAD_OBJECT;
}
return -error;
}
if (nRead == 0) { // check for EOF
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str());
#endif
return DEAD_OBJECT;
}
if (!msg->isValid(nRead)) {
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ received invalid message", mName.c_str());
#endif
return BAD_VALUE;
}
#if DEBUG_CHANNEL_MESSAGES
ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type);
#endif
return OK;
}
总结下,此流程从Activity的onResume声明周期开始,在system_server进程中创建InputChannel对,在App进程中初始化WindowInputEventReceiver,然后尝试从InputChannel-mFd中读取数据,最终会将输入数据抛到View层进行处理;
至此,我们看到了App端接收InputChannel数据的具体流程; 输入数据的类型转换和传递流程,会在4.5章节进行详细介绍;
4.3 IMS读取和传递Input事件流程
4.3.1 流程介绍
这个流程,介绍了InputReader线程,从EventHub读取输入事件,并将事件通过InputDispatcher传递给InputChannel的流程;
事件传递给InputChannel后,存在于App进程中的对端InputChannel就可以读取到输入事件.
4.3.2 相关模块图示
4.3.2.1 模块架构图
4.3.2.2 dev/input驱动文件位置
####4.3.2.3 Idc/kl/kcm文件位置
4.3.3 类图
以下类图可以从InputReader出发,按照输入事件读取和传递流程来查看相关类的依赖关联关系。
4.3.4 时序图
4.3.4.1 EventHub扫描Device数据流程
4.3.4.2 InputReader读取和传输数据流程
4.3.4.3 InputDispatcher传递事件流程
4.3.5 代码解读
此章节,从InputReader从驱动文件读取输入数据开始分析,直到按键事件数据传入某个Window对应的InputChannel中为止,是这个章节的完成流程;
4.3.5.1 InputReader读取数据流程
先来回顾下,PMS的nativeInit方法创建了InputReader和InputDispatcher对象,nativeStart方法启动了两个相关线程,来循环调用loopOnce和diapatchOnce方法;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReader.cpp
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
: mContext(this),
mEventHub(eventHub),
mPolicy(policy),
mGlobalMetaState(0),
mGeneration(1),
mNextInputDeviceId(END_RESERVED_ID),
mDisableVirtualKeysTimeout(LLONG_MIN),
mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
// mQueuedListener 持有InputClassifier的对象listener,listener持有InputDispatcher的对象;
mQueuedListener = new QueuedInputListener(listener);
{ // acquire lock
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
} // release lock
}
InputReader.h里的关键数据:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/include/InputReader.h
// The event queue.
static const int EVENT_BUFFER_SIZE = 256;
RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
// An input device can represent a collection of EventHub devices. This map provides a way
// to lookup the input device instance from the EventHub device id.
std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices;
循环调用loopOnce方法,开始读取输入设备和输入事件;猜测跟mEventHub有关;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
...
// 从EventHub读取事件到mEventBuffer数组中,返回值为count数量;
size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
{ // acquire lock
AutoMutex _l(mLock);
mReaderIsAliveCondition.broadcast();
if (count) {
// 若读取到了输入事件,则处理mEventBuffer中的输入事件;
processEventsLocked(mEventBuffer, count);
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// 当前时间大于超时时间,处理超时问题;
if (now >= mNextTimeout) {
...
mNextTimeout = LLONG_MAX;
timeoutExpiredLocked(now); // 处理超时;
}
}
// mGeneration在mEventHub->getEvents或processEventsLocked时发生了变化,说明inputDevicesChanged,需要更新inputDevices列表;
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
getInputDevicesLocked(inputDevices);
}
} // release lock
// 通知java层IMS端Input设备变化了,如游戏可能在监听输入设备(游戏手柄、鼠标键盘等)的连接、断开等行为
// 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(); // 通知listener输入事件到来?不清楚干啥用的,待会儿看下。
}
此处的关键方法调用; 1,size_t count = mEventHub->getEvents(timeoutMillis,
mEventBuffer, EVENT_BUFFER_SIZE); 2,processEventsLocked(mEventBuffer,
count); 3,mPolicy->notifyInputDevicesChanged(inputDevices);
4,mQueuedListener->flush();
来看下mEventHub->getEvents这个关键方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
// 构造方法中,数据初始化状态:
: mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD),
mNextDeviceId(1),
mControllerNumbers(),
mOpeningDevices(nullptr),
mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false),
mNeedToScanDevices(true), // 注意赋值
mPendingEventCount(0),
mPendingEventIndex(0),
mPendingINotify(false)
// 构造方法 end.
getEvents方法会从驱动节点读取驱动数据,并转换为输入事件或输入设备的插入等相关事件,如InputDevice就绪、注销、输入事件等信息;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
ALOG_ASSERT(bufferSize >= 1);
AutoMutex _l(mLock);
// 创建input_event数组,bufferSize是EVENT_BUFFER_SIZE=256;
struct input_event readBuffer[bufferSize];
RawEvent* event = buffer; // 要存储的数据容器
size_t capacity = bufferSize; // 最大数量
bool awoken = false;
// 无限循环,直到遇到return或break;
for (;;) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
// mNeedToReopenDevices初始化为false,没有要关闭的设备;
// Reopen input devices if needed.
if (mNeedToReopenDevices) {
mNeedToReopenDevices = false;
ALOGI("Reopening all input devices due to a configuration change.");
closeAllDevicesLocked();
mNeedToScanDevices = true;
break; // return to the caller before we actually rescan
}
// 初始化为null,没有要关闭的设备;
// Report any devices that had last been added/removed.
while (mClosingDevices) {
Device* device = mClosingDevices;
ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());
mClosingDevices = device->next;
event->when = now;
event->deviceId = (device->id == mBuiltInKeyboardId)
? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID
: device->id;
event->type = DEVICE_REMOVED;
event += 1;
delete device;
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) {
break;
}
}
// 初始化为true,第一次loopOnce要扫描设备,确认有哪些输入设备,确认输入设备有什么样的特性。
if (mNeedToScanDevices) {
mNeedToScanDevices = false;
// 关键方法!扫描/dev/input/下的驱动文件节点,并添加到EventHub的mDevices中;
scanDevicesLocked();
mNeedToSendFinishedDeviceScan = true;
}
// 上面的scanDevicesLocked方法,会给mOpeningDevices赋值;
// 开机过程中扫描的设备,或新加入的输入设备,都会添加到mOpeningDevices里。
while (mOpeningDevices != nullptr) {
Device* device = mOpeningDevices;
ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());
// mOpeningDevices是链表数据类型
mOpeningDevices = device->next;
event->when = now;
event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
event->type = DEVICE_ADDED;
event += 1;// event指针数组后移一位
mNeedToSendFinishedDeviceScan = true;
if (--capacity == 0) { // capacity -1,即事件容量-1;
break;
}
}
// 扫描输入设备结束,开机扫描时为true;
if (mNeedToSendFinishedDeviceScan) {
mNeedToSendFinishedDeviceScan = false;
event->when = now;
event->type = FINISHED_DEVICE_SCAN;
event += 1;
// 如果getEvents读取到的事件数量超过了256,则退出外面的for(;;)循环,上报当前的事件;
if (--capacity == 0) {
break;
}
}
// 首次loop,mPendingEventIndex和mPendingEventCount都是0,不进入此循环;
// 等读取到输入事件后,上面的for(;;)会重新循环一次,此时mPendingEventCount就是大于0了,mPendingEventItems也从驱动读取到了各种事件;
// Grab the next input event.
bool deviceChanged = false;
while (mPendingEventIndex < mPendingEventCount) {
// 驱动数据原始数据类型:epoll_event!!!
const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];
if (eventItem.data.fd == mINotifyFd) {
if (eventItem.events & EPOLLIN) {
mPendingINotify = true;
} else {
ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events);
}
continue;
}
if (eventItem.data.fd == mWakeReadPipeFd) {
if (eventItem.events & EPOLLIN) {
ALOGV("awoken after wake()");
awoken = true;
char buffer[16];
ssize_t nRead;
do {
nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer));
} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer));
} else {
ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.",
eventItem.events);
}
continue;
}
Device* device = getDeviceByFdLocked(eventItem.data.fd);
if (!device) {
ALOGE("Received unexpected epoll event 0x%08x for unknown fd %d.", eventItem.events,
eventItem.data.fd);
ALOG_ASSERT(!DEBUG);
continue;
}
// video类型,此处不进行分析;
if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {
if (eventItem.events & EPOLLIN) {
size_t numFrames = device->videoDevice->readAndQueueFrames();
if (numFrames == 0) {
ALOGE("Received epoll event for video device %s, but could not read frame",
device->videoDevice->getName().c_str());
}
} else if (eventItem.events & EPOLLHUP) {
// TODO(b/121395353) - consider adding EPOLLRDHUP
ALOGI("Removing video device %s due to epoll hang-up event.",
device->videoDevice->getName().c_str());
unregisterVideoDeviceFromEpollLocked(*device->videoDevice);
device->videoDevice = nullptr;
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
device->videoDevice->getName().c_str());
ALOG_ASSERT(!DEBUG);
}
continue;
}
// 确定是Input输入设备,可能输入物理按键、触屏、游戏手柄、键盘等等类型的输入事件;
// This must be an input event
if (eventItem.events & EPOLLIN) {
// 从此设备读取输入事件;驱动数据原始数据类型:input_event
int32_t readSize =
read(device->fd, readBuffer, sizeof(struct input_event) * capacity);
if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {
// Device was removed before INotify noticed.
ALOGW("could not get event, removed? (fd: %d size: %" PRId32
" bufferSize: %zu capacity: %zu errno: %d)\n",
device->fd, readSize, bufferSize, capacity, errno);
deviceChanged = true;
closeDeviceLocked(device);
} else if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
ALOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
// 读取数据量错误;
ALOGE("could not get event (wrong size: %d)", readSize);
} else {
// 读取到了输入事件!
int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;
// 读取到的输入事件的数量;
size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
// 存入readBuffer中,i从0开始,说明一次for循环只能处理一个输入设备的事件。;
struct input_event& iev = readBuffer[i];
// 将读取到的iev中的数据,读取到event中;
event->when = processEventTimestamp(iev);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
event += 1;//event指针++,后移;
capacity -= 1;// event中可用容量-1;
}
if (capacity == 0) {
// The result buffer is full. Reset the pending event index
// so we will try to read the device again on the next iteration.
mPendingEventIndex -= 1;
break;
}
}
} else if (eventItem.events & EPOLLHUP) {
ALOGI("Removing device %s due to epoll hang-up event.",
device->identifier.name.c_str());
deviceChanged = true;
closeDeviceLocked(device);
} else {
ALOGW("Received unexpected epoll event 0x%08x for device %s.", eventItem.events,
device->identifier.name.c_str());
}
}
// readNotify() will modify the list of devices so this must be done after
// processing all other events to ensure that we read all remaining events
// before closing the devices.
if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {
mPendingINotify = false;
readNotifyLocked();
deviceChanged = true;
}
// Report added or removed devices immediately.
if (deviceChanged) {
continue;
}
// Return now if we have collected any events or if we were explicitly awoken.
if (event != buffer || awoken) {
break;
}
// Poll for events.
// When a device driver has pending (unread) events, it acquires
// a kernel wake lock. Once the last pending event has been read, the device
// driver will release the kernel wake lock, but the epoll will hold the wakelock,
// since we are using EPOLLWAKEUP. The wakelock is released by the epoll when epoll_wait
// is called again for the same fd that produced the event.
// Thus the system can only sleep if there are no events pending or
// currently being processed.
//
// The timeout is advisory only. If the device is asleep, it will not wake just to
// service the timeout.
mPendingEventIndex = 0; // index归零;
mLock.unlock(); // release lock before poll
// 等待输入事件,将数据读取到mPendingEventItems中, pollResult是读取到的事件数量;
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
mLock.lock(); // reacquire lock after poll
// 未读取到数据,重新for循环
if (pollResult == 0) {
// Timed out.
mPendingEventCount = 0;
break;
}
if (pollResult < 0) {
// An error occurred.
......
} else {
// 读取到了数据,赋值读取到的数量到mPendingEventCount,读取到的数据在mPendingEventItems中;
// Some events occurred.
mPendingEventCount = size_t(pollResult);
}
}
// 指针数量相减,得到需要处理的事件的数量;
// All done, return the number of events we read.
return event - buffer;
}
接着上面的关键方法,插入这里发现的关键方法; 1,size_t count =
mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
1.1,扫描设备:scanDevicesLocked()
1.2,读取到输入事件:struct input_event& iev = readBuffer[i]; 2,processEventsLocked(mEventBuffer, count);
3,mPolicy->notifyInputDevicesChanged(inputDevices);
4,mQueuedListener->flush();
来分析1.1 scanDevicesLocked;
此处会从/dev/input/中读取设备驱动文件,并从驱动文件中读取部分信息,如version号,是否支持vendor/product,支持的按键scancode和设备类型等数据;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
void EventHub::scanDevicesLocked() {
// 扫描DEVICE_PATH
// static const char* DEVICE_PATH = "/dev/input";
status_t result = scanDirLocked(DEVICE_PATH);
if (result < 0) {
ALOGE("scan dir failed for %s", DEVICE_PATH);
}
if (isV4lScanningEnabled()) {
result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
if (result != OK) {
ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
}
}
if (mDevices.indexOfKey(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) < 0) {
createVirtualKeyboardLocked();
}
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
status_t EventHub::scanDirLocked(const char* dirname) {
char devname[PATH_MAX];
char* filename;
DIR* dir;
struct dirent* de;
dir = opendir(dirname);// 打开文件夹
if (dir == nullptr) return -1;
strcpy(devname, dirname); // 复制dirname到devname
filename = devname + strlen(devname); // 赋值为/dev/input10,为什么?
*filename++ = '/'; /dev/input10/???
// 从dir中读取到文件;
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;
}
打开文件,读取各种信息,并保存到输入设备列表,方便后续从这些文件节点读取输入事件;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
status_t EventHub::openDeviceLocked(const char* devicePath) {
char buffer[80];
ALOGV("Opening device: %s", devicePath);
int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK); // 打开文件;
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) {
ALOGE("Could not get device name for %s: %s", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name = buffer;
}
// 是否是需要排除的设备,好像在fw的config里定义,从InputManagerService读取;
// Check to see if the device is on our excluded list
for (size_t i = 0; i < mExcludedDevices.size(); i++) {
const std::string& item = mExcludedDevices[i];
if (identifier.name == item) {
ALOGI("ignoring event id %s driver %s\n", devicePath, item.c_str());
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;
}
// input_id信息,如bustype, product, vendor,version;
// 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 = buffer;
}
// 读取uniqueId信息;
// 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 = buffer;
}
// 用上面读取的信息拼凑成Descriptor信息字符串;
// Fill in the descriptor.
assignDescriptorLocked(identifier);
// Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
// 注意此处!EventHub里的是Device对象,
// InputReader里还有一个InputDevice,注意不要弄混淆;
Device* device = new Device(fd, deviceId, devicePath, identifier);
......
// 重要!从磁盘配置文件中读取scanCode和KeyCode的对应配置信息;
// 配置文件为×××.kl和×××.kcm,默认配置在frameworks/base/data/keyboards下;
// Load the configuration file for the device.
loadConfigurationLocked(device);
/*
*从驱动读取此输入设备支持的输入事件类型;
*注意此处在.h文件里的声明,是int[]数组类型;
*uint8_t keyBitmask[(KEY_MAX + 1) / 8];
*uint8_t absBitmask[(ABS_MAX + 1) / 8];
*uint8_t relBitmask[(REL_MAX + 1) / 8];
*uint8_t swBitmask[(SW_MAX + 1) / 8];
*uint8_t ledBitmask[(LED_MAX + 1) / 8];
*uint8_t ffBitmask[(FF_MAX + 1) / 8];
*uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8];
*/
// 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);
// 下面的逻辑,是根据上面读取到的设备支持的类型,给device-classes打上分类标签,方便fw层来区分不同类型的输入设备,如游戏手柄支持abxy按键,鼠标是不是支持relBitmast相关输入?
// 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(BTN_WHEEL),
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 rotary encoder type device.
String8 deviceType = String8();
if (device->configuration &&
device->configuration->tryGetProperty(String8("device.type"), deviceType)) {
if (!deviceType.compare(String8("rotaryEncoder"))) {
device->classes |= INPUT_DEVICE_CLASS_ROTARY_ENCODER;
}
}
// 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;
// Is this a BT stylus?
} else if ((test_bit(ABS_PRESSURE, device->absBitmask) ||
test_bit(BTN_TOUCH, device->keyBitmask)) &&
!test_bit(ABS_X, device->absBitmask) && !test_bit(ABS_Y, device->absBitmask)) {
device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS;
// Keyboard will try to claim some of the buttons but we really want to reserve those so we
// can fuse it with the touch screen data, so just take them back. Note this means an
// external stylus cannot also be a keyboard device.
device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD;
}
// 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.
bool success = loadVirtualKeyMapLocked(device);
if (success) {
device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
}
}
// 注意此处,是加载按键信息到内存中,用到了刚才loadConfigurationLocked里的.kl等配置文件;此处比较重要,待会儿分析
// 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;
}
}
}
// 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.c_str());
delete device;
return -1;
}
// Determine whether the device has a mic.
if (deviceHasMicLocked(device)) {
device->classes |= INPUT_DEVICE_CLASS_MIC;
}
// 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);
setLedForControllerLocked(device);
}
// Find a matching video device by comparing device names
// This should be done before registerDeviceForEpollLocked, so that both fds are added to epoll
for (std::unique_ptr<TouchVideoDevice>& videoDevice : mUnattachedVideoDevices) {
if (device->identifier.name == videoDevice->getName()) {
device->videoDevice = std::move(videoDevice);
break;
}
}
mUnattachedVideoDevices
.erase(std::remove_if(mUnattachedVideoDevices.begin(), mUnattachedVideoDevices.end(), [](const std::unique_ptr<TouchVideoDevice>& videoDevice) {
return videoDevice == nullptr;
}),
mUnattachedVideoDevices.end());
if (registerDeviceForEpollLocked(device) != OK) {
delete device;
return -1;
}
configureFd(device);
ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, "
"configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, ",
deviceId, fd, devicePath, device->identifier.name.c_str(), device->classes,
device->configurationFile.c_str(), device->keyMap.keyLayoutFile.c_str(),
device->keyMap.keyCharacterMapFile.c_str(), toString(mBuiltInKeyboardId == deviceId));
// 重要,添加device到集合中,需要分析。
addDeviceLocked(device);
return OK;
}
我们看到1.1-openDeviceLocked方法中,读取了输入设备驱动节点的一些版本号、name等信息,以及支持的输入类型等信息;
来分析openDeviceLocked用到的以下关键方法:
1.1.1,EventHub-openDeviceLocked-loadConfigurationLocked(device);
1.1.2,EventHub-openDeviceLocked-keyMapStatus = loadKeyMapLocked(device);
1.1.3,EventHub-openDeviceLocked-addDeviceLocked(device);
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
void EventHub::loadConfigurationLocked(Device* device) {
/*查找配置文件路径字符串,返回值赋值给了此device的configurationFile;
*enum InputDeviceConfigurationFileType {
* INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
* INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
* INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
*};
*/
device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(
device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
if (device->configurationFile.empty()) {
ALOGD("No input device configuration file found for device '%s'.",
device->identifier.name.c_str());
} else {
// 配置文件不为空,加载配置信息到此device的configuration中;
status_t status = PropertyMap::load(String8(device->configurationFile.c_str()),
&device->configuration);
if (status) {
ALOGE("Error loading input device configuration file for device '%s'. "
"Using default configuration.",
device->identifier.name.c_str());
}
}
}
查找此设备对应的配置文件
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
std::string getInputDeviceConfigurationFilePathByDeviceIdentifier(
const InputDeviceIdentifier& deviceIdentifier,
InputDeviceConfigurationFileType type) {
// 若驱动层vendor和product信息不为0
if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
// 版本号不为0
if (deviceIdentifier.version != 0) {
// 拼凑字符串为配置文件路径,并返回string,%04x代表按照16进制转化,若不够4位,则前面补0;
// Vendor_#VENDOR#_Product_#PRODUCT#_Version_#VERSION#
// Try vendor product version.
std::string versionPath = getInputDeviceConfigurationFilePathByName(
StringPrintf("Vendor_%04x_Product_%04x_Version_%04x",
deviceIdentifier.vendor, deviceIdentifier.product,
deviceIdentifier.version),
type);
if (!versionPath.empty()) {
return versionPath;
}
}
// Version号==0,则不用Version来拼凑配置文件;
// Try vendor product.
std::string productPath = getInputDeviceConfigurationFilePathByName(
StringPrintf("Vendor_%04x_Product_%04x",
deviceIdentifier.vendor, deviceIdentifier.product),
type);
if (!productPath.empty()) {
return productPath;
}
}
// 用deviceName拼凑字符串,name若包含非法字符,则用_替换;
// Try device name.
return getInputDeviceConfigurationFilePathByName(deviceIdentifier.getCanonicalName(), type);
}
std::string getInputDeviceConfigurationFilePathByName(
const std::string& name, InputDeviceConfigurationFileType type) {
// Search system repository.
std::string path;
// 三个路径,最后一个ANDROID_ROOT是/system;
// Treblized input device config files will be located /odm/usr or /vendor/usr.
const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};
for (size_t i = 0; i < size(rootsForPartition); i++) {
if (rootsForPartition[i] == nullptr) {
continue;
}
path = rootsForPartition[i];
// 拼凑路径为/***/usr/
path += "/usr/";
// 拼凑路径为/odm Or vendor/usr/idc/#NAME#.idc
appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
ALOGD("Probing for system provided input device configuration file: path='%s'",
path.c_str());
#endif
if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
ALOGD("Found");
#endif
// 若文件存在,则使用此配置文件,注意此处相当于存在一个优先级顺序,odm > vendor > #root#;
return path;
}
}
// 上面的路径里没有找到配置文件,从以下逻辑中查找;
// Search user repository.
// TODO Should only look here if not in safe mode.
path = "";
// androidData是/data目录
char *androidData = getenv("ANDROID_DATA");
if (androidData != nullptr) {
path += androidData;
}
path += "/system/devices/";
// 拼凑文件目录:/data/system/devices/#NAME#.idc
appendInputDeviceConfigurationFileRelativePath(path, name, type);
#if DEBUG_PROBE
ALOGD("Probing for system user input device configuration file: path='%s'", path.c_str());
#endif
if (!access(path.c_str(), R_OK)) {
#if DEBUG_PROBE
ALOGD("Found");
#endif
return path;
}
// Not found. // 若不存在,返回空"";
#if DEBUG_PROBE
ALOGD("Probe failed to find input device configuration file: name='%s', type=%d",
name.c_str(), type);
#endif
return "";
}
来看下配置文件的样式,从配置文件中读取到了哪些信息:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/data/keyboards/qwerty.idc:
touch.deviceType = touchScreen
touch.orientationAware = 1
// 注意layout和characterMap配置,分别对应了qwerty.kl和qwerty.kcm
keyboard.layout = qwerty
keyboard.characterMap = qwerty
keyboard.orientationAware = 1
keyboard.builtIn = 1
cursor.mode = navigation
cursor.orientationAware = 1
以下load方法就是将以上数据读取到device的configuration键值对中,此处不再分析;
PropertyMap::load(String8(device->configurationFile.c_str()), &device->configuration);
先来看下qwerty.kl中的一部分配置,每一行代表了一个按键属性+scanCode+按键字符串,按键字符串对应的键值,在一个.h文件中定义,后续会提到:
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/data/keyboards/qwerty.kl
key 217 SEARCH
key 228 POUND
key 227 STAR
key 231 CALL
key 61 CALL
key 232 DPAD_CENTER
key 108 DPAD_DOWN
key 103 DPAD_UP
key 102 HOME
key 105 DPAD_LEFT
key 106 DPAD_RIGHT
key 115 VOLUME_UP
key 114 VOLUME_DOWN
key 116 POWER
key 212 CAMERA
以下配置文件更具备代表性,包含了key,usage,axis三种配置类型;
/home/chen/disk2/project/aosp/r_aosp/frameworks/base/data/keyboards/Generic.kl
key 522 STAR
key 523 POUND
key 580 APP_SWITCH
key 582 VOICE_ASSIST
// Linux KEY_ASSISTANT
key 583 ASSIST
//Keys defined by HID usages
key usage 0x0c006F BRIGHTNESS_UP
key usage 0x0c0070 BRIGHTNESS_DOWN
//Joystick and game controller axes.
//Axes that are not mapped will be assigned generic axis numbers by the input subsystem.
axis 0x00 X
axis 0x01 Y
axis 0x02 Z
axis 0x03 RX
这里好像定义了一些组合按键的信息:
key A {
label: 'A'
number: '2'
base: 'a'
shift, capslock: 'A'
alt: '#'
shift+alt, capslock+alt: none
}
key B {
label: 'B'
number: '2'
base: 'b'
shift, capslock: 'B'
alt: '<'
shift+alt, capslock+alt: none
}
loadConfigurationLocked其实是查找并读取.idc配置文件信息,并将数据加载到device的configuration中;
接下来分析下后续的流程,猜测此处loadKeyMapLocked是加载刚才读到的.kl和kcm信息到device中,上报上来scancode后,就可以转换为对应的keyCode:
1.1.2,EventHub-openDeviceLocked-keyMapStatus = loadKeyMapLocked(device);
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
status_t EventHub::loadKeyMapLocked(Device* device) {
// 通过device的keyMap对象,加载device的configuration,到device的identifier中;
return device->keyMap.load(device->identifier, device->configuration);
}
// 注意此处拿的是device的keyMap对象;
// 上面的idc文件里配置了keyboard.layout = qwerty;keyboard.characterMap = qwerty
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/Keyboard.cpp
status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
const PropertyMap* deviceConfiguration) {
// 若device有自己的配置文件
// Use the configured key layout if available.
if (deviceConfiguration) {
String8 keyLayoutName;
// 若配置了keyboard.layout属性
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
// 加载.kl文件,若不存在则返回NAME_NOT_FOUND
status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
deviceIdentifier.name.c_str(), keyLayoutName.string());
}
}
// 加载keyboard.characterMap文件
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
deviceIdentifier.name.c_str(), keyCharacterMapName.string());
}
}
if (isComplete()) {
return OK;
}
}
// Try searching by device identifier.
if (probeKeyMap(deviceIdentifier, "")) {
return OK;
}
// 上面没有自己的.idc文件,则使用通用的Generic.kl和Generic.kcm配置文件;
// 此处读取并解析Generic.kl,加载到device中;
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
if (probeKeyMap(deviceIdentifier, "Generic")) {
return OK;
}
......
return NAME_NOT_FOUND;
}
来看下probeKeyMap方法,在没有专用配置文件时,使用默认的Generic配置文件;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/Keyboard.cpp
bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
const std::string& keyMapName) {
// 若keyLayoutFile为空,则加载Generic.kl
if (!haveKeyLayout()) {
loadKeyLayout(deviceIdentifier, keyMapName);
}
// 若keyCharacterMapFile为空,则加载Generic.kcm
if (!haveKeyCharacterMap()) {
loadKeyCharacterMap(deviceIdentifier, keyMapName);
}
return isComplete();
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/Keyboard.cpp
status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
const std::string& name) {
// name不为空,则通过getInputDeviceConfigurationFilePathByName方法查找配置文件,并KeyLayoutMap::load;
// 上面查找的是.idc文件,这次查找的是kl文件和kcm文件。
// 在设备里应该是/system/usr/****/Generic.kl文件
std::string path(getPath(deviceIdentifier, name,
INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
if (path.empty()) {
return NAME_NOT_FOUND;
}
// 加载到keyLayoutMap中;
status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
if (status) {
return status;
}
keyLayoutFile = path;
return OK;
}
keyLayoutMap是device-KeyMap中的一个sp keyLayoutMap指针;
需要分析以下方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/KeyLayoutMap.cpp-KeyLayoutMap::load(path, &keyLayoutMap);
先来看下KeyLayoutMap数据结构,就知道要从配置文件中读取什么数据了!
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/include/input/KeyLayoutMap.h
class KeyLayoutMap : public RefBase {
public:
static status_t load(const std::string& filename, sp<KeyLayoutMap>* outMap);
status_t mapKey(int32_t scanCode, int32_t usageCode,
int32_t* outKeyCode, uint32_t* outFlags) const;
status_t findScanCodesForKey(int32_t keyCode, std::vector<int32_t>* outScanCodes) const;
status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const;
status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const;
status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
protected:
virtual ~KeyLayoutMap();
private:
// key 数据结构
struct Key {
int32_t keyCode;
uint32_t flags;
};
// led的数据结构
struct Led {
int32_t ledCode;
};
KeyedVector<int32_t, Key> mKeysByScanCode; // scancode 和key的匹配关系
KeyedVector<int32_t, Key> mKeysByUsageCode; // usageCode和key的匹配关系
KeyedVector<int32_t, AxisInfo> mAxes;
KeyedVector<int32_t, Led> mLedsByScanCode; // scancode和led数据的匹配关系
KeyedVector<int32_t, Led> mLedsByUsageCode;
KeyLayoutMap();
const Key* getKey(int32_t scanCode, int32_t usageCode) const;
class Parser {
KeyLayoutMap* mMap;
Tokenizer* mTokenizer;
public:
Parser(KeyLayoutMap* map, Tokenizer* tokenizer);
~Parser();
status_t parse();
private:
status_t parseKey();
status_t parseAxis();
status_t parseLed();
};
};
}
继续分析KKeyLayoutMap::load方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/Keyboard.cpp
status_t KeyLayoutMap::load(const std::string& filename, sp<KeyLayoutMap>* outMap) {
outMap->clear();
Tokenizer* tokenizer;
status_t status = Tokenizer::open(String8(filename.c_str()), &tokenizer);
if (status) {
ALOGE("Error %d opening key layout map file %s.", status, filename.c_str());
} else {
sp<KeyLayoutMap> map = new KeyLayoutMap();
if (!map.get()) {
ALOGE("Error allocating key layout map.");
status = NO_MEMORY;
} else {
#if DEBUG_PARSER_PERFORMANCE
nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
#endif
// 将文件中的数据解析到map中
Parser parser(map.get(), tokenizer);
status = parser.parse();
#if DEBUG_PARSER_PERFORMANCE
nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
tokenizer->getFilename().string(), tokenizer->getLineNumber(),
elapsedTime / 1000000.0);
#endif
if (!status) {
// outMap解应用,赋值为map;
*outMap = map;
}
}
delete tokenizer;
}
return status;
}
来看下parse方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/KeyLayoutMap.cpp
status_t KeyLayoutMap::Parser::parse() {
while (!mTokenizer->isEof()) {
#if DEBUG_PARSER
ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
#endif
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
if (keywordToken == "key") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseKey(); // 解析key
if (status) return status;
} else if (keywordToken == "axis") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseAxis();// 解析axis
if (status) return status;
} else if (keywordToken == "led") {
mTokenizer->skipDelimiters(WHITESPACE);
status_t status = parseLed();// 解析led事件
if (status) return status;
} else {
ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(),
keywordToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
ALOGE("%s: Expected end of line or trailing comment, got '%s'.",
mTokenizer->getLocation().string(),
mTokenizer->peekRemainderOfLine().string());
return BAD_VALUE;
}
}
mTokenizer->nextLine(); // 每次解析一行,每行代表一个配置信息;
}
return NO_ERROR;
}
解析key的方法:
status_t KeyLayoutMap::Parser::parseKey() {
String8 codeToken = mTokenizer->nextToken(WHITESPACE); // scanCode,数据示例:key 583 ASSIST
bool mapUsage = false;
if (codeToken == "usage") {// 是否为usage
mapUsage = true;
mTokenizer->skipDelimiters(WHITESPACE);
codeToken = mTokenizer->nextToken(WHITESPACE); // 若为usage,则scanCode需要再读一位,数据示例:key usage 0x0c006F BRIGHTNESS_UP
}
char* end;
int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); // String转为int;
if (*end) {
ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(),
mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
}
KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; // 如果是usage,则用mKeysByUsageCode,否则用正常的mKeysByScanCode
if (map.indexOfKey(code) >= 0) { // 已有此scanCode对应配置,则不需要再解析
ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
mapUsage ? "usage" : "scan code", codeToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); // 获取keyCode对应字符串,如BRIGHTNESS_UP、VOLUME_DOWN、F11、A、B等样式
int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); // 将keyCode字符串转换为对应的keyCode,需要分析下getKeyCodeByLabel方法;
if (!keyCode) {
ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(),
keyCodeToken.string());
return BAD_VALUE;
}
uint32_t flags = 0;
for (;;) { // 获取flag定义,猜测可能是这样的数据配置:key 583 ASSIST FUNCTION,暂不分析,一般为null
mTokenizer->skipDelimiters(WHITESPACE);
if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break;
String8 flagToken = mTokenizer->nextToken(WHITESPACE);
uint32_t flag = getKeyFlagByLabel(flagToken.string());
if (!flag) {
ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(),
flagToken.string());
return BAD_VALUE;
}
if (flags & flag) {
ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(),
flagToken.string());
return BAD_VALUE;
}
flags |= flag;
}
#if DEBUG_PARSER
ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
mapUsage ? "usage" : "scan code", code, keyCode, flags);
#endif
Key key;
key.keyCode = keyCode;
key.flags = flags;
// 将scanCode和Key对象的对应关系,添加到mKeysByScanCode中;
// 这样的话,从驱动上报上来的keyScanCode值,就可以找到对应的keyCode数据了;
map.add(code, key);
return NO_ERROR;
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/include/input/InputEventLabels.h
static inline int32_t getKeyCodeByLabel(const char* label) {
return int32_t(lookupValueByLabel(label, KEYCODES)); // 从KEYCODES中找label数据
}
static int lookupValueByLabel(const char* literal, const InputEventLabel *list) {
while (list->literal) {
if (strcmp(literal, list->literal) == 0) {
return list->value;
}
list++;
}
return list->value;
}
// KEYCODES是一组递增的常量值;
// UNKNOWN是、SOFT_LEFT等是在keycodes.h中定义的int类型数据;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/include/input/InputEventLabels.h
#define DEFINE_KEYCODE(key) { #key, AKEYCODE_##key }//宏定义键值对;
struct InputEventLabel {
const char *literal;//名称
int value;// keycode
};
static const InputEventLabel KEYCODES[] = {
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
DEFINE_KEYCODE(UNKNOWN),
DEFINE_KEYCODE(SOFT_LEFT),
DEFINE_KEYCODE(SOFT_RIGHT),
DEFINE_KEYCODE(HOME),
DEFINE_KEYCODE(BACK),
DEFINE_KEYCODE(CALL),
DEFINE_KEYCODE(ENDCALL),
DEFINE_KEYCODE(0),
DEFINE_KEYCODE(1),
......
DEFINE_KEYCODE(SYSTEM_NAVIGATION_DOWN),
DEFINE_KEYCODE(SYSTEM_NAVIGATION_LEFT),
DEFINE_KEYCODE(SYSTEM_NAVIGATION_RIGHT),
DEFINE_KEYCODE(ALL_APPS),
DEFINE_KEYCODE(REFRESH),
DEFINE_KEYCODE(THUMBS_UP),
DEFINE_KEYCODE(THUMBS_DOWN),
DEFINE_KEYCODE(PROFILE_SWITCH),
{ nullptr, 0 }
};
// 真正的keyCode定义的地方:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/include/android/keycodes.h
enum {
/** Unknown key code. */
AKEYCODE_UNKNOWN = 0,
/** Soft Left key.
* Usually situated below the display on phones and used as a multi-function
* feature key for selecting a software defined function shown on the bottom left
* of the display. */
AKEYCODE_SOFT_LEFT = 1,
/** Soft Right key.
* Usually situated below the display on phones and used as a multi-function
* feature key for selecting a software defined function shown on the bottom right
* of the display. */
AKEYCODE_SOFT_RIGHT = 2,
/** Home key.
* This key is handled by the framework and is never delivered to applications. */
AKEYCODE_HOME = 3,
/** Back key. */
AKEYCODE_BACK = 4,
/** Call key. */
AKEYCODE_CALL = 5,
/** End Call key. */
AKEYCODE_ENDCALL = 6,
......
AKEYCODE_THUMBS_DOWN = 287,
/** Used to switch current account that is consuming content.
* May be consumed by system to switch current viewer profile. */
AKEYCODE_PROFILE_SWITCH = 288
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
};
scanDevicesLocked-loadKeyMapLocked方法结束,这部分代码比较长,主要是将按键相关配置信息读取到内存中;
接下来看1.1.3-scanDevicesLocked-addDeviceLocked(device)方法;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
// KeyedVector<int32_t, Device*> mDevices;
// Device* mOpeningDevices;
// Device* mClosingDevices;
void EventHub::addDeviceLocked(Device* device) {
mDevices.add(device->id, device); // 将设备加入EventHub的mDevices中;
device->next = mOpeningDevices;
mOpeningDevices = device; // 将此device加入mOpeningDevices
}
至此scanDevicesLocked方法完成,device的各种驱动信息设备信息、配置信息都已加载到内存中;
来分析InputReader处理读取到的数据的流程,以按键信息为例; 根据之前的分析可知,input_event中的信息,包含以下数据:
event->when = processEventTimestamp(iev);
event->deviceId = deviceId;
event->type = iev.type;
event->code = iev.code;
event->value = iev.value;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
// 若type小于FIRST_SYNTHETIC_EVENT,则是输入事件;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||
rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
#if DEBUG_RAW_EVENTS
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
#endif
// 处理输入时间;
processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
// 若类型是新增设备,则处理addDeviceLocked;
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
}
此处有两个关键方法,设备开机后,会扫描设备,并触发addDeviceLocked,等有输入事件后,会执行processEventsForDeviceLocked方法:
2.1,processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
2.2,addDeviceLocked(rawEvent->when, rawEvent->deviceId);
先来分析addDeviceLocked方法,会将EventHub中的mDevices转化为InputDevice;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::addDeviceLocked(nsecs_t when, int32_t eventHubId) {
if (mDevices.find(eventHubId) != mDevices.end()) {
ALOGW("Ignoring spurious device added event for eventHubId %d.", eventHubId);
return;
}
InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
// 根据EventHub中的Device的identifier,创建InputReader中的InputDevice对象;
// eventHubId是EventHud中的deviceId;
// 此处会创建InputDevice对象,并将device中的classes赋值给InputDevice,然后在InputDevice中创建了处理各种输入事件的mapper对象;
std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
// 从EventHub-device中读取配置信息,并赋值给InputDevice,此处不进行分析;
device->configure(when, &mConfig, 0);
// 重置mapper信息,此处不进行分析
device->reset(when);
if (device->isIgnored()) {
...
} else {
ALOGI("Device added: id=%d, eventHubId=%d, name='%s', descriptor='%s',sources=0x%08x",
device->getId(), eventHubId, identifier.name.c_str(), identifier.descriptor.c_str(),
device->getSources());
}
// 将创建的InputDevice-device和eventHubId进行关联,上报上来的RawEvent里,包含了eventHubId;
// 根据eventHubId查找InputDevice的map;
mDevices.emplace(eventHubId, device);
// 根据InputDevice查找eventHubId的数据结构,相当于可以双向查找,比较快速;
// Add device to device to EventHub ids map.
const auto mapIt = mDeviceToEventHubIdsMap.find(device);
if (mapIt == mDeviceToEventHubIdsMap.end()) {
std::vector<int32_t> ids = {eventHubId};
mDeviceToEventHubIdsMap.emplace(device, ids);
} else {
mapIt->second.push_back(eventHubId);
}
// return ++mGeneration;
bumpGenerationLocked();
if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
notifyExternalStylusPresenceChanged();
}
}
来分析InputReader-addDeviceLocked-createDeviceLocked方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/include/InputReader.h
std::unordered_map<int32_t /*eventHubId*/, std::shared_ptr<InputDevice>> mDevices; // eventHubId和InputDevice的对应关系;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReader.cpp
std::shared_ptr<InputDevice> InputReader::createDeviceLocked(
int32_t eventHubId, const InputDeviceIdentifier& identifier) {
// 查找此设备是否已存在于InputReader-mDevices中;
auto deviceIt = std::find_if(mDevices.begin(), mDevices.end(), [identifier](auto& devicePair) {
return devicePair.second->getDescriptor().size() && identifier.descriptor.size() &&
devicePair.second->getDescriptor() == identifier.descriptor;
});
std::shared_ptr<InputDevice> device;
if (deviceIt != mDevices.end()) { // 若deviceIt不为空
device = deviceIt->second; // devce指向deviceIt的值
} else {
// deviceId递增,mContext是InputReaderContext对象,持有InputReader的引用;
int32_t deviceId = (eventHubId < END_RESERVED_ID) ? eventHubId : nextInputDeviceIdLocked();
device = std::make_shared<InputDevice>(&mContext, deviceId, bumpGenerationLocked(),
identifier);
}
// 注意此处关键方法,创建了多个种类的输入事件对应的mapper;
// 待会儿处理事件的时候会用得到;
device->addEventHubDevice(eventHubId);
return device;
}
InputDevice构造方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputDevice.cpp
InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
const InputDeviceIdentifier& identifier)
: mContext(context),
mId(id),
mGeneration(generation),
mControllerNumber(0),
mIdentifier(identifier), // EventHub里的InputDeviceIdentifier
mClasses(0),
mSources(0),
mIsExternal(false),
mHasMic(false),
mDropUntilNextSync(false) {}
addEventHubDevice关键方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) {
// 若存在eventHubId对应的InputDevice,则不进行重复添加;
if (mDevices.find(eventHubId) != mDevices.end()) {
return;
}
// 创建InputDeviceContext,保存了当前InputDevice,以及eventHubId;
/* 注意此处构造方法,InputDeviceContext中的mContext,指向的是device.getContext(),也就是InputReader中的ContextImpl,InputDeviceContext的构造方法如下;
InputDeviceContext::InputDeviceContext(InputDevice& device, int32_t eventHubId)
: mDevice(device),
mContext(device.getContext()),
// 从InputReader中获取EventHub对象;
mEventHub(device.getContext()->getEventHub()),
mId(eventHubId),
mDeviceId(device.getId()) {}
*/
std::unique_ptr<InputDeviceContext> contextPtr(new InputDeviceContext(*this, eventHubId));
// 输入设备的类型,如鼠标,键盘,蓝牙手柄等类型;
uint32_t classes = contextPtr->getDeviceClasses();
// 根据以上的classes类型,创建各种类型的***Mapper对象,并保存到mappers中
std::vector<std::unique_ptr<InputMapper>> mappers;
// populateMappers默认为true,声明:void addEventHubDevice(int32_t eventHubId, bool populateMappers = true);
// Check if we should skip population
if (!populateMappers) {
// 创建了一个DevicePair,contextPtr+mappers对应关系,然后通过eventHubId跟此DevicePair进行一一关联;
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
return;
}
// 创建Switch类型的mapper,并保存早mappers中;
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
mappers.push_back(std::make_unique<SwitchInputMapper>(*contextPtr));
}
// 创建Rotary滚轮类型的mapper,并保存早mappers中;
// Scroll wheel-like devices.
if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(*contextPtr));
}
// Vibrator-like devices.
if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
mappers.push_back(std::make_unique<VibratorInputMapper>(*contextPtr));
}
// Keyboard-like devices.
uint32_t keyboardSource = 0;
int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
keyboardSource |= AINPUT_SOURCE_KEYBOARD;
}
if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
}
if (classes & INPUT_DEVICE_CLASS_DPAD) {
keyboardSource |= AINPUT_SOURCE_DPAD;
}
if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
keyboardSource |= AINPUT_SOURCE_GAMEPAD;
}
// 创Key按键类型的mapper,并保存早mappers中;
if (keyboardSource != 0) {
mappers.push_back(
std::make_unique<KeyboardInputMapper>(*contextPtr, keyboardSource, keyboardType));
}
// Cursor-like devices.
if (classes & INPUT_DEVICE_CLASS_CURSOR) {
mappers.push_back(std::make_unique<CursorInputMapper>(*contextPtr));
}
// Touchscreens and touchpad devices.
if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
mappers.push_back(std::make_unique<MultiTouchInputMapper>(*contextPtr));
} else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
mappers.push_back(std::make_unique<SingleTouchInputMapper>(*contextPtr));
}
// Joystick-like devices.
if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
mappers.push_back(std::make_unique<JoystickInputMapper>(*contextPtr));
}
// External stylus-like devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
mappers.push_back(std::make_unique<ExternalStylusInputMapper>(*contextPtr));
}
// .h中,mDevices相关的声明如下;
// std::make_pair创建了一个DevicePair对,contextPtr+mappers对应关系,然后通过eventHubId跟此DevicePair进行一一关联;
// map from eventHubId to device context and mappers
// using MapperVector = std::vector<std::unique_ptr<InputMapper>>;
// using DevicePair = std::pair<std::unique_ptr<InputDeviceContext>, MapperVector>;
// std::unordered_map<int32_t, DevicePair> mDevices;
// insert the context into the devices set
mDevices.insert({eventHubId, std::make_pair(std::move(contextPtr), std::move(mappers))});
// Must change generation to flag this device as changed
bumpGeneration();
}
来看下待会儿要分析的KeyboardInputMapper的构造方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.h
class KeyboardInputMapper : public InputMapper {
namespace android {
class KeyboardInputMapper : public InputMapper {
public:
KeyboardInputMapper(InputDeviceContext& deviceContext, uint32_t source, int32_t keyboardType);
virtual ~KeyboardInputMapper();
virtual uint32_t getSources() override;
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
virtual void dump(std::string& dump) override;
virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
uint32_t changes) override;
virtual void reset(nsecs_t when) override;
virtual void process(const RawEvent* rawEvent) override; // 处理事件
......
private:
// The current viewport.
std::optional<DisplayViewport> mViewport;
struct KeyDown {
int32_t keyCode;
int32_t scanCode;
};
uint32_t mSource;
int32_t mKeyboardType;
std::vector<KeyDown> mKeyDowns; // keys that are down
int32_t mMetaState;
nsecs_t mDownTime; // time of most recent key down
......
void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode); // 处理按键
};
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext, uint32_t source, int32_t keyboardType)
: InputMapper(deviceContext), mSource(source), mKeyboardType(keyboardType) {}
来看下父类InputMapper的构造;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/InputMapper.h
// 此处返回的是InputReaderContext中的mContext对象,也就是InputReader对象;
inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
// 调用的是InputReader中的getListener方法;
// 此listener-QueuedInputListener方法封装了InputClassifier对象,而InputClassifier对象持有InputDispatcher对象的应用;
// 通过这样的联系,将InputReader和InputDispatcher两个关键对象联系了起来;
inline InputListenerInterface* getListener() { return getContext()->getListener(); }
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/InputMapper.cpp
InputMapper::InputMapper(InputDeviceContext& deviceContext) : mDeviceContext(deviceContext) {}
至此addDeviceLocked方法分析完毕;
总结一下,此方法是根据EventHub中的device信息,创建了InputDevice对象,此对象中持有EventHubId,还有process和processKey等关键方法;
InputDevice持有的context,还持有InputReader的对象,以及InputClassifier对象,可以将输入事件传递给InputDispatcher!
此处逻辑的结束是个分水岭,上面相当于IMS的初始化流程! 下面的代码,涉及事件分发和处理的关键流程!
4.3.5.2 InputReader处理和传递输入数据流程
来分析重要的processEventsForDeviceLocked(deviceId, rawEvent, batchSize);方法,此处涉及将输入事件交给InputDispatcher进行处理的关键流程;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReader.cpp
void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, size_t count) {
auto deviceIt = mDevices.find(eventHubId); // 根据eventHubId找到对应的InputDevice;
if (deviceIt == mDevices.end()) {
ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
return;
}
std::shared_ptr<InputDevice>& device = deviceIt->second;
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return;
}
// 使用每个InputDevice的process方法,来处理此设备的对应事件;
device->process(rawEvents, count);
}
InputReader中的InputDevice,处理事件的方法如下:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputDevice.cpp
void InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
// 遍历每一个RawEvent对象;
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
.......
if (mDropUntilNextSync) {
......
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
......
} else {
// 上面根据InputDevice的类型,创建了多个mapper对象,此处会循环调用mapper的process方法,来处理对应事件;
// 这里process方法为什么不取返回值?如果一个mapper处理成功后,还需要另一个mapper处理吗
for_each_mapper_in_subdevice(rawEvent->deviceId, [rawEvent](InputMapper& mapper) {
mapper.process(rawEvent);
});
}
--count;
}
}
根据之前创建InputDevice的代码可知,InputMapper有多个子类方法;
我们这里查看的是按键事件的处理,来看下KeyboardInputMapper的process方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
void KeyboardInputMapper::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EV_KEY: {
int32_t scanCode = rawEvent->code;
int32_t usageCode = mCurrentHidUsage;
mCurrentHidUsage = 0;
// 是按键或游戏输入设备,则处理此按键
if (isKeyboardOrGamepadKey(scanCode)) {
processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
}
break;
}
case EV_MSC: {
if (rawEvent->code == MSC_SCAN) {
mCurrentHidUsage = rawEvent->value;
}
break;
}
case EV_SYN: {
if (rawEvent->code == SYN_REPORT) {
mCurrentHidUsage = 0;
}
}
}
}
bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
return scanCode < BTN_MOUSE || scanCode >= BTN_WHEEL ||
(scanCode >= BTN_MISC && scanCode < BTN_MOUSE) ||
(scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
}
继续分析processKey方法:
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
int32_t keyCode; // 待确认的keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
// 根据scanCode或usageCode,获取keyCode,还记得我们查看的.idc,.kl等配置信息吗,这里就派上了用场;
if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
&policyFlags)) {
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
if (down) {
// Rotate key codes according to orientation if needed.
if (mParameters.orientationAware) {
keyCode = rotateKeyCode(keyCode, getOrientation());
}
// Add key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// key repeat, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[keyDownIndex].keyCode;
} else {
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
return;
}
if (policyFlags & POLICY_FLAG_GESTURE) {
getDeviceContext().cancelTouch(when);
}
KeyDown keyDown;
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
mKeyDowns.push_back(keyDown);
}
mDownTime = when;
} else {
// Remove key down.
ssize_t keyDownIndex = findKeyDown(scanCode);
if (keyDownIndex >= 0) {
// key up, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[keyDownIndex].keyCode;
mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
} else {
// key was not actually down
ALOGI("Dropping key up from device %s because the key was not down. "
"keyCode=%d, scanCode=%d",
getDeviceName().c_str(), keyCode, scanCode);
return;
}
}
if (updateMetaStateIfNeeded(keyCode, down)) {
// If global meta state changed send it along with the key.
// If it has not changed then we'll use what keymap gave us,
// since key replacement logic might temporarily reset a few
// meta bits for given key.
keyMetaState = mMetaState;
}
nsecs_t downTime = mDownTime;
// Key down on external an keyboard should wake the device.
// We don't do this for internal keyboards to prevent them from waking up in your pocket.
// For internal keyboards and devices for which the default wake behavior is explicitly
// prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
// wake key individually.
// TODO: Use the input device configuration to control this behavior more finely.
if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
!isMediaKey(keyCode)) {
policyFlags |= POLICY_FLAG_WAKE;
}
if (mParameters.handlesKeyRepeat) {
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
// 注意此处的继承关系,struct NotifyKeyArgs : public NotifyArgs
// NotifyArgs的函数实现在此目录:
// frameworks/native/services/inputflinger/InputListener.cpp
// frameworks/native/services/inputflinger/include/InputListener.h
NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
}
上面有两个关键调用,mapKey是获取scanCode对应的keyCode,notifyKey会将NotifyKeyArgs分发给InputDispatcher:
2.1.1:getDeviceContext().mapKey(…);
2.1.2:NotifyKeyArgs args(…);getListener()->notifyKey(&args);
先来分析mapKey方法,再去分析getListener()->notifyKey(&args);
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/include/InputDevice.h
inline status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
return mEventHub->mapKey(mId, scanCode, usageCode, metaState, outKeycode, outMetaState, outFlags);
}
此处兜兜转转,又回到了EventHub中,因为只有EventHub中的device,才持有此输入设备对应的kl和kcm配置信息;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/EventHub.cpp
status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState, int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
status_t status = NAME_NOT_FOUND;
if (device) {
// Check the key character map first.
sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
if (kcm != nullptr) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0;
status = NO_ERROR;
}
}
// 通过.kl文件的配置,通过scancode找到keycode
// Check the key layout next.
if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
if (!device->keyMap.keyLayoutMap->mapKey(scanCode, usageCode, outKeycode, outFlags)) {
status = NO_ERROR;
}
}
if (status == NO_ERROR) {
if (kcm != nullptr) {
kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
} else {
*outMetaState = metaState;
}
}
}
if (status != NO_ERROR) {
*outKeycode = 0;
*outFlags = 0;
*outMetaState = metaState;
}
return status;
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/KeyLayoutMap.cpp
status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode,
int32_t* outKeyCode, uint32_t* outFlags) const {
const Key* key = getKey(scanCode, usageCode); // 查找keycode
if (!key) {
....
}
*outKeyCode = key->keyCode; // 将keyCode赋值给outKeyCode
*outFlags = key->flags;
......
return NO_ERROR;
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/KeyLayoutMap.cpp
const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
if (usageCode) {
...
}
if (scanCode) {
// 从mKeysByScanCode中查找scanCode,若找到,则返回Key对象,mKeysByUsageCode的类型为:KeyedVector<int32_t, Key> mKeysByUsageCode;
ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
if (index >= 0) {
return &mKeysByScanCode.valueAt(index);
}
}
return nullptr;
}
至此,key的各种参数都已经拿到了,包括:scanCode,keyCode,action,deviceId,displayId等信息;
接下来分析key数据是如何传递到app层的;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
&policyFlags)) {
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
......
if (mParameters.handlesKeyRepeat) {
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(), policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/InputMapper.h
inline InputListenerInterface* getListener() { return getContext()->getListener(); }
// 这里getContext指向的是ContextImpl对象;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/mapper/InputMapper.h
inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }
inline InputListenerInterface* getListener() { return getContext()->getListener(); }
// 拿到QueuedInputListener-mQueuedListener对象
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/reader/InputReader.cpp
InputListenerInterface* InputReader::ContextImpl::getListener() {
return mReader->mQueuedListener.get();
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
traceEvent(__func__, args->id);
// 将NotifyKeyArgs加入mArgsQueue队列,等待消费;
mArgsQueue.push_back(new NotifyKeyArgs(*args));
}
#至此InputReader-loopOnce-processEventsLocked(mEventBuffer, count)方法完成;
这里对mEventBuffer中的原始数据进行了解析,将如按键数据解析为Key对应的上层数据,并加入了QueuedInputListener-mQueuedListener的mArgsQueue中,等待消费;
loopOnce中还有以下两处关键方法,notifyInputDevicesChanged方法不再分析,来看下关键流程mQueuedListener->flush().
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/InputListener.cpp
void QueuedInputListener::flush() {
size_t count = mArgsQueue.size();
// 循环调用mArgsQueue中的每一个NotifyArgs的notify方法,注意mInnerListener参数,是QueuedInputListener构造的入参,也就是InputClassifier对象;
for (size_t i = 0; i < count; i++) {
NotifyArgs* args = mArgsQueue[i];
args->notify(mInnerListener);
delete args;
}
mArgsQueue.clear();
}
QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) :
mInnerListener(innerListener) {
}
NotifyArgs有多个子类,其中就有之前创建的NotifyKeyArgs,所以此处notify调用的是NotifyKeyArgs的notify方法;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/InputListener.cpp
void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
listener->notifyKey(this);
}
listener就是QueuedInputListener中的mInnerListener对象,也就是InputClassifier对象;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/InputClassifier.cpp
void InputClassifier::notifyKey(const NotifyKeyArgs* args) {
// pass through
mListener->notifyKey(args);
}
4.3.5.3 InputDispatcher传递输入数据流程
根据上面章节的调用,notifyKey调用到了InputDispatcher的方法中;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/InputManager.cpp
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = createInputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
mReader = createInputReader(readerPolicy, mClassifier);
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/InputClassifier.cpp
InputClassifier::InputClassifier(const sp<InputListenerInterface>& listener)
: mListener(listener), mHalDeathRecipient(new HalDeathRecipient(*this)) {}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
......
if (!validateKeyEvent(args->action)) {
return;
}
uint32_t policyFlags = ...
policyFlags |= POLICY_FLAG_TRUSTED;
int32_t keyCode = args->keyCode;
accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);
// 将NotifyKeyArgs数据复制到KeyEvent中;
KeyEvent event;
event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
args->action, flags, keyCode, args->scanCode, metaState, repeatCount,
args->downTime, args->eventTime);
android::base::Timer t;
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
std::to_string(t.duration().count()).c_str());
}
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
// InputManagerService过滤并消费掉了此事件,不需要传给应用层;
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
// 将NotifyKeyArgs数据复制到KeyEntry中,并加入缓冲队列,等待消费;
KeyEntry* newEntry =
new KeyEntry(args->id, args->eventTime, args->deviceId, args->source,
args->displayId, policyFlags, args->action, flags, keyCode,
args->scanCode, metaState, repeatCount, args->downTime);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
// 唤醒消费队列dispatchOnce方法;
if (needWake) {
mLooper->wake();
}
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
// 若队列为空,则需要唤醒;
bool needWake = mInboundQueue.empty();
// 加入mInboundQueue队列,等待dispatchOnce方法消费此队列中的内容;
mInboundQueue.push_back(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::Type::KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*entry);
if (isAppSwitchKeyEvent(keyEntry)) {
if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
.......
mAppSwitchDueTime = keyEntry.eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
}
}
}
break;
}
case EventEntry::Type::MOTION: {
if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(*entry))) {
mNextUnblockedEvent = entry;
needWake = true;
}
break;
}
case EventEntry::Type::FOCUS: {
LOG_ALWAYS_FATAL("Focus events should be inserted using enqueueFocusEventLocked");
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
// nothing to do
break;
}
}
return needWake;
}
至此生产者模式已经生产出了输入事件,添加到了缓冲队列mInboundQueue中,并唤醒了消费队列;
接下来看消费队列如何消费事件并传递给app层的:
/home/chen/disk2/project/aosp/r_aosp/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();
// 开始消费mInboundQueue中的数据;
// 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;
}
// 检查是否存在事件消费的ANR行为;
// 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();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
来分析dispatchOnceInnerLocked方法,是如何消费事件的;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
// Reset the key repeat timer whenever normal dispatch is suspended while the
// device is in a non-interactive state. This is to ensure that we abort a key
// repeat if the device is just coming out of sleep.
if (!mDispatchEnabled) {
resetKeyRepeatLocked();
}
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
if (DEBUG_FOCUS) {
ALOGD("Dispatch frozen. Waiting some more.");
}
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
if (mInboundQueue.empty()) {
......
} else {
// 拿出队列中的首个事件;
// Inbound queue has at least one entry.
mPendingEvent = mInboundQueue.front();
mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
......
}
// 拿到了首个输入事件mPendingEvent,准备传递;
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != nullptr);
bool done = false;
DropReason dropReason = DropReason::NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
dropReason = DropReason::POLICY;
} else if (!mDispatchEnabled) {
dropReason = DropReason::DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = nullptr;
}
switch (mPendingEvent->type) {
case EventEntry::Type::CONFIGURATION_CHANGED: {
...
break;
}
case EventEntry::Type::DEVICE_RESET: {
...
break;
}
case EventEntry::Type::FOCUS: {
...
break;
}
case EventEntry::Type::KEY: {
KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
if (isAppSwitchDue) {
if (isAppSwitchKeyEvent(*typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DropReason::NOT_DROPPED) {
dropReason = DropReason::APP_SWITCH;
}
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
// 消费此按键事件;
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::Type::MOTION: {
MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
dropReason = DropReason::APP_SWITCH;
}
if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
dropReason = DropReason::STALE;
}
if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DropReason::BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
}
if (done) {
if (dropReason != DropReason::NOT_DROPPED) {
dropInboundEventLocked(*mPendingEvent, dropReason);
}
mLastDropReason = dropReason;
// 释放此事件,其实是添加到mRecentQueue中,可能是用于判断ANR?
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
// 方法结束,进入下一dispatchOnce循环,再次消费front的输入事件;
}
来分析dispatchKeyLocked方法;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
if (!entry->dispatchInProgress) {
......
entry->dispatchInProgress = true;
logOutboundKeyDetails("dispatchKey - ", *entry);
}
// Handle case where the policy asked us to try again later last time.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
if (currentTime < entry->interceptKeyWakeupTime) {
if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
*nextWakeupTime = entry->interceptKeyWakeupTime;
}
return false; // wait until next wakeup
}
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
entry->interceptKeyWakeupTime = 0;
}
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
......
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
if (*dropReason == DropReason::NOT_DROPPED) {
*dropReason = DropReason::POLICY;
}
}
// Clean up if dropping the event.
if (*dropReason != DropReason::NOT_DROPPED) {
setInjectionResult(entry, *dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
mReporter->reportDroppedKey(entry->id);
return true;
}
// 查找需要消费输入事件的window对象,存入inputTargets中;
// Identify targets.
std::vector<InputTarget> inputTargets;
int32_t injectionResult =
findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResult(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
// Add monitor channels from event's or focused display.
addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));
// Dispatch the key.
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
上面有两个关键方法要调查,方法1要查找消费此事件的windowTarget和InputChannel,然后方法2-dispatchEventLocked将事件传递给app的某一个window:
1,findFocusedWindowTargetsLocked 2,dispatchEventLocked
来分析findFocusedWindowTargetsLocked;
在分析findFocusedWindowTargetsLocked之前,来看下InputTarget数据结构,可以看到InputTarget包含了sp inputChannel对象,inputChannel能够把数据发给app端的inputChannel:
struct InputTarget {
enum {
/* This flag indicates that the event is being delivered to a foreground application. */
FLAG_FOREGROUND = 1 << 0,
/* This flag indicates that the MotionEvent falls within the area of the target
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */
FLAG_WINDOW_IS_OBSCURED = 1 << 1,
...
/* Mask for all dispatch modes. */
FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS | FLAG_DISPATCH_AS_OUTSIDE |
FLAG_DISPATCH_AS_HOVER_ENTER | FLAG_DISPATCH_AS_HOVER_EXIT |
FLAG_DISPATCH_AS_SLIPPERY_EXIT | FLAG_DISPATCH_AS_SLIPPERY_ENTER,
/* This flag indicates that the target of a MotionEvent is partly or wholly
* obscured by another visible window above it. The motion event should be
* delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED. */
FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
};
// 要传入数据的InputChannel对象;
// The input channel to be targeted.
sp<InputChannel> inputChannel;
// Flags for the input target.
int32_t flags = 0;
// Scaling factor to apply to MotionEvent as it is delivered.
// (ignored for KeyEvents)
float globalScaleFactor = 1.0f;
// The subset of pointer ids to include in motion events dispatched to this input target
// if FLAG_SPLIT is set.
BitSet32 pointerIds;
// The data is stored by the pointerId. Use the bit position of pointerIds to look up
// PointerInfo per pointerId.
PointerInfo pointerInfos[MAX_POINTERS];
...
};
std::string dispatchModeToString(int32_t dispatchMode);
} // namespace android::inputdispatcher
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry& entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
std::string reason;
// 获取输入事件对应的displayId,以便找到此display上的focusedWindowHandle。
int32_t displayId = getTargetDisplayId(entry);
// 根据displayId查找焦点window和焦点应用程序, mFocusedWindowHandlesByDisplay是一个map类型的数据结构,key为displayId;
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
sp<InputApplicationHandle> focusedApplicationHandle =
getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
// If there is no currently focused window and no focused application
// then drop the event.
if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) {
ALOGI("Dropping %s event because there is no focused window or focused application in "
"display %" PRId32 ".",
EventEntry::typeToString(entry.type), displayId);
return INPUT_EVENT_INJECTION_FAILED;
}
// Compatibility behavior: raise ANR if there is a focused application, but no focused window.
// Only start counting when we have a focused event to dispatch. The ANR is canceled if we
// start interacting with another application via touch (app switch). This code can be removed
// if the "no focused window ANR" is moved to the policy. Input doesn't know whether
// an app is expected to have a focused window.
if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) {
......
}
// we have a valid, non-null focused window
resetNoFocusedWindowTimeoutLocked();
// Check permissions.
if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
return INPUT_EVENT_INJECTION_PERMISSION_DENIED;
}
if (focusedWindowHandle->getInfo()->paused) {
ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());
return INPUT_EVENT_INJECTION_PENDING;
}
// If the event is a key event, then we must wait for all previous events to
// complete before delivering it because previous events may have the
// side-effect of transferring focus to a different window and we want to
// ensure that the following keys are sent to the new window.
//
// Suppose the user touches a button in a window then immediately presses "A".
// If the button causes a pop-up window to appear then we want to ensure that
// the "A" key is delivered to the new pop-up window. This is because users
// often anticipate pending UI changes when typing on a keyboard.
// To obtain this behavior, we must serialize key events with respect to all
// prior input events.
if (entry.type == EventEntry::Type::KEY) {
if (shouldWaitToSendKeyLocked(currentTime, focusedWindowHandle->getName().c_str())) {
*nextWakeupTime = *mKeyIsWaitingForEventsTimeout;
return INPUT_EVENT_INJECTION_PENDING;
}
}
// 将focusedWindowHandle添加到inputTargets集合中;
// Success! Output targets.
addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0), inputTargets);
// Done.
return INPUT_EVENT_INJECTION_SUCCEEDED;
}
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
/**
* Get the display id that the given event should go to. If this event specifies a valid display id,
* then it should be dispatched to that display. Otherwise, the event goes to the focused display.
* Focused display is the display that the user most recently interacted with.
*/
int32_t InputDispatcher::getTargetDisplayId(const EventEntry& entry) {
int32_t displayId;
switch (entry.type) {
case EventEntry::Type::KEY: {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
displayId = keyEntry.displayId;
break;
}
case EventEntry::Type::MOTION: {
const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);
displayId = motionEntry.displayId;
break;
}
case EventEntry::Type::FOCUS:
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
ALOGE("%s events do not have a target display", EventEntry::typeToString(entry.type));
return ADISPLAY_ID_NONE;
}
}
// 若输入事件未指定屏幕id,则返回焦点屏幕id,即用户最近操作的屏幕;
return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId;
}
map类型的键值对,保存了焦点window和焦点app;
在应用程序ViewRootImpl.addView时,会将焦点窗口传入此处并保存下来,此处逻辑不再赘述;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.h
// Focus tracking for keys, trackball, etc. 屏幕id和InputWindowHandle的对应关系;
std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay
GUARDED_BY(mLock);
// Focused applications.
std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay
GUARDED_BY(mLock);
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
int32_t targetFlags, BitSet32 pointerIds,
std::vector<InputTarget>& inputTargets) {
std::vector<InputTarget>::iterator it =
std::find_if(inputTargets.begin(), inputTargets.end(),
[&windowHandle](const InputTarget& inputTarget) {
return inputTarget.inputChannel->getConnectionToken() ==
windowHandle->getToken();
});
const InputWindowInfo* windowInfo = windowHandle->getInfo();
if (it == inputTargets.end()) {
InputTarget inputTarget;
// 根据token获取InputChannel,token和InputChannel的键值对map数据,在mInputChannelsByToken中保存。
sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
if (inputChannel == nullptr) {
ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
return;
}
// 将inputChannel等相关信息,保存到inputTarget中;
inputTarget.inputChannel = inputChannel;
inputTarget.flags = targetFlags;
inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
inputTargets.push_back(inputTarget);
it = inputTargets.end() - 1;
}
ALOG_ASSERT(it->flags == targetFlags);
ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);
it->addPointers(pointerIds, -windowInfo->frameLeft, -windowInfo->frameTop,
windowInfo->windowXScale, windowInfo->windowYScale);
}
至此findFocusedWindowTargetsLocked分析完毕,是查找焦点窗口对应的InputChannel,并保存到inputTargets中;
4.3.5.3 InputChannel传递输入数据
来看下如何将Event输入数据,通过dispatchEventLocked方法,传递给InputChannel。
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
const std::vector<InputTarget>& inputTargets) {
......
for (const InputTarget& inputTarget : inputTargets) {
// 根据inputTarget.inputChannel的token,获取对应的Connection?
sp<Connection> connection =
getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
if (connection != nullptr) {
prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
} else {
if (DEBUG_FOCUS) {
ALOGD("Dropping event delivery to target with channel '%s' because it "
"is no longer registered with the input dispatcher.",
inputTarget.inputChannel->getName().c_str());
}
}
}
}
疑问:此处为什么要通过inputChannel的token,获取connection对象?inputTarget中已持有inputChannel,已经可以传输数据了啊?
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
sp<Connection> InputDispatcher::getConnectionLocked(const sp<IBinder>& inputConnectionToken) const {
if (inputConnectionToken == nullptr) {
return nullptr;
}
for (const auto& pair : mConnectionsByFd) {
const sp<Connection>& connection = pair.second;
if (connection->inputChannel->getConnectionToken() == inputConnectionToken) {
return connection;
}
}
return nullptr;
}
来看下eventEntry开始传输的最后处理流程;
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
...
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
....
return;
}
// Split a motion event if needed.
if (inputTarget.flags & InputTarget::FLAG_SPLIT) {
...
}
// Not splitting. Enqueue dispatch entries for the event as is.
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
enqueueDispatchEntryLocked将要传输的eventEntry,添加到connection的outboundQueue队列中;
然后通过startDispatchCycleLocked方法,将输入对象传递给app侧;
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget) {
...
bool wasEmpty = connection->outboundQueue.empty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
EventEntry* eventEntry,
const InputTarget& inputTarget,
int32_t dispatchMode) {
...
int32_t inputTargetFlags = inputTarget.flags;
if (!(inputTargetFlags & dispatchMode)) {
return;
}
inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;
// This is a new event.
// Enqueue a new dispatch entry onto the outbound queue for this connection.
std::unique_ptr<DispatchEntry> dispatchEntry =
createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
// different EventEntry than what was passed in.
EventEntry* newEntry = dispatchEntry->eventEntry;
// Apply target flags and update the connection's input state.
switch (newEntry->type) {
case EventEntry::Type::KEY: {
const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*newEntry);
dispatchEntry->resolvedEventId = keyEntry.id;
dispatchEntry->resolvedAction = keyEntry.action;
dispatchEntry->resolvedFlags = keyEntry.flags;
if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,
dispatchEntry->resolvedFlags)) {
...
return; // skip the inconsistent event
}
break;
}
case EventEntry::Type::MOTION: {
............
break;
}
case EventEntry::Type::FOCUS: {
break;
}
case EventEntry::Type::CONFIGURATION_CHANGED:
case EventEntry::Type::DEVICE_RESET: {
LOG_ALWAYS_FATAL("%s events should not go to apps",
EventEntry::typeToString(newEntry->type));
break;
}
}
// Remember that we are waiting for this dispatch to complete.
if (dispatchEntry->hasForegroundTarget()) {
incrementPendingForegroundDispatches(newEntry);
}
// 将eventEntry添加到connection->outboundQueue中;
// Enqueue the dispatch entry.
connection->outboundQueue.push_back(dispatchEntry.release());
traceOutboundQueueLength(connection);
}
来分析startDispatchCycleLocked方法,应该是将connection->outboundQueue发到app侧;
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
const sp<Connection>& connection) {
......
// outboundQueue队列不为空,则一直while循环;
while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
// 拿到队首的输入事件;
DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
const nsecs_t timeout =
getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
dispatchEntry->timeoutTime = currentTime + timeout;
// Publish the event.
status_t status;
EventEntry* eventEntry = dispatchEntry->eventEntry;
switch (eventEntry->type) {
case EventEntry::Type::KEY: {
const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
// 通过InputPublisher对象发布此输入事件给上层逻辑;
// Publish the key event.
status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId, keyEntry->deviceId, keyEntry->source, keyEntry->displayId, std::move(hmac), dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, keyEntry->keyCode, keyEntry->scanCode, keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, keyEntry->eventTime);
break;
}
case EventEntry::Type::MOTION: {
......
// Publish the motion event.
status = connection->inputPublisher
.publishMotionEvent(......
break;
}
case EventEntry::Type::FOCUS: {
......
}
// Check the result.
if (status) {
.........
return;
}
// 删除已发布的输入事件,并进入下一循环;
// Re-enqueue the event on the wait queue.
connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
connection->outboundQueue.end(),
dispatchEntry));
traceOutboundQueueLength(connection);
connection->waitQueue.push_back(dispatchEntry);
if (connection->responsive) {
mAnrTracker.insert(dispatchEntry->timeoutTime,
connection->inputChannel->getConnectionToken());
}
traceWaitQueueLength(connection);
}
}
// 最终会拿到App的对端InputChannel对象,并调用sendMessage方法,将数据通过InputChannel通道下发;
// 然后App端的InputChannel就能够读到输入数据,并响应对应的业务逻辑。
/home/chen/disk2/project/aosp/r_aosp/frameworks/native/libs/input/InputTransport.cpp
status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId,
int32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action,
int32_t flags, int32_t keyCode, int32_t scanCode,
int32_t metaState, int32_t repeatCount, nsecs_t downTime, nsecs_t eventTime) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")", mChannel->getName().c_str(), keyCode);
ATRACE_NAME(message.c_str());
}
if (DEBUG_TRANSPORT_ACTIONS) {
ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d, downTime=%" PRId64 ", eventTime=%" PRId64, mChannel->getName().c_str(), seq, deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
}
if (!seq) {
ALOGE("Attempted to publish a key event with sequence number 0.");
return BAD_VALUE;
}
InputMessage msg;
msg.header.type = InputMessage::Type::KEY;
msg.body.key.seq = seq;
msg.body.key.eventId = eventId;
msg.body.key.deviceId = deviceId;
msg.body.key.source = source;
msg.body.key.displayId = displayId;
msg.body.key.hmac = std::move(hmac);
msg.body.key.action = action;
msg.body.key.flags = flags;
msg.body.key.keyCode = keyCode;
msg.body.key.scanCode = scanCode;
msg.body.key.metaState = metaState;
msg.body.key.repeatCount = repeatCount;
msg.body.key.downTime = downTime;
msg.body.key.eventTime = eventTime;
return mChannel->sendMessage(&msg);
}
至此,system_server进程IMS模块,从驱动读取按键类型输入事件,并传递给App模块的流程已完成;
App侧读取并分发按键事件的流程在其他章节会继续介绍;
4.4 App接收和传递Input事件流程
另起一篇;