Android输入系统(一)——初始化阶段(基于Android 13)

2023-11-11

1 输入事件的处理流程

请添加图片描述

输入系统大致可分为三部分,输入系统部分、WMS部分和View处理部分。用户输入需要通过输入子系统将原始信息转化为事件交由InputManagerService进行处理加工并找到合适的Window,将事件分发到对应的Window。

2 InputManagerService的创建

2.1 SystemServer创建IMS

SystemServer初始化从main方法开始
frameworks/base/services/java/com/android/server/SystemServer.java

public static void main(String[] args) {
    new SystemServer().run();
}

main方法中只是调用了SystemServer的run方法。
frameworks/base/services/java/com/android/server/SystemServer.java

private void run() {
	...
	// Start services.
  try {
      t.traceBegin("StartServices");
      startBootstrapServices(t); //启动引导服务
      startCoreServices(t); //启动核心服务
      startOtherServices(t); //启动其他服务
      startApexServices(t); //启动apex相关的服务
  } catch (Throwable ex) {
      Slog.e("System", "******************************************");
      Slog.e("System", "************ Failure starting system services", ex);
      throw ex;
  } finally {
      t.traceEnd(); // StartServices
  }
  ...

在run方法中启动了各种系统服务,其中IMS是在其他服务中启动的。
frameworks/base/services/java/com/android/server/SystemServer.java

private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
	...
	InputManagerService inputManager = null;
	...
	t.traceBegin("StartInputManagerService"); //1
  inputManager = new InputManagerService(context);
  t.traceEnd();
  ...
  t.traceBegin("StartWindowManagerService"); //2
  // WMS needs sensor service ready
  mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
  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);
  t.traceEnd();
  ...
  t.traceBegin("StartInputManager"); //3
  inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
  inputManager.start();
  t.traceEnd();
  ...

这里截取了其中IMS被WMS创建和启动的部分。IMS使用的是InputManagerService类的构造器去创建的,后面调用IMS的start方法去启动。WMS则是通过WMS的main方法去创建的,其中第二个参数就是上面创建的IMS的对象,这样IMS就和WMS相关联了,接着将WMS和IMS添加到ServiceManager进行管理。

2.2 InputManagerService的构造函数

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

/** Point of injection for test dependencies. */
@VisibleForTesting
static class Injector {
    private final Context mContext;
    private final Looper mLooper;

    Injector(Context context, Looper looper) {//1
        mContext = context;
        mLooper = looper;
    }

    Context getContext() {
        return mContext;
    }

    Looper getLooper() {
        return mLooper;
    }

    NativeInputManagerService getNativeService(InputManagerService service) {
        return new NativeInputManagerService.NativeImpl(service, mContext, mLooper.getQueue());
    }

    void registerLocalService(InputManagerInternal localService) {
        LocalServices.addService(InputManagerInternal.class, localService);
    }
}

public InputManagerService(Context context) {
    this(new Injector(context, DisplayThread.get().getLooper())); //2
}

@VisibleForTesting
InputManagerService(Injector injector) {
    // The static association map is accessed by both java and native code, so it must be
    // initialized before initializing the native service.
    mStaticAssociations = loadStaticInputPortAssociations();

    mContext = injector.getContext();
    mHandler = new InputManagerHandler(injector.getLooper()); //3
    mNative = injector.getNativeService(this); //4

    mUseDevInputEventForAudioJack =
            mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
    Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
            + mUseDevInputEventForAudioJack);

    String doubleTouchGestureEnablePath = mContext.getResources().getString(
            R.string.config_doubleTouchGestureEnableFile);
    mDoubleTouchGestureEnableFile = TextUtils.isEmpty(doubleTouchGestureEnablePath) ? null :
            new File(doubleTouchGestureEnablePath);

    injector.registerLocalService(new LocalService());
}

注释2处是InputManagerService的构造函数,调用的是InputManagerService(Injector injector)这个重载的构造函数,传入的参数是一个新建的Injector对象,调用注释1处的Injector静态内部类的构造函数,传入的是android.display线程的Looper,在注释3处获取该Looper来创建InputManagerHandler对象。这样InputManagerHandler就运行在android.display线程,该线程是系统共享的单例前台线程,这个线程内部执行了WMS的创建。
注释4处调用了Injector类中的getNativeService方法,返回的是NativeInputManagerService.NativeImpl的一个实例对象。
frameworks/base/services/core/java/com/android/server/input/NativeInputManagerService.java

