上一节中讲到 dispatchMotionLocked() 向目标窗口分发事件,接下来继续学习目标窗口是如何获取和绑定的;窗口的绑定是在 Activity 的启动流程中(具体可以参考 笔记14 Activity 启动流程),这里先简单介绍一下 Activity 的创建。
1. Activity 的创建
其中跨进程通信完成后,使用 ActivityThread 的内部类 ApplicationThread 中 scheduleLaunchActivity() 方法进行处理了:其实在这个方法中也很简单,就是使用主线程的 handler 发送了一条 H.LAUNCH_ACTIVITY 的消息,然后 handle r处理消息时调用了 handleLaunchActivity(r, null) 方法,具体有以下两步:
(1)创建 activity 第 1 步 activity.attach():
handleLaunchActivity() -> performLaunchActivity() -> activity.attach(),这个 activity.attach() 方法,是对 activity进行绑定,完成这一步activity才成为四大组件之一,未完成时都只能算一个对象。
(2)创建 activity 第 2 步 handleResumeActivity():
handleLaunchActivity() -> handleResumeActivity(),执行 onResume() 方法并渲染;
1.1 activity.attach():
// activity 的 attach() 方法:
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, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachActivity(this, mContainer, null);
// 创建 Window
// 这里的 mWindow 时 PhoneWindow,后续版本的 mWindow 初始化如下,更加直观:
// mWindow = new PhoneWindow(this, window, activityConfigCallback);
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
mWindow.setOnWindowDismissedCallback(this);
mWindow.getLayoutInflater().setPrivateFactory(this);
// ...
// 在 window 中创建时 mWindowManager 其实是 WindowManagerImpl,代码不复杂,可以跟进去看看
mWindow.setWindowManager( // 设置 WindowManager
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager(); // 这里就可以获取 WindowManager 了
mCurrentConfig = config;
}
在这里记住三个知识点(后续讲setContentView时再详细分析):
a. Window 类是一个抽象类,它的唯一实现类是 PhoneWindow;
b. PhoneWindow 有一个内部类 DecorView,DecorView 是 Activity 的根 View;
c. DecorView 继承自 FramLayout;
关于创建Window对象:
PolicyManager 为策略类,其实现类 Policy 的makeNewWindow内部创建了window对象;
// mWindow = PolicyManager.makeNewWindow(this):
public final class PolicyManager {
private static final String POLICY_IMPL_CLASS_NAME =
"com.android.internal.policy.impl.Policy";
private static final IPolicy sPolicy;
static { // 通过反射创建 sPolicy
try {
Class policyClass = Class.forName(POLICY_IMPL_CLASS_NAME);
sPolicy = (IPolicy)policyClass.newInstance();
} catch (ClassNotFoundException ex) {
// ...
}
}
private PolicyManager() {}
// 创建PhoneWindow
public static Window makeNewWindow(Context context) {
return sPolicy.makeNewWindow(context);
}
public static LayoutInflater makeNewLayoutInflater(Context context) {
return sPolicy.makeNewLayoutInflater(context);
}
public static WindowManagerPolicy makeNewWindowManager() {
return sPolicy.makeNewWindowManager();
}
public static FallbackEventHandler makeNewFallbackEventHandler(Context context) {
return sPolicy.makeNewFallbackEventHandler(context);
}
}
// Policy.java 类中的 makeNewWindow() 方法:
public window makeNewWindow(Context context){
return new PhoneWindow(context);
}
1.2 handleResumeActivity():
// 第二步:
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume) {
// 主要作用是调用 performResumeActivity() 到 activity 的 onResume 状态,然后获取
// DecorView,创建一个关联的 ViewRootImpl 对象,用来配合 WindowManagerService 服
// 务来管理该 Activity 组件的窗口状态,最后 addView
ActivityClientRecord r = performResumeActivity(token, clearHide);
if (r != null) {
final Activity a = r.activity;
// ...
//activity创建成功,window此时为空,进入此分支;
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();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
// 一层层的看最终调用的是:WindowManagerGlobal.java -> addView()
wm.addView(decor, l); // 这里就是测量,摆放,绘制; 也是下面要讲的内容;
}
} else if (!willBeVisible) {
r.hideForNow = true;
}
// Get rid of anything left hanging around.
cleanUpPendingRemoveWindows(r);
// ...
}
}
2. 从 addView() 到 服务端(WMS) InputChannel (也就是 fd ) 的注册
整个过程如下所示:服务端的注册即 WMS 中 InputChannel 注册到 InputDispatcher;
2.1 从 addView 开始:
// WindowManagerImpl.addView():
// 单例获取 WindowManagerGlobal
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}
// WindowManagerGlobal.addView():
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
// ... 省略部分代码:参数的校验
final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
// ...
ViewRootImpl root;
View panelParentView = null;
//...
// 实例化 ViewRootImpl
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
// 添加 view 到全局集合中
// 如果想 hook 全部的 view 时,可以通过反射获取 WindowManagerGlobal -> mViews;
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
}
// do this last because it fires off messages to start doing things
try { // 将 view 添加到 ViewRootImpl 中去
root.setView(view, wparams, panelParentView);
} catch (RuntimeException e) {
// ...
}
}
ViewRootImpl.setView():
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
// 这里先将 mView 保存了 DecorView 的实例,
// 然后调用 requestLayout() 方法,以完成应用程序用户界面的初次布局。
if (mView == null) {
mView = view;
// mWindowAttributes 保存了窗口所对应的 LayoutParams
mWindowAttributes.copyFrom(attrs);
/**
* 在添加窗口之前,先通过requestLayout方法在主线程上安排一次“遍历”。
* 所谓“遍历”是指 ViewRootImpl 中的核心方法 performTraversal()。
* 这个方法实现对控件树进行测量、布局、向 WMS 申请修改窗口属性以及重绘的所有工作。
*/
requestLayout();
/*初始化 mInputChannel。InputChannel 是窗口接受来自 InputDispatcher 的输入事件的管
道。注意,仅当窗口的属性 inputFeatures 不含有 INPUT_FEATURE_NO_INPUT_CHANNEL 时
才会创建 InputChannel,否则 mInputChannel 为空,从而导致此窗口无法接受任何输入事件 */
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel(); // 见 注释1
}
try {
// ...
/* 将窗口添加到 WMS 中。完成这个操作之后,mWindow 已经被添加到指定的Display中去
而且 mInputChannel(如果不为空)已经准备好接受事件了。只是由于这个窗口没有进行
过 relayout() ,因此它还没有有效的 Surface 可以进行绘制 */
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel); // 重点代码
// 这里的 mWindowSession 是向WMS跨进程请求获取的
} catch (RemoteException e) {
// ...
} finally {
// ...
}
}
}
(注释1)InputChannel的构造函数:此时 mInputChannel = new InputChannel() 这里还是一个 Java 的对象;
public final class InputChannel implements Parcelable {
private static final String TAG = "InputChannel";
@SuppressWarnings("unused")
private long mPtr; // used by native code
private static native InputChannel[] nativeOpenInputChannelPair(String name);
private native void nativeDispose(boolean finalized);
private native void nativeTransferTo(InputChannel other);
private native void nativeReadFromParcel(Parcel parcel);
private native void nativeWriteToParcel(Parcel parcel);
private native void nativeDup(InputChannel target);
private native String nativeGetName();
// 构造函数中没有任何操作,此时 mInputChannel = new InputChannel() 只是一个普通的java对象;
// 那么要想具有 c++ 的属性,唯一的方法就是持有 c++ 对象的指针,也就是将 mPtr 赋值;
public InputChannel() {
}
// ...
}
2.2 mWindowSession.addToDisplay():重点的开始
(1)首先,mWindowSession 是如何获取到的:ViewRootImpl 的构造函数中进行初始化的;
// mWindowSession 的初始化:ViewRootImpl 的构造函数中进行初始化的;
public ViewRootImpl(Context context, Display display) {
mContext = context;
mWindowSession = WindowManagerGlobal.getWindowSession(); // 通过 WMS 获取
}
// WindowManagerGlobal 类中的 getWindowSession() 方法
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
// 通过 WMS 获取 mWindowSession
sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}
}
return sWindowSession;
}
}
// WMS 中 openSession():
@Override
public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
IInputContext inputContext) {
if (client == null) throw new IllegalArgumentException("null client");
if (inputContext == null) throw new IllegalArgumentException("null inputContext");
Session session = new Session(this, callback, client, inputContext); // 参数 this 就是 WMS;
return session;
}
IWindowSession:一个aidl接口,它的真的实现类是Session,是一个 Binder 对象,也是 ViewRootImpl 和 WMS 进行通信的代理。在 ViewRootImpl 的 setView() 中最终也是通过它和 WMS 通信完成了 Window 的添加。这个 Session 是应用唯一的,它的创建是在 WindowManagerGloable 中通过 getWindowSession() 获取的。
(2)mWindowSession.addToDisplay():就是调用了 Session 的 addToDisplay() 方法;
// Session 的 addToDisplay() 方法:又是跨进程通讯
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel); // 调用了 WMS 中的 addWindow() 方法
}
该方法的参数 outInputChannel 是 ViewRootImpl.setView() 中 mInputChannel = new InputChannel(),不过此时 InputChannel 中的 c++ 对象指针还未赋值,mService 就是 new Session 时传入的 WMS。
(3)WMS 的addWindow() 方法:App 端 InputChannel 赋值与建立 socketpair 双向通信;
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {
int[] appOp = new int[1];
int res = mPolicy.checkAddPermission(attrs, appOp);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}
boolean reportNewConfig = false;
WindowState attachedWindow = null;
WindowState win = null; // window 对象的信息
long origId;
final int type = attrs.type;
synchronized(mWindowMap) {
// ...
win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
// ...
if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
// 关键代码,打开一对 InputChannel,客户端和服务端
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
// WMS 设置 Channel 为 inputChannels[0]
win.setInputChannel(inputChannels[0]);
// 客户端设置 Channel 为 inputChannels[1],此时给上面 Java层的 mInputChannel 中 mPtr 赋值
// 经过赋值后,Java 层 mInputChannel 才具有 c++ 的对象
inputChannels[1].transferTo(outInputChannel);
// 将服务端的 socket 注册到 InputDispatcher 中
// 这里的 win.mInputWindowHandle 是在 win 初始化的时候 new 出来的;
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
// ...
// 每次添加都会更新
mInputMonitor.updateInputWindowsLw(false /*force*/);
// ...
}
// ...
}
在 WMS 的 addWindow() 方法中有很多的关键点,这里列举一些下面内容中需要关注的关键点:
- (a)win = new WindowState():创建出 WindowState 来描述 App 端的信息;
- (b)InputChannel.openInputChannelPair():使用 socketpair() 打开一对 InputChannel;
- (c)win.setInputChannel(inputChannels[0]):设置服务端 WMS 的 InputChannel 为 inputChannels[0];
- (d)inputChannels[1].transferTo(outInputChannel):客户端设置 Channel 为 inputChannels[1],给上面 Java层的 mInputChannel 中 mPtr 赋值,经过赋值后,Java 层 mInputChannel 才具有了 c++ 的对象;
- (e)mInputManager.registerInputChannel():将服务端的 InputChannel 注册到 InputDispatcher 中 ;
2.3 双向通信 socketpair 的建立:承接上面的关键点进行分析;
(1)InputChannel.openInputChannelPair():在 InputChannel.java 中很简单,只是调用了一个 native 方法 nativeOpenInputChannelPair(name),在 frameworks/base/core/jni/android_view_InputChannel.cpp 中:
// android_view_InputChannel.cpp 中:
static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,
jclass clazz, jstring nameObj) {
const char* nameChars = env->GetStringUTFChars(nameObj, NULL);
String8 name(nameChars);
env->ReleaseStringUTFChars(nameObj, nameChars);
sp serverChannel;
sp clientChannel;
// 第一步(详见下方代码):创建一对 socket 通信;
status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
if (result) {
String8 message;
message.appendFormat("Could not open input channel pair. status=%d", result);
jniThrowRuntimeException(env, message.string());
return NULL;
}
// 第二步:创建 java 数组对象;用于保存这对 InputChannel
jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);
if (env->ExceptionCheck()) {
return NULL;
}
// 第三步(详见下方代码):创建 NativeInputChannel,将 InputChannel 指针保存于 mInputChannel 中;
// 第四步 (详见下方代码):设置 Java InputChannel 的 mPtr 成员变量;
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
new NativeInputChannel(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
env->SetObjectArrayElement(channelPair, 0, serverChannelObj);
env->SetObjectArrayElement(channelPair, 1, clientChannelObj);
return channelPair;
}
// 第一步:创建一对 InputChannel;(InputChannel.cpp中)
status_t InputChannel::openInputChannelPair(const String8& name,
sp& outServerChannel, sp& outClientChannel) {
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
status_t result = -errno;
// ...
// 封装成 InputChannel
String8 serverChannelName = name;
serverChannelName.append(" (server)");
outServerChannel = new InputChannel(serverChannelName, sockets[0]);
String8 clientChannelName = name;
clientChannelName.append(" (client)");
outClientChannel = new InputChannel(clientChannelName, sockets[1]);
return OK;
}
InputChannel::InputChannel(const String8& name, int fd) :
mName(name), mFd(fd) {
// 代码很简单,有用的只有一行(将 fd 设置成为非阻塞方式)
int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
}
// 第二步:创建 java 数组对象;用于保存这对 InputChannel(通过调用 jni 的方法,省略介绍)
// 第三步:创建 NativeInputChannel,将传入的 InputChannel 指针保存于 mInputChannel 成员变量中;
NativeInputChannel::NativeInputChannel(const sp& inputChannel) :
mInputChannel(inputChannel), mDisposeCallback(NULL) {
}
// 第四步:
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
NativeInputChannel* nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor); // 调用 jni 方法 NewObject 创建一个 Java InputChannel 对象
if (inputChannelObj) {
// 调用 android_view_InputChannel_setNativeInputChannel 将 nativeInputChannel 对象指针强
// 转为 jlong,然后将其设置到 Java InputChannel 类的 mPtr 成员变量上;
android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
}
return inputChannelObj;
}
经过 InputChannel.cpp 中 openInputChannelPair() 中调用 socketpair(),并封装成一对 InputChannel,然后转换成 Java 对象返回给 WMS 供其使用(这里注意一下,客户端的 InputChannel 是 WMS 获取到之后,经过 Binder 通信发送给 app 的,这一套 socketpair + Binder 的通信方式,实现了任意进程间的双向通信);另外,socketpair() 在前面的【输入事件番外篇1 Linux知识点】中有讲过。
(2)设置服务端(WMS)和客户端(App)端的 InputChannel:
// 设置 WMS 的 InputChannel:win.setInputChannel(inputChannels[0])
// WindowState.java 中
void setInputChannel(InputChannel inputChannel) {
if (mInputChannel != null) {
throw new IllegalStateException("Window already has an input channel.");
}
// 代码很简单,只需要把 WindowState 中的两个成员变量的值置为传入的参数 inputChannels[0];
mInputChannel = inputChannel;
mInputWindowHandle.inputChannel = inputChannel;
}
// 设置 App 的 InputChannel:inputChannels[1].transferTo(outInputChannel)
// InputChannel.java 中
public void transferTo(InputChannel outParameter) {
if (outParameter == null) {
throw new IllegalArgumentException("outParameter must not be null");
}
// 执行了native 方法,调用了 android_view_InputChannel.cpp 中的方法
// 将 InputChannel 内部状态的所有权转移到另一个实例,并使该实例无效。
nativeTransferTo(outParameter);
}
// android_view_InputChannel.cpp 中
static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,
jobject otherObj) {
/* otherObj 即对应的入参,调用 android_view_InputChannel_getNativeInputChannel 方法可将 Java
InputChannel 对象的 mPtr 成员变量强转为 NativeInputChannel 对象,由于传递过来的 Java 层的
InputChannel 对象中 mPtr 还没有赋值,是一个个“空壳”,所以强转以后一定为空,否则抛出异常 */
if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Other object already has a native input channel.");
return;
}
// 这次调用是将 obj 转化为 NativeInputChannel 对象。
NativeInputChannel* nativeInputChannel =
android_view_InputChannel_getNativeInputChannel(env, obj);
// 将obj 转化的 NativeInputChannel 对象(实际是指针)设置到 otherObj mPtr 成员变量上。*/
android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);
// 最后将 obj mPtr 成员变量设置为 0,即表示 NativeInputChannel 对象为 NULL。
android_view_InputChannel_setNativeInputChannel(env, obj, NULL);
}
// 这两个被调用的方法,主要调用 jni 方法 GetLongField 和 SetLongField,实现 Native 层操作 java 对象成员变量。
static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,
jobject inputChannelObj) {
jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);
return reinterpret_cast(longPtr);
}
static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,
NativeInputChannel* nativeInputChannel) {
env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,
reinterpret_cast(nativeInputChannel));
}
经过上面的赋值操作,WMS 端和 App 端各自持有了一对经过 socketpair 创建封装的 InputChannel,那么接下来就是看看如何与事件分发系统联系起来了;
(3)mInputManager.registerInputChannel():将 WMS 端的 InputChannel 注册到 InputDispatcher 中;这里的 mInputManager 是 IMS,在 WMS 的构造函数中作为参数传入;也就是说调用的是 IMS 的 registerInputChannel() 方法:
// InputManagerService.java 中:
public void registerInputChannel(InputChannel inputChannel,
InputWindowHandle inputWindowHandle) {
if (inputChannel == null) {
throw new IllegalArgumentException("inputChannel must not be null.");
}
// native 方法
nativeRegisterInputChannel(mPtr, inputChannel, inputWindowHandle, false);
}
// frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeRegisterInputChannel(JNIEnv* env, jclass clazz,
jlong ptr, jobject inputChannelObj, jobject inputWindowHandleObj, jboolean monitor) {
// 将 ptr 强转为 NativeInputManager 对象 (这里的 ptr 是 IMS 的 c++ 指针,不是 InputChannel 的)
NativeInputManager* im = reinterpret_cast(ptr);
// 将 inputChannelObj 转化为 NativeInputChannel 对象
sp inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
throwInputChannelNotInitialized(env);
return;
}
// 将 inputWindowHandleObj 转化为 NativeInputWindowHandle 对象
sp inputWindowHandle =
android_server_InputWindowHandle_getHandle(env, inputWindowHandleObj);
// 最终调用 NativeInputManager 类 registerInputChannel() 方法完成实际注册工作
status_t status = im->registerInputChannel(
env, inputChannel, inputWindowHandle, monitor);
if (status) {
String8 message;
message.appendFormat("Failed to register input channel. status=%d", status);
jniThrowRuntimeException(env, message.string());
return;
}
if (! monitor) {
android_view_InputChannel_setDisposeCallback(env, inputChannelObj,
handleInputChannelDisposed, im);
}
}
// com_android_server_input_InputManagerService.cpp 中:
// 这里是一个过渡的方法,主要是获取到之前 IMS 启动时创建的 InputDispatcher,执行里面的方法;
status_t NativeInputManager::registerInputChannel(JNIEnv* env,
const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
return mInputManager->getDispatcher()->registerInputChannel( // 回到了 InputDispatcher 中了
inputChannel, inputWindowHandle, monitor);
}
// frameworks/native/services/inputflinger/InputDispatcher.cpp 中:
// 在这个方法中,WMS 的 InputChannel 终于注册到 InputDispatcher 中了,也就是说,当有事件分发时,服
// 务端的 InputChannel 获取到事件分发然后通过数据通道发送到 App 端了;其主要的工作有以下四步:
status_t InputDispatcher::registerInputChannel(const sp& inputChannel,
const sp& inputWindowHandle, bool monitor) {
{ // acquire lock
AutoMutex _l(mLock);
// 第一步:检查 InputChannel 是否已经注册过
if (getConnectionIndexLocked(inputChannel) >= 0) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().string());
return BAD_VALUE;
}
// 第二步:创建 Connection 对象,Connection 表示客户端和服务端的一个输入数据通道
sp connection = new Connection(inputChannel, inputWindowHandle, monitor);
int fd = inputChannel->getFd(); // // 获取 socketpair 的 fd
// 第三步:以 fd 为 key 将 Connection 添加到容器(mConnectionsByFd)中
mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
/* 第四步:将 fd 添加到 Looper 监听列表中。一旦对端的 Socket 写入数据,Looper 就会被唤醒,接着
就会调用 handleReceiveCallback */
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// 唤醒 Looper,因为一些连接(Connection)已经改变
mLooper->wake();
return OK;
}
经过这一步,WMS 的 InputChannel 就和 InputDispatcher 建立了关联。现在该回到 ViewRootImpl.setView() 方法中具体分析如何关联客户端 InputChannel 了。
3. App 端 InputChannel (也就是 fd ) 的注册
在上面 WindowManagerGlobal.addView() -> ViewRootImpl.setView() -> Session.addToDisplay -> WMS.addWindow() 最终完成了 WMS 端的 InputChannel 的注册;接下来分析客户端 InputDispatcher 的关联,也是从 ViewRootImpl.setView() 这个方法中开始的:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
// ... 省略部分代码
// 在add to window manager之前执行第一次 requestLayout,以确保在 requestLayout 之前已经接收
// 到系统的任何事件;
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(),
mAttachInfo.mContentInsets, mInputChannel);
} catch (RemoteException e) {
//...
} finally {
//...
}
// ... 省略部分代码
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
// 将 InputChannel 封装成 WindowInputEventReceiver,这里是重点
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper()); // 注意一下,这里使用的是主线程的 Looper;
}
// ... 省略部分代码
}
}
将 App 端的 InputChannel 封装成 WindowInputEventReceiver,这里也没有执行它的任何方法,那就看一下这个 WindowInputEventReceiver 的构造函数,看看有没有执行一些方法:
(1)封装 WindowInputEventReceiver:从类名上来看,这个类是 App 端窗口的事件接收器;
// WindowInputEventReceiver.java 中:ViewRootImpl 的内部类;
final class WindowInputEventReceiver extends InputEventReceiver {
public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {
super(inputChannel, looper); // 执行了父类中的方法,继续跟进
}
@Override
public void onInputEvent(InputEvent event) {
enqueueInputEvent(event, this, 0, true);
}
@Override
public void onBatchedInputEventPending() {
if (mUnbufferedInputDispatch) {
super.onBatchedInputEventPending();
} else {
scheduleConsumeBatchedInput();
}
}
@Override
public void dispose() {
unscheduleConsumeBatchedInput();
super.dispose();
}
}
// InputEventReceiver.java 中:
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();
mReceiverPtr = nativeInit(new WeakReference(this),
inputChannel, mMessageQueue); // 这里就执行到 c++ 代码中了
mCloseGuard.open("dispose");
}
InputEventReceiver 构造器中首先检查入参 inputChannel 和 looper 是否为 null,接着从 looper 中获取 MessageQueue,最后调用 nativeInit() 进一步初始化;
(2)JNI 层初始化:nativeInit();
// frameworks/base/core/jni/android_view_InputEventReceiver.cpp
// 主要有以下四个点:
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
jobject inputChannelObj, jobject messageQueueObj) {
//(1)将 Java 层对象 InputChannel 对象转化为 NativeInputChannel 对象
sp inputChannel = android_view_InputChannel_getInputChannel(env,
inputChannelObj);
if (inputChannel == NULL) {
jniThrowRuntimeException(env, "InputChannel is not initialized.");
return 0;
}
//(2)将 Java 层 MessageQueue 对象转化为 NativeMessageQueue 对象
sp messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
if (messageQueue == NULL) {
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
return 0;
}
//(3)创建 NativeInputEventReceiver 对象
sp receiver = new NativeInputEventReceiver(env,
receiverWeak, inputChannel, messageQueue);
//(4)执行 NativeInputEventReceiver 对象 initialize() 方法
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); // 保留对象的引用
return reinterpret_cast(receiver.get());
}
// NativeInputEventReceiver 构造函数:将传递来的入参保存到对应的成员变量中。
// class NativeInputEventReceiver : public LooperCallback 继承自 LooperCallback,
// 并实现 LooperCallback 的 handleEvent() 方法;
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp& inputChannel,
const sp& messageQueue) :
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mInputConsumer(inputChannel), mMessageQueue(messageQueue),
mBatchedInputEventPending(false), mFdEvents(0) {
}
// initialize() 方法:执行了 setFdEvents,其中 ALOOPER_EVENT_INPUT = 1 << 0,左移0位,结果为 1;
status_t NativeInputEventReceiver::initialize() {
setFdEvents(ALOOPER_EVENT_INPUT);
return OK;
}
// setFdEvents() 方法:根据获取 MessageQueue->getLooper(),然后调用 Looper 的 addFd()
void NativeInputEventReceiver::setFdEvents(int events) { // 传入的参数为 1<< 0 为 1
if (mFdEvents != events) { // mFdEvents 初始化的值为 0;
mFdEvents = events;
int fd = mInputConsumer.getChannel()->getFd();
if (events) { // 所以执行此分支
mMessageQueue->getLooper()->addFd(fd, 0, events, this, NULL);
} else {
mMessageQueue->getLooper()->removeFd(fd);
}
}
}
从 nativeInit() 开始,经过一系列对象转换(将 Java 对象转换成 native 层的 c++ 对象),并创建 NativeInputEventReceiver,然后执行了 Looper 的 addFd() 方法;
(3)Looper.cpp 中:addFd()
int Looper::addFd(int fd, int ident, int events, Looper_callbackFunc callback, void* data) {
// // 这里的 callback 是传入的参数 NativeInputEventReceiver
return addFd(fd, ident, events, callback ? new SimpleLooperCallback(callback) : NULL, data);
}
int Looper::addFd(int fd, int ident, int events, const sp& callback, void* data) {
if (!callback.get()) {
if (! mAllowNonCallbacks) {
ALOGE("Invalid attempt to set NULL callback but not allowed for this looper.");
return -1;
}
if (ident < 0) {
ALOGE("Invalid attempt to set NULL callback with ident < 0.");
return -1;
}
} else {
ident = POLL_CALLBACK;
}
int epollEvents = 0;
if (events & EVENT_INPUT) epollEvents |= EPOLLIN;
if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;
{ // acquire lock
AutoMutex _l(mLock);
// 封装成 Request
Request request;
request.fd = fd;
request.ident = ident;
request.callback = callback;
request.data = data;
struct epoll_event eventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field union
eventItem.events = epollEvents;
eventItem.data.fd = fd;
ssize_t requestIndex = mRequests.indexOfKey(fd); // 查找当前是否保存过
if (requestIndex < 0) { // 如果没有则保存
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);
if (epollResult < 0) {
ALOGE("Error adding epoll events for fd %d, errno=%d", fd, errno);
return -1;
}
mRequests.add(fd, request); // 保存 request
} else { // 如果有则替换
int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);
if (epollResult < 0) {
ALOGE("Error modifying epoll events for fd %d, errno=%d", fd, errno);
return -1;
}
mRequests.replaceValueAt(requestIndex, request);
}
} // 释放锁
return 1;
}
在 addFd() 方法中,先将参数封装成 Request,然后向保存 Request 的容器中查询是否保存过当前 fd,没有保存则保存,反之则替换;通过 epoll_ctl() 添加 fd 描述符后,当有数据从服务端写入,就会唤醒 Looper,最终回调到 NativeInputEventReceiver(继承自LooperCallback) 的 handleEvent() 方法。
(4)pollInner() 执行回调:
int Looper::pollInner(int timeoutMillis) {
// ...
// Invoke all response callbacks.
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.ident == POLL_CALLBACK) {
int fd = response.request.fd;
int events = response.events;
void* data = response.request.data;
// 执行 回调函数 handleEvent()
int callbackResult = response.request.callback->handleEvent(fd, events, data);
if (callbackResult == 0) {
removeFd(fd);
}
// Clear the callback reference in the response structure promptly because we
// will not clear the response vector itself until the next poll.
response.request.callback.clear();
result = POLL_CALLBACK;
}
}
return result;
}
还记得上面说到传入的 Looper 是主线程的 Looper 吗?在 Java 层主线程中,执行了 looper.loop() 方法后,会循环执行 pollInner(),所以这里的回调执行后就会返回给 Java 层处理了;