三思系列是我最新的学习、总结办法,着重于:问题剖析、技术堆集、视界拓展,关于三思系列
这次,真的能够一文吃透:
- Java层音讯部队的规划
- Java层Looper分发
- Native层音讯部队和Java层音讯部队的联络
- Native层Looper分发
- 消架构师证书怎样考息
- epoll
前言
作为Andrshell脚本oid中 至关重要
的机制之一,十多年来,剖析它的linux体系文章不断,许多的内容现已Shell被发掘过了。所以:
- 现已对这一机制比较
熟稔
的读者,在这篇文章中,看不到新东西
了。 - 还不太熟悉音讯机制的读者,能够在文章的基础上,持续挖一挖。
可是,经过简略的检索和剖析,大部分
的文章是盘绕:
- Handler,Looper,MQ的联络
- 上层的Handler,Looper、MQ 源码剖析
翻开的。单纯的从这些视点学习的话,并不能 彻底理解
音讯appear机制。
这篇文章本质仍是 一次脑暴
,一来 防止脑暴跑偏
,二来帮忙读者 捋清内容头绪
。先放出脑图:
脑暴:OS处理进程间通讯问题
程序世界中android什么意思,存在着许多的 通讯
场景。查找咱们的常识,处理 进程间通讯
问题有linux体系以下几种办法:
这段内容能够泛读,了解就行,不影响往下阅读
- 管道
一般管道pipe:一种
半双工
的通讯办法,数据只能单向活动
,并且只能在具有亲缘联络
的进程间运用。指令流管道s_pipeshell怎样读:
全双工
,能够一起双向传输命名管道FIFO:
半双工
的通讯办法,容许
在无亲缘联络
的进程间通讯。- 音讯部队 MessageQueue:
音讯的链表
,存放在内核
中 并由音讯部队标识符
标识。
音讯部队克服了信号传递信息少
、管道
只能承载无格局字节省
以及缓冲区大小受限
等缺点。
- 同android/yunos享存储 SharedMeapprovemory:
映射一段
能被其他进程所拜访
的内存,这段同享内存由一个进程创立
,但多个进程都能够拜访
。
同享内存是最快的 IPC 办法
,它是针对其他
进程间通讯办法作业功率低
而专门规划的linux操作体系基础知识。
往往与架构师证书怎样考其他通讯机制一起运用,如信号量
协作运用,来结束进程间的同步和通讯。APP
- 信号量 Semaph架构规划ore:
是一个
计数器
,能够用来操控多个进程对同享资源的拜访。它常作为一种锁机制
,防止某进程正在拜访同享资源时,
其他进程也拜访该资源,结束资源的进程独占
。因而,首要作为进程间
以及同一进程内线程间
的同步办法。
- 套接字Sockeshell脚本编程100例t:
与其他通讯机制不同的是,它能够
经过网络
,在不同机器之间
进行进程通讯。
- 信号 signal:
用于告知接收进程
某作业已发生
。机制比较复杂。
咱们能够想象,Android之间也有许多的 进程间通讯场景android手机
,OS有必Android要选用 至少一种
机制,以结束进程间通讯架构中考。
细心研讨下去,咱们发现,Android OS用了不止一种办法appear。并且,Android 还根据 OpenBinder
开发了 Binder
用于 用户空间
内的架构是什么意思进程间通讯。
关于 为什么不直接运用Linux中现有的进程间通讯办法 ,能够看看这篇appstore知乎问答
这篇文章 也简略探讨了 “内核空间内的音讯部队”
这架构师和程序员的差异儿咱们留一个问题今后根究:
Anlinux中文乱码视频droid 有没有运用 Linandroid下载软件appux内核中的MessageQueue机制 干作业
根据音讯部队的音讯机制规划有许多优势,Android 在许多通讯场景内shellfish,选用了这一linux常用指令规划思路。
音讯机制的三要素
不论在哪,咱们谈到音讯机制,都会有这三个要素:
音讯部队
音讯循环(分发)
音讯处理
音讯部队
,是 音讯方针
的部队,根柢规则是 FIFO
。
音讯循环(分发)
, 根柢是通用的机制,运用 死循环
不断的取出音讯部队头部的音讯,派发实施
音讯处理
,这儿不得不说到 音讯
有两种办法:
- Enrichment 本身信息齐备
- Query-Back 本身信息不齐备,需linux体系求回查
这两者的取舍,首要看体系中 生成音讯的开支
和 回查信息的开支
两者的博弈。
在信息齐备后,接收者即可处理音讯。
Android Framework中的音讯部队
And架构中考roid 的Framework中的音讯部队有两个:
- Java层
frameworks/base/core/java/架构师和程序员的差异android/os/MessageQueue.java
- Naandroid11tive层
frameworks/base/core/jni/android_os_架构师薪酬一月多少MessageQueue.cpp
Java层的MQ并不是 List
或许 Queue
之类的 Jdk内的linux必学的60个指令数据结构结束。
NativShelle层的源码我下载了一份 AndrAPPoid 10 的 源码 ,并不长,咱们能够无缺的读一读。
并不难理解:
用户空架构师薪酬一月多少间
会接收到来自内核Shell空间
的音讯
, 从下图
咱们可知架构师薪酬一月多少,这部分音讯先被Native层
获悉,所以:
- 经过
Native层
建立音讯部队,它具有音讯部队的各种根柢才华- 运用
JNI
打通Java层
和Native层
的Runtime屏障
,在Japproveava层映射
出音讯部队- 运用建立在Java层之上,在Java层中结束音讯的
分发
和处理
PSshellfish:在Android 2.3那个时代,架构规划音讯部队的结束是在linux体系装置Java层的,至于10年前为何改成了 nativshell指令e结束,
估测和CPU空转有关,笔者没有持续根究下去,假定有读者了解,希望能够留言帮我解惑。
PS:还有一张经典的 体系启动架构图
没有找到,这张图愈加直观
代android的drawable类码解析
咱们简略的 阅读、剖析 下Native中的MQ源码
Native层音讯部队的创立:
static jlong androiapproved_os_MessageQueue_nativeandroid手机Inilinuxt(JNIEnv* env, jclass clazz) {
Natilinux运维是必死之路veMessageQueue* nativeMessageQueue = new NativeMessageQueue();
if (!nativeMessageQueue) {
jniThrowRuntimeException(env, "Unable to allocate native queue")架构;
return 0;
}
nativeMessageQueue->shell指令incStrong(env);
return reinterpret_cast<jlong>(nativeMessaandroid下载软件appgeQueue);
}
很简略,创立一个Native层的音讯队linux体系伍,假定创立失利,抛异常信息,回来0,不然将指针转换为Java的long型值回android体系来。当然,会被Java层的app装置下载MQ所持有
。
NativeMessageQueue
类的结构函数
NativeMessageQueue::NativeMessageQueue() :
mPolllinux运维是必死之路Env(NULL), mPollObj(shelly-lanNULL), mExceptionObj(NULL) {linux是什么操作体系
mLooper = Looper::getForThread();
if (mLooper == NULL) {
mLooper = newshell脚本根本指令 Looper(false);
Looper::setForThread(mLooper);
}
}
这儿的Looper是shellfishnative层Looper,经过静态办法 Looper::getForThread()
获取方针实例,假定未获取到,则创架构师建实例,并经过静态办法设置。
看一下Java层MQ中会运用到的native办法
class MessageQueue {
private long mPtr; // used by native code
private native static long nativeInit();
private native static void nativeDestroy(long ptr);
private native void nativePollOnce(lon架构g ptr, int timeoutMillis); /*non-static for callbacks*/
private native static void nativeWake(long ptr);
private native static boolean nativeIsPolling(long ptr)架构师;
private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events);
}
对应签名:
static const JNINativeMandroid下载软件appe架构图怎样做wordthod gMessageQuappleideueMethods[] = {
/* name, siglinux是什么操作体系nature, funcPtr */
{ "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInitAndroid },
{ "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
{ "shellfishnativeShellPoandroid什么意思llOnce", "(JI)V", (void*)android_os_MessageQueue_nativePollOnce },
{ "nati架构师和程序员的差异veWake", "(J)V", (vshellfishoid*)Androidandroid_os_MessaShellgeQueue_nativeWake },
{ "nativeIsPolling", "(J)Z", (void*)android_os_MessageQueue_nativeIsPolling },
{ "nati架构是什么意思veSetFileDescriptorEvents", "(JII)V",
(void*)android_os_Messa架构师薪酬一月多少geQueue_nativeSetFileDescriptorEvandroid下载软件appents },
};
mPtr
是Native层MQ的内存地址在Java层的映射Linux。
Java层判别MQ是否还在作业:
private boolean isPollingLocshell是什么意思中文ked() {
// If the loopappreciate is quitting then it must not be idling.
// We can assume mPtr != 0 when mQuitting is falslinux操作体系基础知识e.
randroid体系eturn !mQuitting && nativeIsPolling(mPtr);
}
standroid下载atic jboolean android_os_MessageQueue_nlinux体系ativeIsPolling(JNshellyIEnv* env, jclass clazz, jlong ptr) {
NativeMessageQueue* nativappreciateeMessageQueue = reinterp架构图怎样做ret_cashell怎样读st<android什么意思;NativeMessageQueue*>(ptr);
return nativeMessageQueue->getLooper()->isPolling();
}
/**
* Returns whether this looper's thread is currently polling for more work to do.
* This is a good signal that the loop is still alive rather than being stuck
* handling a calinux必学的60个指令llback. Note that this method is intrinsically racy, since the
* stashell脚本编程100例te of架构图模板 the loop can changeAPP before you g架构师et the result back.架构师薪酬一月多少
*appstore/
bool isPolling() const;
唤醒 Native层MQ:
static void android_os_MessageQueue_nativeWake(JNIEnv* env, jclass clazz, jloandroid平板电脑价格ng ptr) {
NativeMessageQueue* nativeMessageQueue = reinterpret_candroid下载ast<NativeMessageQueue*>(ptr);
nativeMessageQueue->wake();
}
void NativeMeappleidssageQueue::wake() {
mLooper->wake();
}
Native层Poll:
stAndroidatic void android_os_MessageQueue_nati架构师和程序员的差异vePollOnce(JNIEnv* env, jobject obj架构图怎样做word,
jlong ptr, jint timeoutMillis)shell脚本编程100例 {
NativeMessageQueue* nativeMessageQueue = reinterpret_casshell脚本编程100例t<NativeMessageQueue*>(ptr)approve;
nativeMessageQueue->pollOnce(env, obj, timeoutMillis);
}
voi架构是什么意思d NativeMessageQueue::pollOnce(JNIEnv* env, jobject pollObj, int timeoutMillis) {
mPollshell脚本Env = env;
mPollObj = pollObj;
mLooper->pollOnce(timeoutMillis);
mPollOlinux常用指令bj = NULL;
mPollEnv = NULL;
if (mExceptionObj) {
env->Throw(mExcelinux体系ptionObj);
env->DeleteLocalRef(mExceptionObj);
mExceptionObj = NULL;
}
}
这儿比较重要,咱们架构先大约看下 Natshell编程ive层的Looper是 怎样分发音讯
的
//Looper.h
int pollOnce(int timeoutMillis, int* outFd, iandroid平板电脑价格nt* outEvents, void** outData);
inline int pollOnce(int timeoutMillis) {
return pollOnce(timeoutMillis, NULL, NULL, NULL);
}
//结束
int Looper::pollOnce(int tappreciateime架构是什么意思outMillis, int* outFd, int* outEventsandroid手机, void** outData) {
int result = 0;
for (;;) {
whiappearancele (mResponseIndex < mResponses.size()) {
const R架构中考esponse& response = mResponse架构图怎样做words.itemAt(mResponseIndex++);
int ident = response.request.ilinux中文乱码视频dent;
if (ident >= 0) {
int fd = response.request.fd;
int events架构图模板 = response.events;
void* data = response.request.data;
#if D架构EBUG_POLL_AND_WAKE
ALandroid下载软件appOGD("%p ~ pollOncelinux - returning signalled identifier %d: "
"fd=%d, events=0x%xshell指令, data=%p",
this, ident, fd, events, data);
#endif
if (outFapp装置下载d != NULL) *outFd = fd;
if (outEvents != NULL) *android11outEvents = events;
if (outData != NULL) *outData = data;
return ident;
}
}
if (result != 0) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce - returning result %d", this, result);
#endif
if (outFd != NULL) *outFd = 0;
if (oulinux是什么操作体系tEvents != NULL) *outEvents = 0;
if (outData != NULL) *outData = Napp装置下载ULL;
return result;
}
result = pollInner(timeoutMillis);
}
}
先处理Native层逗留的Response,然后调用pollInner。这儿的细节比较复杂,稍后咱们在 Native Looper解析 中进appleid行脑暴。
先于此处细节剖析,咱们知道,调用一个办法,这是
堵塞的
,用大白话描述即在办法回来前,调用者在等候
。
Java层集结 native void nativePollOnce(long ptr, int timeo架构图怎样做utMillis);
进程中是堵塞的。
此刻咱们再阅读下Java层MQ的音讯获取:代码比较长,直接在代码中进行要害注释。
在看之前,咱们先shelly单纯从 TDD的视点
考虑下,有哪些 首要场景
:当然,这些场景不一定都符合Anandroid体系droid现有的规划
- 音讯部队是否在作业中
- 作业中,希望回来音讯
- 不作业,希望回来null
- 作业中的音讯部队
当时
是否有音讯- 不存在音讯,堵塞 or 回来null?– 假定回来null,则在Linux外部需求需求
坚持空转
或许唤醒机制
,以支撑正常运作。从封装视点启航,应当坚持空转
,自己处理问题 - 存在音讯
- 特别的
内部功用性音讯
,希望MQ内部自行处理 - 现已到处理时刻的音讯, 回来音讯
- 未到处理时刻,假定都是排过序的,希望
空转坚持堵塞
or回来静默并android下载设置唤醒
? 依照前面的谈论,是希望坚持空转
- 特别的
- 不存在音讯,堵塞 or 回来null?– 假定回来null,则在Linux外部需求需求
class Mes架构中考sageQushell是什么意思中文eue {
Message next() {
// Retuandroid是什么手机牌子rn here架构中考 if the message loop has already quit and been disposlinux必学的60个指令eappeard.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
// 1. 假定 native音讯部队指针映射现已为0,即虚引证,说明音讯部队现已退出,没有音讯了。
// 则回来 null
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHanandroid是什么手机牌子dlerCount = -1; // -1 only during first架构图怎样做 iteration
int nextPollTimeoutMillis = 0;
// 2. 死循环,当为获取到需求 `分发处理` 的音讯时,坚linux体系装置持空转
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binde架构师证书怎样考r.flushPe架构规划ndingCoandroid体系mmands();
}
// 3. 调用native层办法,poll message,留神,音讯还存在于native层
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Retu架构师证书怎样考rn if found.
final long now = SystemClock.upapprovetimeMillis();
Meapp装置下载ssage prevMsg = null;
Message msg = mMessages;
//4. 假定发现 barrier ,即同步屏障,则寻找部队中的下一个或许存在的异步音讯
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asandroid平板电脑价格ynchroshell脚本根本指令nous message in the queue.
dappearo {
prevMsg = mandroid体系sg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg !android下载软件app= null) {
// 5. 发现了音讯,
// 假定是还没有linux操作体系基础知识到约好时刻的音讯,则设置一个 `下次唤醒` 的最大时刻差
// 不然 `维护单链表信息` 并回来音讯
if (now < msg.wheappleidn) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillisandroid什么意思 = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 寻找到了 `到处理时刻` 的音讯。 `维护单链表信息` 并回来音讯
// Got a messaappearancege.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} elsshell脚本e {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.vandroid下载(TAG, "Returning message: " + msg);
msg.mlinux操作体系基础知识arkInUse();
rlinux是什么操作体系eturn msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// 处理 是否需求android是什么手机牌子 连续音讯部队
// Process the quit message now that all penapproachding messages have been haapplicationndleAndroidd.
if (mQuitting) {
dispose();
retapp装置下载urnandroid/yunos null;
}
// 维护 接下来需求处理的 IDLEHandler 信息,
// 假定没有 IDLEHandler,架构师薪酬一月多少则直接进入下Shell一轮音讯获取环APP节
// 不然处理 IDLEHandler
// If firslinuxt time idle, the架构师和程序员的差异n get the number of idlersshelly to run.
// Idle handles only run if the queue is emptandroid体系y or if the first meslinux指令sage
// iandroid下载软件appn the queue (possibly a balinux必学的60个指令rrier) is due to be handled in the future.
if (android下载软件apppendingIdleHandlerCount < 0
&&amandroid的drawable类p; (mapproachMessages == null || now &lapproacht; mMessages.wheapplicationn)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount &applelt;= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHanlinux体系装置dler[Matshellyh.max(pendingIdleHandlerCount, 4)架构];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleshelly-lanHandlers);
}
// 处理 IDLEHandler
// Run the idle handlers.
// We only ever reach this code block during the first ishell怎样读teration.
for (int i = 0; i < penapp装置下载dingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandleapprovers[i] = null; // release the reference to the handshell怎样读ler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "Idle架构规划Handler threw ex架构图怎样做wordception", t);
}
if (!keep) {
synchroandroid下载nized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them agalinux操作体系基础知识in.
pendiappstorengIdleHandlerCount = 0;
// While calling an idle handler, a new message could hashelly-lanve been delivered
// so go back and look again for a p架构图怎样做wordendinglinux运维是必死之路 message without waiting.
nextPollTimeoutMillis = 0;
}
}
}
Japplicationava层压入音讯
这就比较简略了,当音讯本身合法,且音讯部队还在作业中时。
依旧从 TDD视点
启航:
- 假定音讯部队没有头,希望直接作为头
- 假定有头
-
音讯处理时刻
先于头音讯
或许是需求当即处理的音讯,则作为新的头 - 不然依照
处理时刻
刺进到适合方位
-
booleaandroid下载n enqueueMessage(Message msg, long wh架构师薪酬一月多少en) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");shell怎样读
}
if (mQuitting) {
IllegalStateExceptandroid什么意思ion e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.gandroid下载软件appetMessage(), e);
msg.recycle();
retur架构图怎样做n false;
}
msg.markInUse();
msg.when = whenLinux;
Me架构师证书怎样考ssage p = mM架构图模板essages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mshell指令Blocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wakeshell怎样读
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earappearanceliest asynchronous message架构图怎样做word in the queue.
needWake = mBlocked &&APP p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
brealinux体系装置k;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 becauslinux操作体系基础知识e mQuitting is false.
if (needWake) {
nativeWake(linux中文乱码视频mPtr);
}
}
return true;
}
同步屏障 barrilinux中文乱码视频er
后边独自脑暴shell脚本编程100例, 其他部分就先不看了
Java层音讯分发
这一节开端,咱们脑暴音讯分发,前面咱们现已看过了 Me架构图模板ssageQuapproveeue
,音讯分发便是 不停地
从 MessAndroidageQueue
中取出音讯,并指派给处理者。
结束这一作业的,是linux操作体系基础知识Looper。
在前面,咱们现已知道了,Natilinux中文乱码视频ve层也有Looper,可是不难理解
:
- 音讯部队需求
桥梁
连通 Java层和Native层 - Looper只需求
在自己这一端
,处理自己的音讯部队分发即可
所以,咱们看Java层的音讯分发时,看Java层的Looper即可。
重视三个首要办法:
- 出门Shell上班
- 作业
- 下班回家
出门上班 prelinux操作体系基础知识pare
class Looper {
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() !=架构是什么意思 null) {
throw new RuntimeException("Only one Looper may be created peapprover thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
}
这儿有两个留神点:
- 现已出了门,除非再进门,不然没法再出门了。同样,一个线程有一个Looper就够了,只需它还活着,就没必要再建一个。
- 职linux是什么操作体系责到人,一个Looper服务于一个Thread,这需求
注册
,代表着某个Thread
现已由自己服务了。运用了ThreadLocal,由于多线程拜访集结,`总需android/yunos求考虑
比赛,这很不人道主义,爽性分家,每个架构师和程序员的差异Thread操作自己的内容互不搅扰,也就没有了比赛,所以封装了
ThreadLshell是什么意思中文ocal`
上班 loop
留神作业性质是 分发
,并不需求自己处理
- 没有
注册
天然就找不到担任这份作业的人。 - 现已在作业了就不要催,催了会导致作业犯错,次序出现问题。
- 作业便是不断的取出
老板
—MQ
的指令
—Messaglinux常用指令e
,并交给相关担任人
—Handlershell脚本根本指令
去处理,并记载信息 -
007
,不眠不休,当MQ再也不宣告音讯了
,没活干了,咱们都散了吧,下班回家
class Looper {
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLapproachoop) {
Slog.w(TAG, "applicationLoop agashelly-lanin would have the queued messages be executed"
+ " before this one coapp装置下载mpleted.");
}
me.mInLoop = true;
final MessageQueue queue = me.mQueuelinux指令;
// Makeapproach sure the identity of this thread is that of the local proandroid手机cess,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.cleandroid手机arshelly-lanCallingIde架构图模板ntity();
// Allow overriding a threshold with a system prop. e架构师证书怎样考.android手机g.
// adb shell 'setprop log.looper.appear1000.main.slow 1 && stop &&appstore; start'
final int thresholdOverride =
SystemProperties.getInt("log.looper架构."
+ Process.myUid()架构 + "."
+ Thread.currentThread().getName()
+ ".sloshell指令w", 0);
booleandroid是什么手机牌子an slowDeliveryDetected = false;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is架构图怎样做word quittingLinux.
return;
}
// ThiAndroids must be in a local variable, in case a UapproachI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {linux运维是必死之路
logging.println(">>>>> Dispaandroid下载软件apptching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// Make sure the observer won't change while processishell脚本根本指令ng a transaction.架构是什么意思
final Observer olinux中文乱码视频bsandroid平板电脑价格erver = sObserver;
final long traceTag = me.mTraceTagLinux;
long slowDispatchThreandroid下载软件appsholdMs = me.mSlowDispatchThresholdMs;
long sapp装置下载lowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (android是什么手机牌子msg.when > 0);
final boshell脚本根本指令olean l架构师和程序员的差异ogSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStar架构师薪酬一月多少tTime = logSlowDelivery || logSlowDispatch;
fshell是什么意思中文inal boolean needEndTime = logSlowDilinux体系装置spatch;APP
if (traceTag != 0 &&shell脚本编程100例 Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceT架构师ag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = obse架构图模板rver.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.android/yunosslinux体系装置etUid(msg.workSourceUid);
try {
//留神这儿
msg.target.dispatchMessage(msg);
if (observer != nuandroid体系ll) {
obShellserver.messageDispatched(token, msg);
}
dispalinux指令tchEndshelly = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.disandroid下载软件apppatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
T架构race.traceEnandroid下载d(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeli架构中考veryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLoglinux是什么操作体系(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
mlinux操作体系基础知识sg)) {
// Oshell编程nceshell是什么意思中文 we write a slow delivery log, suppress until the queue drains.
slowDeliveshell指令ryDetected = true;
}
}
}
if (logSlowDispatch) {android的drawable类
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "disapprovepatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.linux中文乱码视频callback);
}
// Make sure that durshellfishing the course of dispatching the
// identity of the thread wasn't corrupted.
final long newshelly-lanIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "shellfishThread identity changed from 0x"
+ Long.toHlinux体系exString(ident) + " to 0x"
+ Long.toHexStriandroid是什么手机牌子ng(newIdent) + " while dispatching to "
+ msg.target.getClass().geandroid是什么手机牌子tName() +appstore " "
+ msg.candroid/yunosall架构是什么意思back + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
}
下班 quit/quitSafely
这是比较粗暴的行为,MQ离开了Looper就没法正常作业了,即下班即意味着辞去职务
class Looper {
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQue架构师薪酬一月多少ue.quit(true);Linux
}
}架构师证书怎样考
音讯处理 Handler
这儿就比较清晰了。API根柢分为以下几类:
面向android体系运用者:
- 创立Message,经过Message的
享元办法
- 发送音讯,android下载软件app留神postRunnable也是一个音讯
- 移除音讯,
- 退出等
面向音讯处理linux体系:
class Handler {
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNandroid下载ull MAndroidessage msg) {
}
/**
* Handle system messashell是什么意思中文ges here.
* Looper分发时调用的API
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null)架构图怎样做 {
handleCall架构是什么意思back(msg);
} elslinux常用指令e {
if (mCallback != null) {
if (mCallback.handleMessage(msg)appstore) {
return;
}
}
handleMessage(msg);
}
}appstore
}
假定有 Handlinux是什么操作体系ler callback
,则交给callback处理,不然自己处理,假定没覆写 handleMessage
,音讯相当于被 drop 了。
音讯发送部分能够结合下图收拾:
阶架构师薪酬一月多少段性小结,至此,咱们现已对
Framework层的音讯机制android下载软件app
有一个无缺的了解了。
前面咱们收拾了:
- Native层 和 Java层均有音讯队shellfish伍,并且经过JNI和指针映射,存在对应联络
- Nativelinux体系装置层 和 Java层MQ
消架构息获取时的大致进程
- Java层 Looper 怎样作业
- Java层 Handlinux是什么操作体系ler 大致概览
根据前面收拾的内容,能够总结:从
Java Runtime
看:
- 音讯部队机制服务于
线程级别
,即一个架构图模板线shell脚本根本指令程有一个作业中的音讯部队即可,当然,也能够没有。即,一个Thread
至多有
一个作业android什么意思中的Looper。
- Looper 和 Java层MQ
一一对应
- Handlerandroid/yunos 是MQ的进口,也是
音讯
的处理者- 音讯–
Messandroid下载age
运用了享元办法
,本身信息满意,满意自洽
,创立音讯的开支性对较大,所以运用享元办法对音讯方针进行复用架构师证书怎样考。
下面咱们再持续根究细节,处理前面语焉不详处留下的疑问:
- 音讯的类型和本质
- Native层Looper 的papp装置下载ollInner
音讯的类型和本质
message中的几个重要成员变量:
class Message {
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
/*package*/ int flags;
public long when;
/*package*/ Bundle data;
/*package*/ Handler target;
/*package*/ Runnable callback;shelly
}
其间 target是 方针
,假定没有方针,那便是一个特别的音讯: 同步屏障
即 barrier
;
what 是音讯标识
arg1 和 arg2 是开支较小的 数据
,假定 不足以表达信息
则能够放入 Bundle data
中。
replyTo 和 obj 是跨进程传递音讯时运用的,暂时不看。
flags 是 message 的状况标识,例如 是否在运用中
,是否是同步音讯
上面说到的同步屏障,即 b架构图模板arriAndroider,其作用是阻挠后边的
同步音讯
不被获取,在前面阅读Java层MQ的nandroid11ext办法时读到过。咱们还记得,next办法中,运用死循环,测验读出一个满意处理条件的音讯,假定取不到,由于死循环的存在,调用者(Loopeandroid什么意思r)会被一向堵塞。
此刻能够印证一个结论,音讯依照 功用分类
能够分linux为 三种
:
- 一般音讯
- 同步屏障音讯
- 异步音讯
其间同步音讯是一种内部机制。设置屏障之后需求在适合时刻撤消屏障,不然会导致 一般音讯永久无法被处理
,而撤消时,需求用到设appstore置屏障时回来的tandroid/yunosoken。
Native层Looper
信linux体系赖咱们都对 Native层
的Looper发生爱好了,想看看它在Native层都干shell脚本根本指令些什么。
对无缺源码感爱好的能够看 这儿 ,下面咱们节选部分进行阅读。
前面说到了Looper的架构师pollOnceshell是什么意思中文,处理完放置的Response之后,会调用pollInner获取音讯
int Looper::pollInner(int timeoutMillis) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ poshell是什么意思中文llOnce - wAPPaiting: timeoutMillis=%d", this, timeoutMillis);
#endif
// Adjust the ti架构是什么意思meout based on when the next message is due.
if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MappleidONOTONIC);
int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
if (messageTimeoutMillis >= 0
&& (timeoutMillis < 0 || messageTimeoutMillilinux常用指令s < timeoutMillis)) {
timeoutMishellyllis = messageTimeoutMillinux是什么操作体系lis;
}
#if DEBUG_POshelly-lanLL_AND_WAKE
ALOGD("%pAPP ~ pollOnce - next message in %lldns, adandroid平板电脑价格justed timeoutandroid什么意思: timeoutMillis=%d",
this, mNextMessageUptime - now, timeoutMillishell脚本编程100例s);
#endif
}
// Poll.
int result = ALOOPER_POLL_WAKE;
mResponses.clear();
mResponseIndex = 0;
struct epoll_event eventItemshell编程s[EPOLL_MAX_EVENTS];
//留神 1
int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillilinux操作体系基础知识s);
//架构师 Acquire lock.
mLock.lock();
// 留神 2
// Check for poll error.
if (eventCount < 0) {
if (errno == EINTR) {
goto Done;
}
ALOGW("Polllinux运维是必死之路 failed with an unexpected error, errno=%d", errno);
result = ALOOPER_POLL_ERRORandroid下载;
goto Done;
}
// 留神 3
// Check fAPPor poll timeout.
if (evshell编程enandroid下载软件apptCAndroidount == 0) {
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ pollOnce -架构师证书怎样考 timeout", this);
#endif
result = ALOOPER_POLL_TIMEOUT;
goto Done;
}
//留神 4
// Handle all events.
#if DEBUG_POLL_AND_WAKE
ALOGD("%p ~ p架构师证书怎样考ollOLinuxnce - handling events from %d fd架构规划s", this, eventshell怎样读Count);
#endif
for (int i = 0; i < eventCount; i++) {
int fd = eventItems[i].data.fd;
uint32_t epollEvents = eventItems[i].events;
if (fd ==Shell mWakeReadPipeFd) {
iandroid下载f (epollEvents & EPlinux指令OLLIN) {
awoken();
} else {
ALOGW("Ignoring ushell脚本编程100例nexpeandroid/yunoscted epoll events 0x%x on wake read pipe.", epollEvents);
}
} else {
ssize_t requestIndex = mRequests.indlinux运维是必死之路exOfKey(fd架构师薪酬一月多少);
if (requestInLinuxdex &android下载gt;= 0) {
int evenlinux操作体系基础知识ts = 0;
if (epollEvents &amandroid11p; EPOLLIN) events |= ALOOPER_EVENT_INPUT;
if (epollEvents & EPOLLOUT) events |= ALOOPER_EVENT_OUTPUT;
if (epollEvents & EPOLandroid11LERR) events |= ALOOPERapple_EVENT_ERROR;
if (epollEveandroid平板电脑价格nts & EPOLLHUP) events |= ALOOPER_EVENT_HANGUP;
pushResponse(events, mRequests.valueAtlinux操作体系基础知识(requestIndeshelly-lanx));
} e架构规划lse {
Aandroid手机Lapp装置下载OGW("Ignoring unexpected epoll events 0x%x on fd %d that is "
"no loAPPnger registered.", epollEventandroid11s, fd);
}
}
}
Done: ;
// 留神 5
// Invoke pending message callbacks.
mNextMessageUptime = LLONG_MAX;
while (mMeappstoressageEnvelopes.size() != 0) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
conshell脚本编程100例st MessageEnvelope& messageEnvelope = mappleMessageEnvelopes.itemAt(0);架构图怎样做word
if (meslinux是什么操作体系sageEnvelope.uptime <= now) {
// Remove the envelope from the list.
// Wapp装置下载e keep a strong refere架构师nce to the handler ulinux必学的60个指令ntil the call to handleMesshellfishsage
// finishes. Tlinux中文乱码视频hen we droshell怎样读p it so that the hAndroidandler can be deleted *before*
// we reacquire our lock.
{ // obtain handler
sp<MessageHandler> handler = messageEnvAndroidelope.handler;
Messa架构图模板ge meandroid平板电脑价格ssage = messagelinux体系装置Envelope.messagapp装置下载e;
mMessageEnvelopes.removeAt(0);
mSendingMessage = true;
mLock.unlock();
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLinuxLBACKS
ALOGD(linux指令"%p ~ polllinux运维是必死之路Once - sending message: handler=%p, what=%d",
this, handler.get(), message.what);
#endilinux常用指令f
handler->linux指令;handleMessage(message);
} // release handler
mLock.lock();
mSendingMessage = false;
result = ALOOPER_POLandroid手机L_CALLBACK;
} else {
// The landroid体系ast message left at thandroid11e head of thappstoree queue d架构是什么意思etermines the next wakeup ti架构图怎样做me.
mNextMessageUptimeandroid手机 = messageEnvelope.uptime;
break;
}
}
// Relelinux中文乱码视频ase lock.
mLock.unlock();
//留神 6
// Invoke all response callbacks.
for (size_t i = 0; i < mResponses.size(); i++) {
Response& response = mResponses.editItemAt(i);
if (response.request.idelinux体系nt == ALOOPER_POLL_CALLBACK) {
int fd = response.requeandroid下载软件appst.fd;
int events = response.events;
void* data = response.request.dandroid11ata;
#if DEBUG_POLL_AND_WAKE || DEBUG_CALLBACKS
ALOGD("%p ~ pollOnce - invoking fd event caapp装置下载llback %p: fd=%d, eveshell脚本nts=0x%x, data=%p",
thisandroid平板电脑价格, response.requeappreciatest.callback.get(), fd, events, data);
#endif
int callbaandroid平板电脑价格ckResult = response.requestandroid什么意思.callback->handleEAPPvent(fd, events, data);
if (caapproachllbackResult == 0) {
removeFd(fd);
}
// Clear the callback referenceandroid是什么手机牌子 in the rappleesponse structure promptly because we
// will not candroid是什么手机牌子lear the response vectshell脚本or itself until the next poappearancell.
response.request.callback.clear();
result = ALOOPER_POapproachLL_CALLBACK;
}
}
return result;
}
上面符号了留神点
- 1 epoll机制,等候
mEpollFd
发生作业, 这个等候具有超时时刻。 - 2,3,4 是等候的三Shell种作用,
goto
句子能够直接跳转到符号
处 - 2 检测poll
是否犯错
,假定有,跳转到 Done - 3 检测pool
是否超时
,假定架构图模板有,跳转到 Done - 4 处理epoll后一切的作业
- 5 处理 pending 音讯的回调
- 6 处理 一切 Response的回调
并且咱们能够发现回来的作用有以下几种:
- ALOshell脚本根本指令OPER_POLL_CALLBACK
有 pending message
或许 request.ident
值为 Alinux体系装置LOOPER_POLL_CALLBACK
的 Response被处理了。
假定没有:
- ALOOPER_POLL_WAKE架构图怎样做word 正常唤醒
- ALOOPER_POLL_ERROR epoll差错
- ALOOPLinuxER_POLL_TIMEOUT epoll超时
查找了一下枚举值:
ALOOPER_POLL_WAKE = -1,
ALOOPER_POLL_CALLBACK = -2,
ALOOPER_POLL_TIMEOUT = -3,
ALOOPER_POLL_ERROR = -4
阶段性小结, 咱们对
音讯
和Native层的pollInner
进行了一次脑暴,引出了epoll机制。linux指令其实Nashellytive层的application
Looper分发
还有不少值得脑暴的点,但咱们先慢慢,现已刻不容缓的要对epoll
机制进行脑暴了。
##脑暴:android是什么手机牌子Linux中的I/O模型
这部分内容,举appleid荐一篇文章:运用 libevent 和 libev 行进网络运用功用——I/O模型演进改动史 作者 hguisu
PS:本段中,存在部分图片直接引证自该文,我偷了个懒,没有去找原版内容并符号出处
堵塞I/O模型图:在调用recv()函数时,发生在内核中等候数据和拷贝数据的进程
结束十分的 简略
,可是存在一个问题,堵塞导致线程无法实施其他任何核算,假定是在网络编android体系程布景下,需求shell怎样读运用多线程行进处理并发的才华。
留神,不要用 Android中的 点击屏幕等硬件被触发作业
去对应这儿的 网络并发
,这是两码事。
假定选用了 多进程
或许 多线程
结束 并发应对
,模型如下:
到linux体系这儿,咱们看的都是 I/O 堵塞 模型。
脑暴,堵塞为调用办法后一向在等候回来值,线程内linux体系装置实施的内容就像
卡顿
在这儿。架构师薪酬一月多少
假定要消android平板电脑价格除这种卡顿,那就不能调用办法等候I/O作用,而是要 当即回android11来
!
举个比如:
- 去西装店定制西装,供认好approve样式和规范后,你appreciate坐在店里一向等着,比及做appear好了拿给你,这便是堵塞型的,这能等死你;
- 去西装店定制西装,供认好样式和linux运维是必死之路规范后,店员告知你别干等着,好多天呢,等你有空了来看看,这便对错堵塞型的。
改动为非堵塞模型后,应对模型如下:
不难理解,这种办法需求顾客去 轮询
。对客户不友好,可是对店家可是一点丢掉都没有,还让等候区没那么挤了。
有些西装店进行了改造,appear对客户愈加友好了appleid:
去西装店定制西装,供认好样式和规范后,留下联络办法,等西服做好了联络客户,让他来取。
这就变成了 select
or poll
模型android/yunos:
留神:进行改造的西装店需求增加一个架构中考职工,图中标识的用户线程,他的作业是:
- 在前台记载客户订单和联络办法
- 拿记载着
订单
的小本子去找制造间,不断查看
订单是否竣工,竣工的就android是什么手机牌子能够提走并联linux指令络客户了。
并且,他去看订单竣工时,无法在前台记载客户信息,这意味他 堵塞
了,其他作业只能先放置着。
这个做法,关shell编程于制造间而言,和 非堵塞模型
并没有多大差异。还增加了application一个店架构师薪酬一月多少员,可是,用 一个店员
就处理了之前 许多店员
都会跑去 制造间
帮客户问”订单好了没有?” 的问shell怎样读题。
值得一linux指令提的是,为了行进服务质量,这个职工每次去制造间问询一个订单时,都需求记载一些信息:
- 订单结束度问询时,是否被应对;
- 应对有没有扯谎;等
有些店对每种不同的查核项均预备了记载册,这和
select
模型相似有些店只用一本记载册,可是android11册子上能够运用表格记载各种查核项,这和
poll
模型相似
select
模型 和 poll
模型的近似度apple比较高。
没多久,老板就发现了,这个店员的作业功率有点低下,他每apple次都架构图模板要拿appreciate着一本shell是什么意思中文订单簿,去把订单都问一遍,倒不android下载是职工不勤快,是这个办法有APP点问题。
所以老板又进行了改造:
- 在
前台
和制造间
之间加一个送信管道。 - 制造间有发展需求汇报了,就送一份信到前台,信上写着订单号。
- 前台职工直接去问对应的订单。
这android手机就变成了 epoll模型
处理了 select/poll
模型的遍历功率问题。
这样改造后,前台职工就不再需求按着订单簿从上到下挨个问了。行进了功率,前台职工只需无事发生
,就能够高雅的划水了。
咱们看一下NativeLooper的结构函数:
Looper::Looper(bool allowNonCallbacks)approach :
mAllowNonCallbacks(allowNonCallbacks), mSending架构图怎样做Message(false),
mResponseIndex(0), mNextMessageUptime(LLONG_架构中考MAX) {
int wakeFds架构师[2];
int result = pipe(wakeFds);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not creandroid是什么手机牌子ate wake pipe. errno=%d", errno);
mWakeReadPipeFd = wakeFds[0];
mWakeWrit架构图怎样做wordePipeFd = wakeFds[1];
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d",
errno);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d",
elinux中文乱码视频rrno);
// Allocate the epoll instance and register the wake pipe.
mEpollshelly-lanFd = epoll_create(EPOLL_SIZE_HINT);
LOLinuxG_ALWAYS_FATAL_IF(mEpollFlinux体系装置d < 0, "Could not create epollshell脚本根本指令 instance. errno=%d", errno);
struct epoll_event elinux体系ventItem;
memset(& eventItem, 0, sizeof(epoll_event)); // zero out unused members of data field unshell编程ion
eventItem.events = EPOLLIN;
eventItem.data.fd = mWakeReadPipeFd;
result = epoll_ctl(mEpollFd, EPOLL_C架构图怎样做wordTL_ADD, mWakeReadPipeFd, &amlinux运维是必死之路p; eventItem);
LOG_ALWAYS_FAapproachTAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
}
总结
信赖看到这儿,咱们现已自己悟透了各种问题。依照惯例,仍是要总结下,由于 这篇是脑暴
,所以 思绪
是比较 跳动
的,内容前后联络不太明显。
咱们结合一个问题来点明内容前后联络。android/yunos
Java层 Looper和MQ 会什么运用了死循环可是
不会"堵塞"UI线程
/没构成ANR
/依旧能够呼应点击作业
- Android是根据
作业驱动
的,并建立了完善android/yunos的
音讯机制 - Java层的音讯机制仅仅一个部分,其担任的便是面向音讯部队,处理
音讯部队处理
,音讯分发
,音讯处理
- Looperandroid的drawable类的死循环保证了
音讯linux必学的60个指令部队
的音讯分发
一向处于有用作业中,不循环就连续了分发。 - MessageQueue的
死循环
保证了Looper能够获取有用的音讯
,保证了Looper只需有音讯,就一向作业
,发现有用音讯,就跳出了死循环。 - 并且Java层MessageQueue在 next() 办法中的死循环中,经过JNI调用了 Native层MQ的
pollOlinux指令nce
,驱动了Native层去处理Native层音讯 - 值得一提的是,UI线程处理的作业也都是根据android下载音讯的,无论是更android手机新UI仍是呼应点击作业等。
所以,正是Looper 进行loop()之后的死循环,保证了UI线程的各项作业正常实施。
再说的ANR,这是Android 供认主线程
音讯机制 正常
且 健android体系康
作业的一种检测appearance机制。
由于主线程Looper需求运用 音讯机制
驱动UI渲染和交互作业处理,
假定某个音讯的实施,或许其衍生出的业务,在主线程占用架构师薪酬一月多少了许多的时刻,导致主线程长时刻堵塞,会影响用户体appear会。
所以ANR检测选用了一种 埋定时炸弹
的机制,有必要依托Looper的appleid高效linux中文乱码视频作业来消除android是什么手机牌子之前装的定时炸linux操作体系基础知识弹。而这种定时炸弹比较有意思,被发现了才会炸
。
在说到 呼应架构点击作业
,相似的作业总是从硬件启航的,在到内核,再进程间通讯到用户空间,这些作业以音讯的办法存在于Native层,经过处理后,表现出:
ViewRootImpl收到了InputMana架构师薪酬一月多少ger的输入,并进行了作业处理
这儿咱们借用一张图appreciate总结整个音讯机Android制流程:
图片来自 《Android7.0 MessageQueue详解》 作者 Gaugalinux操作体系基础知识meapp装置下载la
PS:这篇文章写得很长,内容长,耗时也长,大约花费了10天的时刻,其间还有不少内容写linux常用指令得未能尽兴。例如:
“Java层在哪linux操作体系基础知识些状况下运用JNI调取Native层的唤醒,为什么这么干?”等等。可是考虑到篇幅,决议不再往下挖了。