class NativeImpl implements NativeInputManagerService {
    /** Pointer to native input manager service object, used by native code. */
    @SuppressWarnings({"unused", "FieldCanBeLocal"})
    private final long mPtr;

    NativeImpl(InputManagerService service, Context context, MessageQueue messageQueue) {
        mPtr = init(service, context, messageQueue); 
    }
    private native long init(InputManagerService service, Context context,
                MessageQueue messageQueue); //1
    ...
}

初始化调用的是native层的init方法。
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;
    }

    NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
            messageQueue->getLooper());//1
    im->incStrong(0);
    return reinterpret_cast<jlong>(im);
}

在注释1处创建了InputManager,构造函数如下:
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 = env->NewGlobalRef(serviceObj);

    {
        AutoMutex _l(mLock);
        mLocked.systemUiLightsOut = false;
        mLocked.pointerSpeed = 0;
        mLocked.pointerAcceleration = android::os::IInputConstants::DEFAULT_POINTER_ACCELERATION;
        mLocked.pointerGesturesEnabled = true;
        mLocked.showTouches = false;
        mLocked.pointerDisplayId = ADISPLAY_ID_DEFAULT;
    }
    mInteractive = true;

    InputManager* im = new InputManager(this, this);//1
    mInputManager = im;
    defaultServiceManager()->addService(String16("inputflinger"), im);
}

注释1处创建了InputManager对象,并将其添加到servicemanager进行管理。
frameworks/native/services/inputflinger/InputManager.cpp

InputManager::InputManager(
        const sp<InputReaderPolicyInterface>& readerPolicy,
        const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
    mDispatcher = createInputDispatcher(dispatcherPolicy); //1
    mClassifier = std::make_unique<InputClassifier>(*mDispatcher);
    mBlocker = std::make_unique<UnwantedInteractionBlocker>(*mClassifier);
    mReader = createInputReader(readerPolicy, *mBlocker); //2
}

InputManager的构造函数中创建了InputDispatcher(注释1处)和InputReader(注释2处)。InputReader会不断读取EventHub中的原始信息进行加工并交给InputDispatcher,InputDispatcher中保存了Window的信息,可以将事件信息派发到合适的窗口。InputReader和InputDispatcher都是耗时的操作,在单独的线程中执行。

2.3 InputDispatcher和InputReader初始化

  • InputDispatcher的初始化

frameworks/native/services/inputflinger/dispatcher/InputDispatcherFactory.cpp

std::unique_ptr<InputDispatcherInterface> createInputDispatcher(
        const sp<InputDispatcherPolicyInterface>& policy) {
    return std::make_unique<android::inputdispatcher::InputDispatcher>(policy);
}

使用std:make_unique调用InputDispatcher的构造函数,其构造函数如下:
frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy,
                                 std::chrono::nanoseconds staleEventTimeout)
      : mPolicy(policy),
        mPendingEvent(nullptr),
        mLastDropReason(DropReason::NOT_DROPPED),
        mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
        mAppSwitchSawKeyDown(false),
        mAppSwitchDueTime(LONG_LONG_MAX),
        mNextUnblockedEvent(nullptr),
        mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),
        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(kDefaultInTouchMode),
        mMaximumObscuringOpacityForTouch(1.0f),
        mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
        mWindowTokenWithPointerCapture(nullptr),
        mStaleEventTimeout(staleEventTimeout),
        mLatencyAggregator(),
        mLatencyTracker(&mLatencyAggregator) {
    mLooper = new Looper(false);
    mReporter = createInputReporter();

    mWindowInfoListener = new DispatcherWindowListener(*this);
    SurfaceComposerClient::getDefault()->addWindowInfosListener(mWindowInfoListener);

    mKeyRepeatState.lastKeyEntry = nullptr;

    policy->getDispatcherConfiguration(&mConfig);
}

InputDispatcher的构造函数中创建了Looper和InputReporter,也创建了对于Window的监听器。

  • InputReader初始化

frameworks/native/services/inputflinger/reader/InputReaderFactory.cpp

std::unique_ptr<InputReaderInterface> createInputReader(
        const sp<InputReaderPolicyInterface>& policy, InputListenerInterface& listener) {
    return std::make_unique<InputReader>(std::make_unique<EventHub>(), policy, listener);
}

