1,概念

在启动一个acitivity时,将该activity和服务进程的InputChannel对应,这样事件就可以通过sockets进行通信了。

但是只有当前显示的acitivity才会获取事件,这就说明,在有一刻,会断开其他acitivity和服务进程的对应关系。

比如,销毁activity时就会断开该对应关系。

2,取消注册分析

销毁activity时会调用activity的finish方法,

private void finish(boolean finishTask) {if (mParent == null) {int resultCode;Intent resultData;synchronized (this) {resultCode = mResultCode;resultData = mResultData;}if (false) Log.v(TAG, "Finishing self: token=" + mToken);try {if (resultData != null) {resultData.prepareToLeaveProcess();}if (ActivityManagerNative.getDefault().finishActivity(mToken, resultCode, resultData, finishTask)) {mFinished = true;}} catch (RemoteException e) {// Empty}} else {mParent.finishFromChild(this);}}

直接调用ActivityManagerNative的finishActivity方法,然后跨进程调用ActivityManagerService的finishActivity方法,

AMS服务处理之后,然后又回调apk的ActivityThread进行处理, ActivityThread首先发送DESTROY_ACTIVITY消息切换到主线程,

调用handleDestroyActivity方法进一步处理。流程图如下,


从应用apk转到系统服务进程,然后又转回应用apk,

又从应用apk转到系统服务进程,终于出现了IMS服务,

C/C++层调用流程图如下,

转个来转个去,终于找到点子上了,

static void nativeUnregisterInputChannel(JNIEnv* env, jclass /* clazz */,jlong ptr, jobject inputChannelObj) {NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,inputChannelObj);if (inputChannel == NULL) {throwInputChannelNotInitialized(env);return;}android_view_InputChannel_setDisposeCallback(env, inputChannelObj, NULL, NULL);status_t status = im->unregisterInputChannel(env, inputChannel);if (status && status != BAD_VALUE) { // ignore already unregistered channelString8 message;message.appendFormat("Failed to unregister input channel.  status=%d", status);jniThrowRuntimeException(env, message.string());}

im是NativeInputManager对象,而NativeInputManager是com_android_server_input_InputManagerService.cpp中的一个内部类,

status_t NativeInputManager::unregisterInputChannel(JNIEnv* /* env */,const sp<InputChannel>& inputChannel) {return mInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
}

得到的是InputDispatcher对象,调用其unregisterInputChannel方法,

status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
#if DEBUG_REGISTRATIONALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
#endif{ // acquire lockAutoMutex _l(mLock);status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/);if (status) {return status;}} // release lock// Wake the poll loop because removing the connection may have changed the current// synchronization state.mLooper->wake();return OK;
}
status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,bool notify) {ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);if (connectionIndex < 0) {ALOGW("Attempted to unregister already unregistered input channel '%s'",inputChannel->getName().string());return BAD_VALUE;}sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); // 找到索引mConnectionsByFd.removeItemsAt(connectionIndex); // 从mConnectionsByFd中删除if (connection->monitor) {removeMonitorChannelLocked(inputChannel);}mLooper->removeFd(inputChannel->getFd());//从Looper中删除nsecs_t currentTime = now();abortBrokenDispatchCycleLocked(currentTime, connection, notify);connection->status = Connection::STATUS_ZOMBIE;return OK;
}

这2个方法和注册(registerInputChannel)刚好相反,

Looper的removeFd方法如下,

