当前位置: 首页 > wzjs >正文

商家网站建设模板seo关键词排名优化软件

商家网站建设模板,seo关键词排名优化软件,网站首页布局设计教程,自己做个网站多少钱Android输入系统在native中的核心工作就是,从Linux驱动设备节点中读取事件,然后将这个事件进行分发,这两项工作分别交给了InputReader和InputDispatcher来做。 他们的源码都属于native层inputflinger里面的一部分,如下架构&#…

Android输入系统在native中的核心工作就是,从Linux驱动设备节点中读取事件,然后将这个事件进行分发,这两项工作分别交给了InputReader和InputDispatcher来做。

他们的源码都属于native层inputflinger里面的一部分,如下架构:

根据Android.bp和目录结构来看,可以进行如下总结:

  • inputflinger并不是一个独立的native进程,它以库的形式存在,即被FW的IMS进行调用
  • inputflinger的核心代码为InputManager.cpp,因此InputManager充当了JNI的角色与FW的IMS进行交互
  • libinputflinger.so依赖于InputReader.cpp和InputDispatcher.cpp,但进行了分离把他们分别封装成为libinputreader.so和libinputdispatcher.so来进行引用,因此后续调试可以专门针对这三个库进行推送调试

一、InputManager与IMS的联系

前文已经提到了InputManager.cpp主要用来和fw层的InputManagerService来进行联系,这里从源码的角度来解析一下他们之间到底是如何联系起来的。其实还是使用了传统的方式,让InputMnagerService通过JNI的方式来调用InputManager.cpp,因此inputflinger的代码是运行在system_server进程里面的

1、system_server进程如何引用libinputflinger.so?

FrameWork层最重要的两个framework.jar和services.jar,已经SystemServer等一系列系统服务都被定义在aosp/framework/base/目录中,有如下信息:

​frameworks/base/services/core/jni/Android.bp  --->集成libinputflinger
frameworks/base/services/core/java/com/android/server/input/InputManagerService.java  --->Android输入系统FW层IMS服务
frameworks/native/services/inputflinger/Android.bp  --->定义libinputflinger
frameworks/native/services/inputflinger/InputManager.cpp  --->Android输入系统Native层管理类
​

因此他们同属一个模块和进程,libinputflinger以库的方式被引用进去。

2、InputManagerService

//frameworks/base/services/core/java/com/android/server/input/InputManagerService.java
public class InputManagerService extends IInputManager.Stub implements Watchdog.Monitor {static final String TAG = "InputManager";// To enable these logs, run: 'adb shell setprop log.tag.InputManager DEBUG' (requires restart)private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);//定义mNative是一个java类,其内部定义了所有的native方法private final NativeInputManagerService mNative;private final Context mContext;private final InputManagerHandler mHandler;private DisplayManagerInternal mDisplayManagerInternal;//...省略...static class Injector {private final Context mContext;private final Looper mLooper;Injector(Context context, Looper looper) {mContext = context;mLooper = looper;}Context getContext() {return mContext;}Looper getLooper() {return mLooper;}//获取NativeInputManagerService实例NativeInputManagerService getNativeService(InputManagerService service) {return new NativeInputManagerService.NativeImpl(service, mLooper.getQueue());}void registerLocalService(InputManagerInternal localService) {LocalServices.addService(InputManagerInternal.class, localService);}}public InputManagerService(Context context) {this(new Injector(context, DisplayThread.get().getLooper()));}InputManagerService(Injector injector) {mContext = injector.getContext();mHandler = new InputManagerHandler(injector.getLooper());//获取NativeInputManagerService实例mNative = injector.getNativeService(this);//后续把mNative实例对象添加到各个模块,为了让IMS系统的native层更加方便的与fw各个模块进行交互mSettingsObserver = new InputSettingsObserver(mContext, mHandler, this, mNative);mKeyboardLayoutManager = new KeyboardLayoutManager(mContext, mNative, mDataStore, injector.getLooper());mBatteryController = new BatteryController(mContext, mNative, injector.getLooper());mKeyboardBacklightController =  KEYBOARD_BACKLIGHT_CONTROL_ENABLED ? new KeyboardBacklightController(mContext,  mNative, mDataStore, injector.getLooper()) : new KeyboardBacklightControllerInterface() {};mKeyRemapper = new KeyRemapper(mContext, mNative, mDataStore, injector.getLooper());mUseDevInputEventForAudioJack = mContext.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="   + mUseDevInputEventForAudioJack);injector.registerLocalService(new LocalService());}public void start() {Slog.i(TAG, "Starting input manager");//非常重要,初始化native层世界所有的C++类mNative.start(); Watchdog.getInstance().addMonitor(this);// Add ourselves to the Watchdog monitors.}//......省略...
}

