首页 > 其他分享 >【framework】InputChannel创建流程

【framework】InputChannel创建流程

时间:2023-03-19 17:22:52浏览次数:58  
标签:... InputChannel 流程 framework NativeInputChannel env android view

1 前言

IMS启动流程 中介绍了 IMS 在 Java 层和 Native 层的初始化流程,以及创建 NativeInputManager、InputManager、InputReader、InputDispatcher、EventHub 等对象过程;View添加过程 中介绍了从 WindowManagerImpl 的 addView() 方法到 WindowState、SurfaceSession 的创建流程;本文将介绍 InputChannel 在 Java 层和 Native 层的初始化流程。

InputChannel 本质是对 Socket 的封装,用于输入事件跨进程通讯。

​ 如图,浅蓝色的类是应用进程中执行的,深蓝色的类是在 system_server 进程中执行的;浅蓝色和深蓝色的都是 Java 层代码,绿色的是 JNI 层代码,紫色的是 Native 层代码。

img

2 Java 层 InputChannel 初始化流程

(1)addView

​ /frameworks/base/core/java/android/view/ViewRootImpl.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
	synchronized (this) {
		if (mView == null) {
			mView = view;
            ...
			if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
                //创建 InputChannel,构造方法中什么也没干
				mInputChannel = new InputChannel();
			}
			...
            //请求显示 View
            requestLayout();
			if ((mWindowAttributes.inputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
				mInputChannel = new InputChannel();
			}
            ...
			try {
				...
				res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), 
					mDisplay.getDisplayId(), mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, 
					mAttachInfo.mOutsets, mAttachInfo.mDisplayCutout, mInputChannel, mTempInsets);
				setFrame(mTmpFrame);
			}
			...
			if (mInputChannel != null) {
				if (mInputQueueCallback != null) {
					mInputQueue = new InputQueue();
					mInputQueueCallback.onInputQueueCreated(mInputQueue);
				}
                //创建 WindowInputEventReceiver
				mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
			}
		}
	}
}

​ 说明:在 setView 过程中,创建了 InputChannel,说明每个窗口对应一个 InputChannel,这里创建了一个空的 InputChannel,mWindowSession.addToDisplay() 将创建的 InputChannel 对象传给system_server 进程,并在 WindowState 中实现初始化。

(2)addToDisplay

​ /frameworks/base/services/core/java/com/android/server/wm/Session.java

public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, 
		int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, 
		DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState) {
    //mService 为 WMS
	return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, 
			outStableInsets, outOutsets, outDisplayCutout, outInputChannel, outInsetsState);
}

(3)addWindow

​ /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, Rect outOutsets, 
		DisplayCutout.ParcelableWrapper, InputChannel outInputChannel, InsetsState outInsetsState) {
	...
	synchronized (mGlobalLock) {
		...
		//创建 WindowState,说明每个根 View,都与一个 WindowState 一一对应
		final WindowState win = new WindowState(this, session, client, token, parentWindow, appOp[0], 
				seq, attrs, viewVisibility, session.mUid, session.mCanAddInternalSystemWindow);
		...
		if  (openInputChannels) {
			//打开 InputChannel
			win.openInputChannel(outInputChannel);
		}
		...
        win.attach(); //mSessions.add(win.mSession)
		mWindowMap.put(client.asBinder(), win);
        ...
        win.mToken.addWindow(win); //win.mToken.addChild(win, mWindowComparator)
        ...
	}
	...
	return res;
}

(4)openInputChannel

​ /frameworks/base/services/core/java/com/android/server/wm/WindowState.java

void openInputChannel(InputChannel outInputChannel) {
	...
	String name = getName();
	//创建 socketpair,nativeOpenInputChannelPair(name)
	InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
	mInputChannel = inputChannels[0]; //本地存留
	mClientChannel = inputChannels[1]; //返给应用进程
	mInputWindowHandle.token = mClient.asBinder();
	if (outInputChannel != null) {
		//nativeTransferTo(outInputChannel),将 outInputChannel 与 NativeInputChannel 绑定,mClientChannel 与 NativeInputChannel 解绑 
		mClientChannel.transferTo(outInputChannel);
		//nativeDispose(false),将 mClientChannel 与 NativeInputChannel 解绑,并清除对应 NativeInputChannel 
		mClientChannel.dispose();
		mClientChannel = null;
	}
	...
	//inputChannel.setToken(token);
	//nativeRegisterInputChannel(mPtr, inputChannel, Display.INVALID_DISPLAY),将 inputChannel 注入到 InputDispatcher 中
	mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());
}