int Looper::removeFd(int fd, int seq) {
#if DEBUG_CALLBACKSALOGD("%p ~ removeFd - fd=%d, seq=%d", this, fd, seq);
#endif{ // acquire lockAutoMutex _l(mLock);ssize_t requestIndex = mRequests.indexOfKey(fd);if (requestIndex < 0) {return 0;}// Check the sequence number if one was given.if (seq != -1 && mRequests.valueAt(requestIndex).seq != seq) {
#if DEBUG_CALLBACKSALOGD("%p ~ removeFd - sequence number mismatch, oldSeq=%d",this, mRequests.valueAt(requestIndex).seq);
#endifreturn 0;}// Always remove the FD from the request map even if an error occurs while// updating the epoll set so that we avoid accidentally leaking callbacks.mRequests.removeItemsAt(requestIndex); // 移除索引
•••

在Looper中,底层消息来时, pollInner方法会遍历mResponses数组,并将回调handleEvent方法,

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;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKSALOGD("%p ~ pollOnce - invoking fd event callback %p: fd=%d, events=0x%x, data=%p",this, response.request.callback.get(), fd, events, data);
#endif// Invoke the callback.  Note that the file descriptor may be closed by// the callback (and potentially even reused) before the function returns so// we need to be a little careful when removing the file descriptor afterwards.int callbackResult = response.request.callback->handleEvent(fd, events, data);if (callbackResult == 0) {removeFd(fd, response.request.seq);}// 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;}}

由于在removeFd方法中已经去掉了被销毁(未显示)的activity的对应索引,所以仅有当前显示的activity才可以收到消息。

Activity取消注册InputChannel(十二)相关推荐

  1. 【EventBus】事件通信框架 ( 取消注册 | 获取事件参数类型 | 根据事件类型获取订阅者 | 移除相关订阅者 )

    文章目录 一.取消注册订阅者 二.完整代码示例 一.取消注册订阅者 取消注册操作 : 从 Map<Object, List<Class<?>>> typesBySu ...

  2. 《深入理解 Spring Cloud 与微服务构建》第十二章 服务注册和发现 Consul

    <深入理解 Spring Cloud 与微服务构建>第十二章 服务注册和发现 Consul 文章目录 <深入理解 Spring Cloud 与微服务构建>第十二章 服务注册和发 ...

  3. 十二客推出新版邮箱批量注册

    下载地址:http://www.12ke.com/Support/Products/RegisterAided/3.html 十二客邮箱辅助注册程序系列(网易版)是一款自动注册邮箱账号的软件,需要手工 ...

  4. 【转载】 javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册 - 孤傲苍狼 - 博 http://www.cnblogs.com/xdp-gacl/

    javaweb学习总结(二十二)--基于Servlet+JSP+JavaBean开发模式的用户登录注册 一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+Ja ...

  5. 20189200余超 2018-2019-2 移动平台应用开发实践第十二周作业

    20189200余超 2018-2019-2 移动平台应用开发实践第十二周作业 服务 Service的声明 Service是Android中的四大组件,使用它一定要在AndroidManifest.x ...

  6. ASP 三十二条精华代码

    整理收藏: ASP 三十二条精华代码 1. οncοntextmenu="window.event.returnvalue=false" 将彻底屏蔽鼠标右键 <table b ...

  7. Windows 家族的十二种常用密码破解法

    在日常操作中,我们经常要输入各种各样的密码,例 如开机时要输入密码, QQ 时也要先输入密码,假如你忘记了这些密码,就有可能用不了机器.打不开文件.不能聊天 ... . <?xml:namesp ...

  8. 插入DLL和挂接API——Windows核心编程学习手札之二十二

    插入DLL和挂接API --Windows核心编程学习手札之二十二 如下情况,可能要打破进程的界限,访问另一个进程的地址空间: 1)为另一个进程创建的窗口建立子类时: 2)需要调试帮助时,如需要确定另 ...

  9. linux线程并不真正并行,Linux系统编程学习札记(十二)线程1

    Linux系统编程学习笔记(十二)线程1 线程1: 线程和进程类似,但是线程之间能够共享更多的信息.一个进程中的所有线程可以共享进程文件描述符和内存. 有了多线程控制,我们可以把我们的程序设计成为在一 ...

最新文章

  1. .net new一个类为什么报空指针_谈谈.NET对象生命周期
  2. Android 事件分发 简单学
  3. mysql索引检测_mysql检测重复索引
  4. 开发自定义控件的笔记 (2)
  5. Django从理论到实战(part18)--配置templates文件夹路径
  6. 获取List对象的泛型类(原创)
  7. Linux篇:shell脚本监控主机状态的3种方式
  8. uview组件得到回调的参数
  9. 统计学习——联合概率分布
  10. QT软件开发:基于libVLC内核设计视频播放器
  11. 关于程序员的教育和培训
  12. 在Windows Server 2012中搭建WEB服务器,附ASP配置方法
  13. PDF文件如何转成Word?这样操作就能转换
  14. R语言如何做配对t检验?
  15. 编程序,用getchar函数读人两个字符给c1和c2,然后分别用
  16. 苹果手机用户流失严重,竟是因为这个原因?
  17. 电脑快捷键【Crtl】
  18. APP下载量成空洞,留住用户最关键
  19. leetcode 滑动窗口
  20. 横空出世IDEA画图神器来了,比Visio快10倍

热门文章

  1. golang-proxy 具有性能评估功能的高性能免费高匿代理抓取
  2. HTTP 错误代码表_HTTP 错误码大全
  3. curl 模拟 GET\POST 请求,以及 curl post 上传文件
  4. vant ui之选择器
  5. jmeter全局变量有的线程组引用不成功
  6. 海思芯片上GPIO操作
  7. 7种内聚与7种耦合的类型及强弱关系
  8. 在QGIS 3.10中访问Geoserver中发布的服务
  9. Promise原理及手写Promise
  10. [android]使用android自带josn解析