根据如上代码可以进行如下总结:

  • IMS通过持有NativeInputManagerService对象来控制native世界
  • IMS在服务启动之后通过mNative.start方法来调用native世界对象的start方法进行启动

3、NativeInputManagerService

NativeInputManagerService就是一个单纯的接口,定义了一堆需要和native世界交互的方法。

最终把这些接口方法转换为native层方法,即这些方法的实现全部都在native层里面的那些C++库里面。

这些native方法的根据包名转换到:com_android_server_input_InputManagerService.cpp

 4、JNI如何引用到InputManager.cpp?

  • NativeInputManager对象的构造:改对象直接实例化了InputManager.cpp
//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
//NativeInputManager构造函数
NativeInputManager::NativeInputManager(jobject serviceObj, const sp<Looper>& looper): mLooper(looper), mInteractive(true) {JNIEnv* env = jniEnv();//拿到FW的IMS对象实例mServiceObj = env->NewGlobalRef(serviceObj);//实例化C++世界的核心类InputManager.cppInputManager* im = new InputManager(this, *this);mInputManager = im;//直接像c++世界的servicemanager注册服务inputflinger,注意该方法只是注册服务实例对象,并不是注册进程,这里的进程还是system_server进程defaultServiceManager()->addService(String16("inputflinger"), im);
}
//NativeInputManager析构函数
NativeInputManager::~NativeInputManager() {JNIEnv* env = jniEnv();env->DeleteGlobalRef(mServiceObj);
}
  • nativeInit和nativeStart的实现
//frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static NativeInputManager* getNativeInputManager(JNIEnv* env, jobject clazz) {return reinterpret_cast<NativeInputManager*>(env->GetLongField(clazz, gNativeInputManagerServiceImpl.mPtr));
}
static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject messageQueueObj) {sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);if (messageQueue == nullptr) {jniThrowRuntimeException(env, "MessageQueue is not initialized.");return 0;}static std::once_flag nativeInitialize;NativeInputManager* im = nullptr;std::call_once(nativeInitialize, [&]() {// Create the NativeInputManager, which should not be destroyed or deallocated for the lifetime of the process.//核心代码:创建NativeInputManager实例化对象,其实就是封装了InputManager.cppim = new NativeInputManager(serviceObj, messageQueue->getLooper());});LOG_ALWAYS_FATAL_IF(im == nullptr, "NativeInputManager was already initialized.");return reinterpret_cast<jlong>(im);
}static void nativeStart(JNIEnv* env, jobject nativeImplObj) {NativeInputManager* im = getNativeInputManager(env, nativeImplObj);//核心代码:拿到NativeInputManager实例化对象,并调用start,就是调用了InputManager.start方法status_t result = im->getInputManager()->start();if (result) {jniThrowRuntimeException(env, "Input manager could not be started.");}
}

    综上,IMS与InputManager的关系如下,system_server进程的IMS通过JNI的方式启动了native世界的InputManager.cpp的start方法。

    5、InputManager的封装

    综上所述,从IMS到InputManager之间的关系如下图:

    二、InputReader事件读取

    InputReader事件读取的原理就是直接从驱动设备节点/dev/input/里面读取事件,通常有多个输入设备,在我手上的这台Android平板的该目录如下:

    • 在我触摸屏幕的时候event3节点文件中会打印数据:

    • 在我按音量-的时候event0节点文件中会打印数据
    • 在我按音量+的时候event2节点文件中会打印数据
    • 输入getevent命令可以直接获取/dev/input/里面的事件:

    1、EventHub

    InputReader事件读取的原理就是直接从驱动设备节点/dev/input/里面读取事件。如果对应设备有事件,例如鼠标事件,屏幕触摸事件,驱动会直接向这些节点写入数据。

    • 设备节点的路径:他的日志可以过滤EventHub

    • 设备节点的读取:EventHub.cpp做的事情就是从这个节点里面读取数据,并进行封装整理成为events向量:如下代码,这里我直接引用https://xiaoxu.blog.csdn.net/article/details/146344278
    size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {……RawEvent* event = buffer;size_t capacity = bufferSize;bool awoken = false;for (;;) {nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);// 如果需要,重新打开输入设备if (mNeedToReopenDevices) {mNeedToReopenDevices = false;closeAllDevicesLocked();mNeedToScanDevices = true;break; // return to the caller before we actually rescan}// 报告最近添加/删除的任何设备for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) {std::unique_ptr<Device> device = std::move(*it);ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str());event->when = now;event->deviceId = (device->id == mBuiltInKeyboardId)? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID : device->id;event->type = DEVICE_REMOVED;event += 1;it = mClosingDevices.erase(it);mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}}// 扫描新的输入设备,第一次为trueif (mNeedToScanDevices) {mNeedToScanDevices = false;// 打开 /dev/input/ 目录下的input设备后,将其注册到epoll的监控队列中。scanDevicesLocked();mNeedToSendFinishedDeviceScan = true;}// 报告设备添加事件while (!mOpeningDevices.empty()) {std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin());mOpeningDevices.pop_back();ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str());event->when = now;event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;// 对于新开的设备,生成一个 DEVICE_ADDED 类型的 RawEvent 并添加到输出缓冲区。event->type = DEVICE_ADDED;event += 1;// 尝试为设备匹配相应的视频设备(如触摸屏),并将设备信息插入到 mDevices 映射中for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end(); it++) {std::unique_ptr<TouchVideoDevice>& videoDevice = *it;if (tryAddVideoDeviceLocked(*device, videoDevice)) {// videoDevice was transferred to 'device'it = mUnattachedVideoDevices.erase(it);break;}}auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device));if (!inserted) {ALOGW("Device id %d exists, replaced.", device->id);}mNeedToSendFinishedDeviceScan = true;if (--capacity == 0) {break;}}// 发送设备扫描完成通知if (mNeedToSendFinishedDeviceScan) {mNeedToSendFinishedDeviceScan = false;event->when = now;event->type = FINISHED_DEVICE_SCAN;event += 1;if (--capacity == 0) {break;}}// 处理待处理事件队列中的下一个输入事件bool deviceChanged = false;while (mPendingEventIndex < mPendingEventCount) {const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++];// 处理INotify事件if (eventItem.data.fd == mINotifyFd) {if (eventItem.events & EPOLLIN) {mPendingINotify = true;}//...省略....continue;}// 处理唤醒管道事件if (eventItem.data.fd == mWakeReadPipeFd) {if (eventItem.events & EPOLLIN) {ALOGV("awoken after wake()");awoken = true;char wakeReadBuffer[16];ssize_t nRead;do {nRead = read(mWakeReadPipeFd, wakeReadBuffer, sizeof(wakeReadBuffer));} while ((nRead == -1 && errno == EINTR) || nRead == sizeof(wakeReadBuffer));}//...省略....continue;}// 处理输入设备事件Device* device = getDeviceByFdLocked(eventItem.data.fd);//...省略....// 处理触摸屏输入事件if (device->videoDevice && eventItem.data.fd == device->videoDevice->getFd()) {//...省略....continue;}// 处理标准输入设备事件// 对于标准输入设备(如键盘、鼠标等),检查是否有可读事件 (EPOLLIN)if (eventItem.events & EPOLLIN) {// 从device中得到fd后再去读取设备,获取input事件int32_t readSize = read(device->fd, readBuffer, sizeof(struct input_event) * capacity);if (readSize == 0 || (readSize < 0 && errno == ENODEV)) {// 读取失败或设备已被移除,则关闭该设备deviceChanged = true;closeDeviceLocked(*device);} //...省略....else {// 读取成功,将每个input_event转换为RawEvent并添加到输出缓冲区中int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;size_t count = size_t(readSize) / sizeof(struct input_event);for (size_t i = 0; i < count; i++) {struct input_event& iev = readBuffer[i];event->when = processEventTimestamp(iev);event->readTime = systemTime(SYSTEM_TIME_MONOTONIC);event->deviceId = deviceId;event->type = iev.type;event->code = iev.code;event->value = iev.value;event += 1;capacity -= 1;}if (capacity == 0) {// 缓冲区已满。重置挂起的事件索引,等待下一次再次尝试读取设备。mPendingEventIndex -= 1;break;}}} else if (eventItem.events & EPOLLHUP) {// 处理挂起事件 (EPOLLHUP),则关闭该设备deviceChanged = true;closeDeviceLocked(*device);}//...省略....}// 如果存在未处理的 INotify 事件并且所有待处理事件都已处理完毕if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) {mPendingINotify = false;// 处理设备节点的变化readNotifyLocked();deviceChanged = true;}// 报告添加或移除的设备if (deviceChanged) {continue;}//...省略....// 等待更多事件的到来int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);//...省略....// 所有操作完成后,返回我们读取的事件数return event - buffer;
    }
    • events3节点:从下面的代码来看有些怀疑专门针对屏幕的定制,但具体代码有带研究

    2、InputReader的轮询

    1)InputReader开启线程轮询

    InputReader的构造函数和start与stop方法如下,其核心就是通过封装的InputThread类来创建线程,线程名为InputReader,并在EventHub收到事件的时候唤起,调用loopOnce函数。

    2)loopOnce

    //frameworks/native/services/inputflinger/reader/InputReader.cpp
    void InputReader::loopOnce() {int32_t oldGeneration;int32_t timeoutMillis;bool inputDevicesChanged = false;std::vector<InputDeviceInfo> inputDevices;std::list<NotifyArgs> notifyArgs;//流程1:读取驱动设备节点的事件数据,并以RawEvent数组的方式进行封装std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);{ // acquire lockstd::scoped_lock _l(mLock);mReaderIsAliveCondition.notify_all();if (!events.empty()) {//流程2:成功读取到事件之后,通过processEventsLocked进行解析,并以NotifyArgs数组的方式进行封装notifyArgs += processEventsLocked(events.data(), events.size());}//....省略....} // release lock//...省略...//流程3:遍历mQueuedListener队列中所有的监听器,并发布事件,其实就是进行所有设备的事件分发notifyAll(std::move(notifyArgs));//流程4:更新队列mQueuedListener.flush();
    }
    void InputReader::notifyAll(std::list<NotifyArgs>&& argsList) {for (const NotifyArgs& args : argsList) {mQueuedListener.notify(args);}
    }

    在一次轮询中,核心的任务就两个:

    • 读取原始数据格式的RawEvent事件,然后并封装成NotifyArgs事件
    • 然后遍历所有监听器,进行事件分发,实际上搞了一个装饰者模式,讲不同类型的事件分发出去,这块逻辑我们在事件分发的时候详细介绍

    三、InputDispatcher事件分发

    http://www.dtcms.com/wzjs/332448.html

    相关文章:

  • 网站建设 合优网络廊坊seo排名公司
  • 网页广告设计师培训搜索引擎优化指的是
  • Springmvc网站开发实例青海seo技术培训
  • 做外贸如何通过网站精准找到老板联系方法如何做推广
  • 新手学做网站必备软件百度刷排名优化软件
  • 代码wordpress夫唯seo视频教程
  • 果麦传媒的网站怎么做的秘密入口3秒自动进入
  • 网站免费优化软件徐州百度推广电话
  • 常用网站建设软件免费推广引流平台
  • wordpress 个性主题seo优化诊断
  • 青浦网站建设推广郑州seo优化培训
  • 哪些网站可以做推广域名注册查询入口
  • 淘宝网站运营的工作怎么做百度首页
  • 东莞市主营网站建设平台优化seo搜索
  • 做摄影和后期的兼职网站房地产销售怎么找客户
  • wordpress七牛远程图片seo数据
  • 残疾人招聘网站建设企业网页制作
  • 阿泰勒北京网站建设b站推广网站2024mmm
  • 做外贸独立网站怎么样代运营公司可靠吗
  • 易迈互联网站建设怎么样百度数据中心
  • 深圳做网站建设比较好的公司谷歌浏览器下载电脑版
  • 国外对旅游网站的建设营销型网站建设公司价格
  • 昆山住房和城乡建设局网站首页b2b外链代发
  • 装修网站制作外链网
  • 网站建站中关键字搜索怎么弄淘宝店铺怎么免费推广
  • 网站建设作业多少钱在线crm
  • 在网上做效果图的网站可以推广的软件有哪些
  • java可以用来做网站吗百度动态排名软件
  • 做广告在哪个网站做效果人流最多下载app到手机上并安装
  • python 和php网站开发销售方案怎么做