InputChannel通道建立-Android12
Posted xhBruce
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了InputChannel通道建立-Android12相关的知识,希望对你有一定的参考价值。
InputChannel通道建立-android12
android12-release
InputDispatcher线程分发事件-Android12 最后通过
mChannel->sendMessage(&msg)
发送给InputEventReceiver接收端,之间使用Socket实现通信。
frameworks/base/core/java/android/view/InputChannel.java
frameworks/base/core/java/android/view/InputEventReceiver.java
frameworks/native/libs/input/InputTransport.cpp
1. APP界面建立InputChannel
InputReader和InputDispatcher都是运行在system_server进程,通过建立InputChannel socket传递给APP进程
1.1 APP界面添加
App即将显示处理ActivityThread.handleResumeActivity
中:
performResumeActivity
通过Instrumentation.java通知Activity.onResumewm.addView(decor, l)
和r.activity.makeVisible()
实质一样,通过WindowManager(即WindowManagerImpl
)调用WindowManagerGlobal.addView()
,ViewRootImpl.setView()
建立InputChannel
frameworks/base/core/java/android/app/ActivityThread.java
public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
boolean isForward, String reason)
// ... ...
if (!performResumeActivity(r, finalStateRequest, reason))
return;
// ... ...
if (r.window == null && !a.mFinished && willBeVisible)
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
// ... ...
if (a.mVisibleFromClient)
if (!a.mWindowAdded)
a.mWindowAdded = true;
wm.addView(decor, l);
else
// ... ...
// ... ...
// ... ...
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow)
// ... ...
if (r.activity.mVisibleFromClient)
r.activity.makeVisible();
// ... ...
1.1.1 Context.WINDOW_SERVICE
实际获取WindowManagerImpl
frameworks/base/core/java/android/app/Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor,
Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken,
IBinder shareableActivityToken)
// ... ...
mWindow = new PhoneWindow(this, window, activityConfigCallback);
// ... ...
mUiThread = Thread.currentThread();
mMainThread = aThread;
// ... ...
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
// ... ...
1.2 InputChannel / WindowInputEventReceiver建立联系
- 创建Java层的InputChannel对象
mWindowSession.addToDisplayAsUser()
向WMS注册InputChannel信息,通过InputChannel::openInputChannelPair
创建的socket pair,将其中的客户端赋值给mInputChannel.WindowInputEventReceiver
接收InputChannel消息- InputStage 事件处理责任链
frameworks/base/core/java/android/view/WindowManagerGlobal.java
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId)
synchronized (mLock)
// ... ...
root = new ViewRootImpl(view.getContext(), display);
// ... ...
// do this last because it fires off messages to start doing things
try
root.setView(view, wparams, panelParentView, userId);
catch (RuntimeException e)
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0)
removeViewLocked(index, true);
throw e;
frameworks/base/core/java/android/view/ViewRootImpl.java
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId)
synchronized (this)
if (mView == null)
// ... ...
InputChannel inputChannel = null;
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)
inputChannel = new InputChannel();
// ... ...
try
// ... ...
res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId,
mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
mTempControls);
if (mTranslator != null)
mTranslator.translateInsetsStateInScreenToAppWindow(mTempInsets);
mTranslator.translateSourceControlsInScreenToAppWindow(mTempControls);
catch (RemoteException e)
// ... ...
finally
if (restore)
attrs.restore();
// ... ...
if (inputChannel != null)
// ... ...
mInputEventReceiver = new WindowInputEventReceiver(inputChannel,
Looper.myLooper());
// ... ...
// Set up the input pipeline.
CharSequence counterSuffix = attrs.getTitle();
mSyntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(mSyntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);
mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
1.3 InputChannel使用socket通信
- 服务端serverChannel、客户端clientChannel;将clientChannel给到java层mInputChannel
setsockopt()
socket通信- 创建Connection,并将
serverChannel->getFd()
添加到Looper监听
mWindowSession.addToDisplayAsUser() --> mService.addWindow() --> win.openInputChannel(outInputChannel) -->mWmService.mInputManager.createInputChannel(name) ==JNI==>最终调用InputDispatcher::createInputChannel
frameworks/base/services/core/java/com/android/server/wm/Session.java
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
frameworks/base/services/core/java/com/android/server/wm/WindowState.java
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name)
#if DEBUG_CHANNEL_CREATION
ALOGD("channel '%s' ~ createInputChannel", name.c_str());
#endif
std::unique_ptr<InputChannel> serverChannel;
std::unique_ptr<InputChannel> clientChannel;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
if (result)
return base::Error(result) << "Failed to open input channel pair with name " << name;
// acquire lock
std::scoped_lock _l(mLock);
const sp<IBinder>& token = serverChannel->getConnectionToken();
int fd = serverChannel->getFd();
sp<Connection> connection =
new Connection(std::move(serverChannel), false /*monitor*/, mIdGenerator);
if (mConnectionsByToken.find(token) != mConnectionsByToken.end())
ALOGE("Created a new connection, but the token %p is already known", token.get());
mConnectionsByToken.emplace(token, connection);
std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
this, std::placeholders::_1, token);
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, new LooperEventCallback(callback), nullptr);
// release lock
// Wake the looper because some connections have changed.
mLooper->wake();
return clientChannel;
frameworks/native/libs/input/InputTransport.cpp
status_t InputChannel::openInputChannelPair(const std::string& name,
std::unique_ptr<InputChannel>& outServerChannel,
std::unique_ptr<InputChannel>& outClientChannel)
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets))
status_t result = -errno;
ALOGE("channel '%s' ~ Could not create socket pair. errno=%s(%d)", name.c_str(),
strerror(errno), errno);
outServerChannel.reset();
outClientChannel.reset();
return result;
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));
sp<IBinder> token = new BBinder();
std::string serverChannelName = name + " (server)";
android::base::unique_fd serverFd(sockets[0]);
outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd), token);
std::string clientChannelName = name + " (client)";
android::base::unique_fd clientFd(sockets[1]);
outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd), token);
return OK;
2. 开发者选项中指针位置建立InputChannel
- WMS监听开关
POINTER_LOCATION
,enablePointerLocation初始化绘制界面PointerLocationView
,注册registerPointerEventListener监听 - 实质就是
InputChannel \\ InputEventReceiver
,在DisplayContent.java初始化是已经建立,这里注意有其他功能通过该InputChannel监听MotionEvent事件
3. Drag and drop拖放框架 建立InputChannel
View.startDrag/startDragAndDrop --> mAttachInfo.mSession.performDrag() --> mDragDropController.performDrag() --> mCallback.get().registerInputChannel() --> state.register() --> mInputInterceptor = new InputInterceptor(display) --> InputChannel / DragInputEventReceiver
- APP调用
startDrag()
启动时建立InputChannel / DragInputEventReceiver
frameworks/base/core/java/android/view/View.java
frameworks/base/services/core/java/com/android/server/wm/Session.java
frameworks/base/services/core/java/com/android/server/wm/DragDropController.java
frameworks/base/services/core/java/com/android/server/wm/WindowManagerInternal.java
frameworks/base/services/core/java/com/android/server/wm/DragState.java
以上是关于InputChannel通道建立-Android12的主要内容,如果未能解决你的问题,请参考以下文章
InputChannel发送Input给App-Android12
Android系统源码阅读(12):InputChannel的注册过程
InputManagerService实体按键及组合按键-Android12