使用std:make_unique调用InputDispatcher的构造函数,其构造函数如下:
frameworks/native/services/inputflinger/reader/InputReader.cpp

InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
                         const sp<InputReaderPolicyInterface>& policy,
                         InputListenerInterface& listener)
      : mContext(this),
        mEventHub(eventHub),
        mPolicy(policy),
        mQueuedListener(listener),
        mGlobalMetaState(AMETA_NONE),
        mLedMetaState(AMETA_NONE),
        mGeneration(1),
        mNextInputDeviceId(END_RESERVED_ID),
        mDisableVirtualKeysTimeout(LLONG_MIN),
        mNextTimeout(LLONG_MAX),
        mConfigurationChangesToRefresh(0) {
    refreshConfigurationLocked(0);
    updateGlobalMetaStateLocked();
}

初始化了EventHub等参数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android输入系统(一)——初始化阶段(基于Android 13) 的相关文章

  • 如何制作在手机和平​​板电脑上使用的响应式Android应用程序?

    我创建了一个 Android 应用程序 当我运行我的应用程序时Mobile Phone它工作得很好 但是当我跑进去时Tablet应用程序的布局已更改 那么 如何制作响应式Android应用程序用于Mobile并且也在Tablet 在Andr
  • Java Microsoft Excel API [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • JFace ColumnWeigthData 导致父级增长

    我有一个 Eclipse RCP 应用程序 并且想要在TableViewer using ColumnWeigthData as ColumnLayoutData 问题是父表单 ScrolledForm在示例代码中 每当我布局表格时都会增加
  • 如何在 Eclipse 中使用其他外部 jar 依赖项创建不可运行/不可执行的 jar

    我无法通过 Eclipse 导出向导创建普通的 jar 不可运行 不可执行 它仅创建 jar 文件 但不会导出依赖的 jar 从而在从其他类调用导出的 jar 的方法时出现错误 请帮助 非常感谢 kurellajunior的建议 它是通过使
  • Android 时钟滴答数 [赫兹]

    关于 proc pid stat 中应用程序的总 CPU 使用率 https stackoverflow com questions 16726779 total cpu usage of an application from proc
  • 所有平台上的java

    如果您想用 java 为 Windows Mac 和 Linux 编写桌面应用程序 那么所有这些代码都相同吗 您只需更改 GUI 即可使 Windows 应用程序更像 Windows 等等 如果不深入细节 它是如何工作的 Java 的卖点之
  • android textview 有字符限制吗?

    我正在尝试在 android TextView 中输入超过 2000 3000 个字符 它不显示任何内容 任何一份指南是否对 android textview 有字符限制或什么 我在G3中做了一些小测试 我发现 如果activtiy布局中有
  • 当您在数组列表上调用remove(object o)时,它如何比较对象?

    当您在 java 中的数组列表上调用remove object o 时 它如何比较对象以找到要删除的正确对象 它使用指针吗 或者它使用 Comparable 接口来比较对象吗 ArrayList remove 依赖于对象的实现Equal方法
  • 屏幕开/关检测

    在这里 我试图确定屏幕是否打开 但按下电源锁定 解锁按钮时它似乎不起作用 应用程序运行没有错误 但 if else 中的代码似乎没有效果 Edited现在代码可以工作了 谢谢Olgun 但媒体播放器播放不会停止 并且每次在屏幕上 离屏时都会
  • SDK >=26 仍需要 mipmap/ic_launcher.png?

    在 Android 中 有两种指定启动器图标 可以说是应用程序图标 的方法 老 方式 在 mipmap 文件夹中指定不同的 png 文件 通常命名为 ic launcher png 但可以通过以下方式设置名称android icon mip
  • 是否可以使用 CardView 为浮动操作按钮制作阴影?

    I know CardView不是为此而设计的 但理论上如果cardCornerRadius view size 2它应该导致圆圈 我错过了什么吗 绘制真实的动画阴影并不困难 您可以尝试在 Froyo 等任何 Android 设备上实现 L
  • 创建正则表达式匹配数组

    在Java中 我试图将所有正则表达式匹配返回到一个数组 但似乎您只能检查模式是否匹配某些内容 布尔值 如何使用正则表达式匹配来形成与给定字符串中的正则表达式匹配的所有字符串的数组 4城堡的回答 https stackoverflow com
  • 我在 PopupMenu 中使用 ShareActionProvider,但显示两个 PopupMenu?

    我在 PopupMenu 中使用 ShareActionProvider 但是当我单击共享菜单项时 它会在屏幕上显示两个 PopupMenus 一个被另一个覆盖 一个显示应用程序图标和名称 另一个仅显示应用程序名称 除了这个问题之外 它工作
  • 由于“进程崩溃”,仪器运行失败。

    我想运行以下测试 package com xxx yyy import android content Context import androidx test InstrumentationRegistry import androidx
  • JavaFX - 为什么多次将节点添加到窗格或不同的窗格会导致错误?

    我现在正在学习基本的 JavaFX 我不明白我正在阅读的书中的这一说法 不 诸如文本字段之类的节点只能添加到一个窗格中一次 将节点添加到多次窗格或不同的窗格将导致运行时错误 我可以从书中提供的UML图看出它是一个组合 但我不明白为什么 库类
  • 无法使用文件提供程序从内部存储打开 PDF 以便在 Android 8 和 9 上查看

    仅适用于 Android 8 和 9 我这里有一个 PDF 文件管理器 String url file storage emulated 0 Android data com verna poc files Download mypdf p
  • Fragment 生命周期和在不存在的 Fragment 上调用 onCreate 的问题

    我正在 Android 中测试片段 并且片段生命周期有一些令人困惑的行为 我有一个活动 在横向和纵向模式下使用 xml 布局 我有一些代码可以访问在片段布局之一中定义的 EditText 对象 如果我以横向模式启动应用程序 一切都会正常 我
  • 摩尔斯电码 至 英语

    我现在的问题是让 摩尔斯电码转英语 正常工作 将英语转换为莫尔斯电码的第一部分工作正常 我知道以前已经有人问过这个问题 但我不知道我做错了什么 我知道我需要在某个地方进行拆分 但我只是不确定将其放在代码中的何处 现在 莫尔斯电码到英语的部分
  • 如何正确编写AttributeSet的XML?

    我想创建一个面板适用于 Android 平台的其他小部件 http code google com p android misc widgets 在运行时 XmlPullParser parser getResources getXml R
  • 为什么范围为“provided”的依赖项会隐藏 Maven 中的传递依赖项?

    我的 Maven 项目中有三个模块 这稍微简化了 model包含JPA注释的实体类 坚持实例化一个实体管理器并调用它的方法 应用创建类的实例model 设置一些值并将它们传递给坚持 model and 坚持显然取决于javax persis

随机推荐

  • IDEA+Maven的JAVA开发环境配置

    本文记录了在windows上配置Hadoop Java开发环境的全过程 本次实验使用系统为Win10 其中Maven的安装位置为D 程序文件 源代码 Java apache maven 3 8 4 bin apache maven 3 8
  • token的生成与验证

    写在前面 最近在写自己毕业的东西 由于采用的是前后端分离的写法 为了方便写使用的是跨域的模式 所以cookie session就不好用了 所以记录一下token吧 夜太深了 就简单写一下用法吧 官方文档写的很全了 使用场景 用户成功登陆之后
  • 互联网业务全球化互通组网

    随着互联网业务的快速发展 越来越多的企业开始全球化扩张业务 并需要在全球范围内建立互联网组网以实现业务数据的高效传输 在这个过程中 如何建立高效 稳定的全球互联网组网方案 是每个企业都需要考虑的问题 一种可行的方案是使用云网络加速服务 例如
  • shell中打印带有时间的日志的命令(转)

    echo date Y m d H M S logadm on date Y m d H M S 2013 09 30 11 42 48 logadm on 20130930114248 转载于 https www cnblogs com
  • mobile.php discuz,电脑访问discuz手机版【触屏版跳转标准版的修改方法】

    推荐方法 以前我们介绍过如何通过修改Chrome浏览器运行参数的方法来模拟手机访问网站 但是在Chrome 32和33版本以后增加了更加便捷的方法 在开发者工具中只需要设置一下就能方便的模拟各种手机型号的访问效果了 方法如下 1 打开Chr
  • 作用域【python-4】

    file author jUicE g2R qq 3406291309 彬 bin 必应 一个某双流一大学通信与信息专业大一在读的技术彩笔 brief python小白入门笔记 copyright 2022 8 COPYRIGHT 原创技术
  • windows脚本 批量删除指定文件夹、指定文件

    前言 用于批量删除项目中的测试数据 提供用户纯净的软件 使用说明 修改file list和folder list对应的数据 来自定义删除的内容 效果图 源码 echo off chcp 65001 gt nul 2 gt 1 REM 设置文
  • Errors accessing files.There may be spaces in your image‘s filename (已解决)

    一 问题 最近要做一个识别身份证的 然后就拷贝改代码 用到了Tesseract OCR 没想到出了这问题 说我文件名有空格 但是我这边确实没有啊 二 解决 上面框起来的地方是语言包 我想了想一般下载的时候好像没有相关的连带下载 然后去文件夹
  • Python3,爬虫的HTTP Error、URL Error及混合使用

    爬虫常出现的两种error URL Error HTTP Error HTTP Error 和URL Error 混合使用 URL Error url error 很常见的 就是url地址不正确 或者失效 我们来看看 代码是怎么实现的 co
  • 服务器被攻击了怎么处理?

    服务器若是被黑客或是攻击小组攻击 不同的机房会做出不同的策略调整 封机处理 一般2小时解封 最迟24小时 若是解封后仍然有攻击 则封机时间会增加24 48 72H 再安全的服务器也避免不了网络的攻击 作为一个网络安全运维人员需要做到维护好系
  • SD卡寄存器及对应的CMD命令描述

    目录 1 SD卡寄存器 1 1操作条件寄存器 OCR 1 2卡识别寄存器 CID 1 3特定数据寄存器 CSD 1 4相对地址寄存器 RCA 1 5驱动阶段寄存器 DSR 1 6SD配置寄存器 SCR 1 7SD状态寄存器 SSR 1 8卡
  • signature=5e1766d4239e5ac6aef18e8849a2555c,checksum.xml

    4FD71D2654435626B5FC1D5FB47809D322D9AC3AEDE1A45D1A45070B1820C922522C7D1586CD1C074F3F27D9E73C8F51F554AEE0F07A08ECB6593CAF
  • One-Way Conveyors 【Tarjan缩点+树链剖分】

    One Way Conveyors Aizu 1408 这道题上面推荐大家把maxN开的大一点 不然会RE 我倒是被这个坑了一下 还有一些细节 我将在后面徐徐道来 目前最快还是比较的开心 先讲一下题意 有N个点 M条无向边 然后输入这M条无
  • 回顾与展望

    原文链接 点击打开链接 摘要 8月14日启动 历时130天 全球AI届最大盛事之一 来自65个国家上万名选手参与的首届 AI Challenger全球AI挑战赛 在12月21日落下帷幕 AI Challenger视觉和翻译两大类共五个赛道
  • java快速开发框架---JavaBoot

    基于SpringBoot2倾情打造 面向所有层次的Java开发者 零门槛开箱即用的后台快速开发解决方案 1 系统环境 我们采取了Java EE 8 Servlet 3 0 Apache Maven 3作为环境开发的一套后台的系统 入门快 2
  • 【SSA-LSTM】基于麻雀算法优化LSTM 模型预测研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 1 1 麻雀搜索算法 1 2 长短期记忆神经网络 2 运行结果 3 参考文献 4 Matlab代码实现 1
  • x86架构芯片启动过程分析

    1 上电启动顺序 上电自检 读取ROM里的bios程序 bios程序会进行硬件检测 比如 内存 硬盘 显卡等 bios完成自检后 需要选择引导设备 比如设备上有U盘 SSD eMMC 机械硬盘 bios需要知道从哪个启动介质去启动计算机 b
  • (android地图开发) 高德地图自定义对话框

    截图效果 布局文件
  • 【Python】不用numpy用纯python求极差、平均数、中位数、众数与方差,python的打印到控制台

    python作为数据分析的利器 求极差 平均数 中位数 众数与方差是很常用的 然而 在python进行统计往往要使用外部的python库numpy 这个库不难装 然而 如果单纯只是求极差 平均数 中位数 众数与方差 还是自己写比较好 因为
  • Android输入系统(一)——初始化阶段(基于Android 13)

    1 输入事件的处理流程 输入系统大致可分为三部分 输入系统部分 WMS部分和View处理部分 用户输入需要通过输入子系统将原始信息转化为事件交由InputManagerService进行处理加工并找到合适的Window 将事件分发到对应的W