​ openInputChannel() 方法中调用了如下 4 个JNI 层的方法:

  • nativeOpenInputChannelPair:创建 socket 客户端和服务端,并使用 InputChannel(Native 层) 封装;
  • nativeTransferTo:将 outInputChannel 与 NativeInputChannel 绑定,mClientChannel 与 NativeInputChannel 解绑;
  • nativeDispose:将 mClientChannel 与 NativeInputChannel 解绑,并清除对应 NativeInputChannel;
  • nativeRegisterInputChannel:将 inputChannel 注入到 InputDispatcher 中,并创建 Connection 对象。

3 Native 层 InputChannel 初始化流程

​ 本节主要介绍 WindowState 中调用的 InputChannel 和 IMS 中的 Native 方法,依次为:nativeOpenInputChannelPair、nativeTransferTo、nativeDispose、nativeRegisterInputChannel。

3.1 nativeOpenInputChannelPair 后续流程

​ InputChannel 的 openInputChannelPair() 方法调用了 JNI 层的 nativeOpenInputChannelPair() 方法,调用点如下。

//创建 socket 客户端和服务端,并使用 InputChannel(Native 层) 封装
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);

(1)gInputChannelMethods

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

static const JNINativeMethod gInputChannelMethods[] = {
    //Java 层调用的 nativeOpenInputChannelPair 方法对应 JNI 层的 android_view_InputChannel_nativeOpenInputChannelPair 方法
    { "nativeOpenInputChannelPair", "(Ljava/lang/String;)[Landroid/view/InputChannel;",
            (void*)android_view_InputChannel_nativeOpenInputChannelPair },
	//Java 层调用的 nativeDispose 方法对应 JNI 层的 android_view_InputChannel_nativeDispose 方法
    { "nativeDispose", "(Z)V",
            (void*)android_view_InputChannel_nativeDispose },
	//Java 层调用的 nativeTransferTo 方法对应 JNI 层的 android_view_InputChannel_nativeTransferTo 方法
    { "nativeTransferTo", "(Landroid/view/InputChannel;)V",
            (void*)android_view_InputChannel_nativeTransferTo },
    ...
};

(2)android_view_InputChannel_nativeOpenInputChannelPair

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

#include <input/InputTransport.h>

static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env, jclass clazz, jstring nameObj) {
    ...
    sp<InputChannel> serverChannel; //服务端 InputChannel
    sp<InputChannel> clientChannel; //客户端 InputChannel
    //创建 socketpair,并创建 Native 层的 InputChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
    ...
    jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
    ...
    jobject serverChannelObj = android_view_InputChannel_createInputChannel(env, std::make_unique<NativeInputChannel>(serverChannel));
    ...
    jobject clientChannelObj = android_view_InputChannel_createInputChannel(env, std::make_unique<NativeInputChannel>(clientChannel));
    ...
	//将 serverChannelObj、clientChannelObj 放入 channelPair
    env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
    env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
    return channelPair;
}

​ 说明:

  • inputTransport.h 中定义了抽象的 InputChannel 类,inputTransport.cpp 实现 inputTransport.h 中的抽象方法;
  • openInputChannelPair() 方法创建了socketpair,并创建了 Native 层的 InputChannel 对象,用于封装 socket;
  • std::make_unique(params)) 用于创建 T 类型对象,这里创建了 2 个 NativeInputChannel 对象,并将前面创建的 InputChannel(Native 层)对象注入;
  • android_view_InputChannel_createInputChannel() 方法将 JNI 层的 NativeInputChannel 对象封装为 Java 层的 InputChannel 对象;
  • 一个 Java 层的 InputChannel 对象,对应一个 JNI 层的 NativeInputChannel 对象,对应一个 Native 层的 InputChannel 对象。
//new NativeInputChannel(serverChannel)
std::make_unique<NativeInputChannel>(serverChannel)

//new NativeInputChannel(clientChannel)
std::make_unique<NativeInputChannel>(clientChannel)

(3)openInputChannelPair

​ /frameworks/native/libs/input/InputTransport.cpp

status_t InputChannel::openInputChannelPair(const std::string& name, sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
        ...
    }
    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));
	//serverChannelName = name + " (server)"
    outServerChannel = new InputChannel(serverChannelName, sockets[0]);
	//clientChannelName = name + " (client)"
    outClientChannel = new InputChannel(clientChannelName, sockets[1]);
    return OK;
}

(4)InputChannel

​ /frameworks/native/libs/input/InputTransport.cpp

InputChannel::InputChannel(const std::string& name, int fd) : 
    mName(name) {
	...
    setFd(fd);
}

void InputChannel::setFd(int fd) {
    ...
    mFd = fd;
    if (mFd > 0) {
        int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
        ...
    }
}

​ fcntl() 为 Linux 层函数,其作用是:根据文件描述词来操作文件的特性(Linux fcntl函数详解);InputChannel 的构造方法中传入的 fd 参数为 openInputChannelPair() 方法中创建的 socket,由此可知,InputChannel 的本质是对 socket 的封装。

