三思系列是我最新的学习、总结办法,着重于:问题剖析技术堆集视界拓展,关于三思系列

这次,真的能够一文吃透:

  • Java层音讯部队的规划
  • Java层Looper分发
  • Native层音讯部队和Java层音讯部队的联络
  • Native层Looper分发
  • 架构师证书怎样考
  • epoll

前言

作为Andrshell脚本oid中 至关重要 的机制之一,十多年来,剖析它的linux体系文章不断,许多的内容现已Shell被发掘过了。所以:

  • 现已对这一机制比较 熟稔 的读者,在这篇文章中,看不到 新东西 了。
  • 还不太熟悉音讯机制的读者,能够在文章的基础上,持续挖一挖。

可是,经过简略的检索和剖析,大部分 的文章是盘绕:

  • Handler,Looper,MQ的联络
  • 上层的Handler,Looper、MQ 源码剖析

翻开的。单纯的从这些视点学习的话,并不能 彻底理解 音讯appear机制。

这篇文章本质仍是 一次脑暴 ,一来 防止脑暴跑偏 ,二来帮忙读者 捋清内容头绪 。先放出脑图:

三思系列:Android的音讯机制,一文吃透

脑暴: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空转有关,笔者没有持续根究下去,假定有读者了解,希望能够留言帮我解惑。

三思系列:Android的音讯机制,一文吃透

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&ltandroid什么意思;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下载设置唤醒? 依照前面的谈论,是希望 坚持空转
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 &&ampappstore; 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 了。

音讯发送部分能够结合下图收拾:

三思系列:Android的音讯机制,一文吃透


架构师薪酬一月多少段性小结,至此,咱们现已对 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-&gtlinux指令;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的音讯机制,一文吃透

结束十分的 简略,可是存在一个问题,堵塞导致线程无法实施其他任何核算,假定是在网络编android体系程布景下,需求shell怎样读运用多线程行进处理并发的才华。

留神,不要用 Android中的 点击屏幕等硬件被触发作业 去对应这儿的 网络并发,这是两码事。

假定选用了 多进程 或许 多线程 结束 并发应对,模型如下:

三思系列:Android的音讯机制,一文吃透

linux体系这儿,咱们看的都是 I/O 堵塞 模型。

脑暴,堵塞为调用办法后一向在等候回来值,线程内linux体系装置实施的内容就像 卡顿 在这儿。架构师薪酬一月多少

假定要消android平板电脑价格除这种卡顿,那就不能调用办法等候I/O作用,而是要 当即回android11

举个比如:

  • 去西装店定制西装,供认好approve样式和规范后,你appreciate坐在店里一向等着,比及做appear好了拿给你,这便是堵塞型的,这能等死你;
  • 去西装店定制西装,供认好样式和linux运维是必死之路规范后,店员告知你别干等着,好多天呢,等你有空了来看看,这便对错堵塞型的。

改动为非堵塞模型后,应对模型如下:

三思系列:Android的音讯机制,一文吃透

不难理解,这种办法需求顾客去 轮询 。对客户不友好,可是对店家可是一点丢掉都没有,还让等候区没那么挤了。

有些西装店进行了改造,appear对客户愈加友好了appleid:

去西装店定制西装,供认好样式和规范后,留下联络办法,等西服做好了联络客户,让他来取。

这就变成了 select or poll 模型android/yunos

三思系列:Android的音讯机制,一文吃透

留神:进行改造的西装店需求增加一个架构中考职工,图中标识的用户线程,他的作业是:

  • 在前台记载客户订单和联络办法
  • 拿记载着 订单 的小本子去找制造间,不断查看 订单是否竣工,竣工的就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制流程:

三思系列:Android的音讯机制,一文吃透

图片来自 《Android7.0 MessageQueue详解》 作者 Gaugalinux操作体系基础知识meapp装置下载la

PS:这篇文章写得很长,内容长,耗时也长,大约花费了10天的时刻,其间还有不少内容写linux常用指令得未能尽兴。例如:
“Java层在哪linux操作体系基础知识些状况下运用JNI调取Native层的唤醒,为什么这么干?”等等。

可是考虑到篇幅,决议不再往下挖了。