(5)NativeInputChannel

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

NativeInputChannel::NativeInputChannel(const sp<InputChannel>& inputChannel) :
    mInputChannel(inputChannel), mDisposeCallback(NULL) {
}

​ 说明:inputChannel(Native层)是 openInputChannelPair() 方法中创建的 serverChannel 和 clientChannel。

(6)android_view_InputChannel_createInputChannel

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

static jobject android_view_InputChannel_createInputChannel(JNIEnv* env, std::unique_ptr<NativeInputChannel> nativeInputChannel) {
    jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz, gInputChannelClassInfo.ctor);
    if (inputChannelObj) {
        android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel.release());
    }
    return inputChannelObj;
}

static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj, NativeInputChannel* nativeInputChannel) {
    env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr, reinterpret_cast<jlong>(nativeInputChannel));
}

​ android_view_InputChannel_createInputChannel() 方法将 JNI 层的 NativeInputChannel 对象封装为 Java 层的 InputChannel 对象。

3.2 nativeTransferTo 后续流程

​ InputChannel 的 transferTo() 方法调用了 JNI 层的 nativeTransferTo() 方法,调用点如下。

//将 outInputChannel 与 NativeInputChannel 绑定,mClientChannel 与 NativeInputChannel 解绑
mClientChannel.transferTo(outInputChannel);

(1)android_view_InputChannel_nativeTransferTo

​ Java 层调用的 nativeTransferTo() 方法对应 JNI 层的 android_view_InputChannel_nativeTransferTo() 方法。

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj, jobject otherObj) {
    ...
    //获取与 obj 绑定的 NativeInputChannel 对象
    NativeInputChannel* nativeInputChannel = android_view_InputChannel_getNativeInputChannel(env, obj);
    //将 otherObj 与 nativeInputChannel 绑定
    android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
    //将 Obj 与 nativeInputChannel 解绑
    android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}

​ 说明:obj 指 Java 层的 mClientChannel;otherObj 指 Java 层 的 outInputChannel。

(2)android_view_InputChannel_getNativeInputChannel

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

static struct {
    jclass clazz;
    jfieldID mPtr;   // native object attached to the DVM InputChannel
    jmethodID ctor;
} gInputChannelClassInfo;

static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env, jobject inputChannelObj) {
    jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
    return reinterpret_cast<NativeInputChannel*>(longPtr);
}

​ 说明:inputChannelObj 指 Java 层的 mClientChannel,每个 Java 层的 InputChannel 对应一个 JNI 层的 NativeInputChannel。

(3)android_view_InputChannel_setNativeInputChannel

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj, NativeInputChannel* nativeInputChannel) {
    env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr, reinterpret_cast<jlong>(nativeInputChannel));
}

​ 说明:obj 指 Java 层的 mClientChannel 或 outInputChannel。

3.3 nativeDispose 后续流程

​ InputChannel 的 dispose() 方法调用了 JNI 层的 nativeDispose() 方法,调用点如下。

//nativeDispose(false),将 mClientChannel 与 NativeInputChannel 解绑,并清除对应 NativeInputChannel 
mClientChannel.dispose();

(1)android_view_InputChannel_nativeDispose

​ Java 层调用的 nativeDispose() 方法对应 JNI 层的 android_view_InputChannel_nativeDispose() 方法。

​ /frameworks/base/core/jni/android_view_InputChannel.cpp

static void android_view_InputChannel_nativeDispose(JNIEnv* env, jobject obj, jboolean finalized) {
	//获取与 obj 绑定的 NativeInputChannel 对象
    NativeInputChannel* nativeInputChannel = android_view_InputChannel_getNativeInputChannel(env, obj);
    if (nativeInputChannel) {
        ...
        nativeInputChannel->invokeAndRemoveDisposeCallback(env, obj);
		//将 obj 与 NativeInputChannel 解绑
        android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
		//清除对应 NativeInputChannel
        delete nativeInputChannel;
    }
}

3.4 nativeRegisterInputChannel 后续流程

​ WindowState 的 openInputChannel() 方法调用了 IMS 的 registerInputChannel() 方法,调用点如下。

mWmService.mInputManager.registerInputChannel(mInputChannel, mClient.asBinder());

(1)registerInputChannel

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

public void registerInputChannel(InputChannel inputChannel, IBinder token) {
	...
	if (token == null) {
		token = new Binder();
	}
	inputChannel.setToken(token);
    //mPtr 为指向 NativeInputManager 的指针
	nativeRegisterInputChannel(mPtr, inputChannel, Display.INVALID_DISPLAY);
}

(2)gInputManagerMethods

​ /frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static const JNINativeMethod gInputManagerMethods[] = {
	...
	//Java 层调用的 nativeRegisterInputChannel 方法对应 JNI 层的 nativeRegisterInputChannel 方法
    { "nativeRegisterInputChannel",
            "(JLandroid/view/InputChannel;I)V",
            (void*) nativeRegisterInputChannel },
    ...
}

(3)nativeRegisterInputChannel

​ /frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

static void nativeRegisterInputChannel(JNIEnv* env, jclass, jlong ptr, jobject inputChannelObj, jint displayId) {
    //获取 NativeInputManager
	NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
	//获取与 inputChannelObj 绑定的 Native 层的 InputChannel 对象
    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env, inputChannelObj);
    ...
    status_t status = im->registerInputChannel(env, inputChannel, displayId);
    ...
    android_view_InputChannel_setDisposeCallback(env, inputChannelObj, handleInputChannelDisposed, im);
}

​ 说明:ptr 为指向 NativeInputManager 的指针,NativeInputManager 在 IMS 初始化时创建,详见→IMS启动流程;inputChannelObj 为 Java 层的 InputChannel。

(4)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);
	//转换为 InputChannel
    return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;
}

(5)registerInputChannel

​ /frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp

status_t NativeInputManager::registerInputChannel(JNIEnv* , const sp<InputChannel>& inputChannel, int32_t displayId) {
    ...
    return mInputManager->getDispatcher()->registerInputChannel(inputChannel, displayId);
}

​ 说明:NativeInputManager 为 JNI 层的类,InputManager 为 Native 层的类,它们在 IMS 初始化时就已创建,mInputManager 属于 InputManager 类;这里将 InputChannel 注册到 InputDispatcher 中。

(6)registerInputChannel

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

status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, int32_t displayId) {
	...
    { // acquire lock
        ...
		//创建 connection
        sp<Connection> connection = new Connection(inputChannel, false);
        int fd = inputChannel->getFd();
        mConnectionsByFd.add(fd, connection);
        mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
    } // release lock
    mLooper->wake(); //唤醒 Looper
    return OK;
}

​ 说明:Connection 是 InputDispatcher 的内部类。

(7)Connection

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

InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, bool monitor) :
        status(STATUS_NORMAL), inputChannel(inputChannel),
        monitor(monitor),
        inputPublisher(inputChannel), inputPublisherBlocked(false) {
}

​ 说明:在 Connection 的构造放方法中注入 inputChannel 和 monitor 属性。

​ 声明:本文转自【framework】InputChannel创建流程

标签:...,InputChannel,流程,framework,NativeInputChannel,env,android,view
From: https://www.cnblogs.com/zhyan8/p/17233654.html

相关文章

  • 【framework】surfaceflinger启动流程
    1前言​surfaceflinger的作用是合成来自WMS的Surface数据,并发送到显示设备。​SurfaceFlinger服务不同于AMS、WMS、IMP、PMS、DMS等服务,主要区别如下:......
  • java的流程控制-break continue
    breakcontinuebreak:在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。(break也在switch语句中使用) continue:在......
  • Vue.js props配置(微信收款确认流程)
    视频直接修改外来数据props会产生警告props配置项1.功能:让组件接收外部传过来的数据2.传递数据:```<Demoname="xxx"/>```3.接收数据:1.第一种方式(只接收......
  • java流程控制
    java流程控制Scanner对象通过新建Scanner类来获取用户的输入基本语法:Scannerscanner=newScanner(system.in)Stringstr=scanner.nextLine(),inti=scanner.ne......
  • python安装robotframework的一些常见的错误
    python安装robotframework的一些常见的错误首先的电脑环境是x86的,然后下载的python版本起初是3.10.1的在cmd中出入pipinstallrobotframwork是没有问题的,但是在输入下......
  • 【Python从入门到进阶】10、流程控制语句-循环语句(for-while)
    接上篇《9、流程控制语句-条件语句(if-else)》上一篇我们学习了Python的控制流语句的概念,以及其中的条件语句(if/else),本篇我们来学习控制流语句中的循环语句(for/while)。......
  • 逻辑备份与online ddl流程
    逻辑备份:6步   onlineddl:5步 ......
  • 请你详细说说类加载流程,类加载机制及自定义类加载器
    当程序使用某个类时,如果该类还未被加载到内存中,则JVM会通过加载、链接、初始化三个步骤对该类进行类加载。加载类加载指的是将类的class文件读入内存,并为之创建一个java.......
  • nanoFramework
    nanoFramework01:GettingstartedwithnanoFramework!08:.NETnanoFrameworkGPIO,I2C,SPIandotherIOsupport......
  • (3) MasaFramework 入门第三篇,使用MasaFramework
    首先我们需要创建一个MasaFramework模板的项目,项目名称TokenDemo,项目类型如图所示删除Web/TokenDemo.Admin项目,新建MasaBlazorPro项目模板项目,项目位置在src/Web项目......