閱讀更多

0頂
0踩

編程語言

轉載新聞 深入理解Android消息機制

2018-04-20 11:18 by 副主編 jihong10102006 評論(0) 有35106人瀏覽
在日常的開發中,Android 的消息機制作為系統運行的根本機制之一,顯得十分的重要。
從 Handler 發送消息開始

查看源碼,Handler的post、send方法最終都會走到
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
	if (delayMillis < 0) {
	    delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

sendMessageDelayed 會走到
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
	msg.target = this;
    if (mAsynchronous) {
	    msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

這里可以設置 Message 為異步消息

查看 queue 的 enqueueMessage 方法, 我們剝離出核心代碼:
if (p == null || when == 0 || when < p.when) {
	// New head, wake up the event queue if blocked.
	msg.next = p;
    mMessages = msg;
    needWake = mBlocked;
 }

如果是新的隊列頭,直接插入隊列

如果隊列里面已經有消息了,執行如下邏輯
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
	prev = p;
    p = p.next;
    if (p == null || when < p.when) {
	    break;
    }
    if (needWake && p.isAsynchronous()) {
	    needWake = false;
    }
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;

插入消息的時候,一般不會喚醒消息隊列。如果消息是異步的,并且隊列頭不是一個異步消息的時候,會喚醒消息隊列
if (needWake) {
	nativeWake(mPtr);
}

消息隊列的具體喚醒過程我們暫時不細看。把關注點移到 Looper 上。looper在執行的時候具體執行了什么邏輯呢?查看 Looper.java 的 looper() 方法

looper 方法中有一個死循環, 在死循環中,會獲取下一個 Message
for (;;) {
	Message msg = queue.next(); // might block
}

if (msg != null && msg.target == null) {
// Stalled by a barrier.  Find the next asynchronous message in the queue.
do {
	prevMsg = msg;
	msg = msg.next;
} while (msg != null && !msg.isAsynchronous());

當存在一個 barrier 消息的時候,會尋找隊列中下一個異步任務。而不是按照順序。 例如3個消息,1,2,3, 2 是異步消息。如果不存在barrier的時候,next的順序就是 1,2,3 但是如果存在barrier的時候,則是 2,1,3
if (msg != null) {
	if (now < msg.when) {
    // Next message is not ready.  Set a timeout to wake up when it is ready.
    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
    } else {
	    // Got a message.
        mBlocked = false;
        if (prevMsg != null) {
	        prevMsg.next = msg.next;
        } else {
		    mMessages = msg.next;
        }
        msg.next = null;
        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
        msg.markInUse();
	    return msg;
   }
} else {
	// No more messages.
	nextPollTimeoutMillis = -1;
}

這里如果 next 的 Message 不為空,就返回,并且將它移出隊列 在 MessageQueue 為空的時候,會順便去處理一下 add 過的 IdleHandler, 處理一些不重要的消息
for (int i = 0; i < pendingIdleHandlerCount; i++) {
	final IdleHandler idler = mPendingIdleHandlers[i];
    mPendingIdleHandlers[i] = null; // release the reference to the handler

    boolean keep = false;
    try {
		keep = idler.queueIdle();
    } catch (Throwable t) {
	    Log.wtf(TAG, "IdleHandler threw exception", t);
    }

    if (!keep) {
		synchronized (this) {
        mIdleHandlers.remove(idler);
     }
}

查看 IdleHandler 的源碼。
   
 * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     */
    public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         */
        boolean queueIdle();
    }

當 queueIdle() 為 false 的時候,會將它從 mIdleHandlers 中 remove,仔細思考下,我們其實可以利用IdleHandler實現不少功能, 例如
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
	@Override
	public boolean queueIdle() {
		return false
	}
});

我們可以在 queueIdle 中,趁著沒有消息要處理,統計一下頁面的渲染時間(消息發送完了說明UI已經渲染完了),或者算一下屏幕是否長時間沒操作等等。

拿到 Message 對象后,會將 Message 分發到對應的 target 去
msg.target.dispatchMessage(msg);

查看源碼
public void dispatchMessage(Message msg) {
	if (msg.callback != null) {
		handleCallback(msg);
    } else {
	    if (mCallback != null) {
	        if (mCallback.handleMessage(msg)) {
	            return;
            }
         }
     handleMessage(msg);
	}
}

當 msg 的 callback 不為 null 的時候,即通過 post(Runnable) 發送信息的會執行 handlerCallback(msg) 方法。如果 mCallback 不為 null并且 handleMessage 的結果為 false,則執行 handleMessage 方法。否則會停止分發。
private static void handleCallback(Message message) {
	message.callback.run();
}

查看 handlerCallback 方法源碼, callback 會得到執行。到這里基本的Android消息機制就分析完了,簡而言之就是,Handler 不斷的將Message發送到一 根據時間進行排序的優先隊列里面,而線程中的 Looper 則不停的從MQ里面取出消息,分發到相應的目標Handler執行。

為什么主線程不卡?

分析完基本的消息機制,既然 Looper 的 looper 方法是一個for(;;;)循環,那么新的問題提出來了。為什么Android會在主線程使用死循環?執行死循環的時候為什么主線程的阻塞沒有導致CPU占用的暴增??

繼續分析在源碼中我們沒有分析的部分:
  • 消息隊列構造的時候是否調用了jni部分
  • nativeWake、nativePollOnce這些方法的作用是什么
先查看MQ的構造方法:
MessageQueue(boolean quitAllowed) {
	mQuitAllowed = quitAllowed;
	mPtr = nativeInit();
}

會發現消息隊列還是和native層有關系,繼續查看android/platform/frameworks/base/core/jni/android_os_MessageQueue_nativeInit.cpp中nativeInit的實現:
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) {
    NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue();
    if (!nativeMessageQueue) {
        jniThrowRuntimeException(env, "Unable to allocate native queue");
        return 0;
    }

    nativeMessageQueue->incStrong(env);
    return reinterpret_cast<jlong>(nativeMessageQueue);
}

這里會發現我們初始化了一個 NativeMessageQueue ,查看這個消息隊列的構造函數
NativeMessageQueue::NativeMessageQueue() :
        mPollEnv(NULL), mPollObj(NULL), mExceptionObj(NULL) {
    mLooper = Looper::getForThread();
    if (mLooper == NULL) {
        mLooper = new Looper(false);
        Looper::setForThread(mLooper);
    }
}

這里會發現在mq中初始化了 native 的 Looper 對象,查看android/platform/framework/native/libs/utils/Looper.cpp中 Looper 對象的構造函數
// 簡化后的代碼
Looper::Looper(bool allowNonCallbacks) :
        mAllowNonCallbacks(allowNonCallbacks), mSendingMessage(false),
        mResponseIndex(0), mNextMessageUptime(LLONG_MAX) {

	int wakeFds[2];
	int result = pipe(wakeFds);

	mWakeReadPipeFd = wakeFds[0];
	mWakeWritePipeFd = wakeFds[1];
	
	result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
	result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);

	mEpollFd = epoll_create(EPOLL_SIZE_HINT);

	struct epoll_event eventItem;
    memset(& eventItem, 0, sizeof(epoll_event)); 
    eventItem.events = EPOLLIN;
    eventItem.data.fd = mWakeReadPipeFd;
    result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, & eventItem);
}

這里我們會發現,在 native 層創建了一個epoll,并且對 epoll 的 event 事件進行了監聽。

什么是epoll

在繼續分析源碼之前,我們先分析一下,什么是epoll

epoll是Linux中的一種IO多路復用方式,也叫做event-driver-IO。

Linux的select 多路復用IO通過一個select()調用來監視文件描述符的數組,然后輪詢這個數組。如果有IO事件,就進行處理。

select的一個缺點在于單個進程能夠監視的文件描述符的數量存在最大限制,select()所維護的存儲大量文件描述符的數據結構,隨著文件描述符數量的增大,其復制的開銷也線性增長。

epoll在select的基礎上(實際是在poll的基礎上)做了改進,epoll同樣只告知那些就緒的文件描述符,而且當我們調用epoll_wait()獲得就緒文件描述符時,返回的不是實際的描述符,而是一個代表就緒描述符數量的值,你只需要去epoll指定的一個數組中依次取得相應數量的文件描述符即可。

另一個本質的改進在于epoll采用基于事件的就緒通知方式(設置回調)。在select中,進程只有在調用一定的方法后,內核才對所有監視的文件描述符進行掃描,而epoll事先通過epoll_ctl()來注冊一個文件描述符,一旦基于某個文件描述符就緒時,內核會采用類似callback的回調機制,迅速激活這個文件描述符,當進程調用epoll_wait()時便得到通知

關于epoll和select,可以舉一個例子來表達意思。select的情況和班長告訴全班同學交作業類似,會挨個去詢問作業是否完成,如果沒有完成,班長會繼續詢問。

而epoll的情況則是班長詢問的時候只是統計了待交作業的人數,然后告訴同學作業完成的時候告訴把作業放在某處,然后喊一下他。然后班長每次都去這個地方收作業。

大致了解了epoll之后,我們繼續查看nativePollOnce方法,同理,會調用native Looper的pollOnce方法
while (mResponseIndex < mResponses.size()) {
            const Response& response = mResponses.itemAt(mResponseIndex++);
            int ident = response.request.ident;
            if (ident >= 0) {
                int fd = response.request.fd;
                int events = response.events;
                void* data = response.request.data;
                if (outFd != NULL) *outFd = fd;
                if (outEvents != NULL) *outEvents = events;
                if (outData != NULL) *outData = data;
                return ident;
            }
        }

在pollOnce中,會先處理沒有callback的response(ALOOPER_POLL_CALLBACK = -2),處理完后會執行pollInner方法
// 移除了部分細節處理和日志代碼
// 添加了分析源碼的日志
int Looper::pollInner(int timeoutMillis) {
	if (timeoutMillis != 0 && mNextMessageUptime != LLONG_MAX) {
	        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
	        int messageTimeoutMillis = toMillisecondTimeoutDelay(now, mNextMessageUptime);
	        if (messageTimeoutMillis >= 0
	                && (timeoutMillis < 0 || messageTimeoutMillis < timeoutMillis)) {
	            timeoutMillis = messageTimeoutMillis;
	        }
	  }

	// Poll.
    int result = ALOOPER_POLL_WAKE;
    mResponses.clear();
    mResponseIndex = 0;

    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
	// 等待事件發生或者超時
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // Acquire lock.
    mLock.lock();


	// Check for poll error.
	// epoll 事件小于0, 發生錯誤
    if (eventCount < 0) {
        if (errno == EINTR) {
            goto Done;
        }
        result = ALOOPER_POLL_ERROR;
        goto Done;
    }

	if (eventCount == 0) {
		// epoll事件為0,超時,直接跳轉到Done
        result = ALOOPER_POLL_TIMEOUT;
        goto Done;
    }

	//循環遍歷,處理所有的事件
	for (int i = 0; i < eventCount; i++) {
        int fd = eventItems[i].data.fd;
        uint32_t epollEvents = eventItems[i].events;
        if (fd == mWakeReadPipeFd) {
            if (epollEvents & EPOLLIN) {
                awoken();  //喚醒,讀取管道里面的事件
            } else {
            }
        } else {
            ssize_t requestIndex = mRequests.indexOfKey(fd);
            if (requestIndex >= 0) {
                int events = 0;         
                // 處理request,生成response對象,push到相應的Vector
                pushResponse(events, mRequests.valueAt(requestIndex));
            } else {               
            }
        }
    }

Done: ;

	// Invoke pending message callbacks.
	// 發生超時的邏輯處理
    mNextMessageUptime = LLONG_MAX;
    while (mMessageEnvelopes.size() != 0) {
	    // 處理Native端的Message
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
        const MessageEnvelope& messageEnvelope = mMessageEnvelopes.itemAt(0);
        if (messageEnvelope.uptime <= now) {
            // Remove the envelope from the list.
            // We keep a strong reference to the handler until the call to handleMessage
            // finishes.  Then we drop it so that the handler can be deleted *before*
            // we reacquire our lock.
            { // obtain handler
                sp<MessageHandler> handler = messageEnvelope.handler;
                Message message = messageEnvelope.message;
                mMessageEnvelopes.removeAt(0);
                mSendingMessage = true;
                mLock.unlock();
                handler->handleMessage(message);   // 處理消息事件
            } // release handler

            mLock.lock();
            mSendingMessage = false;
            result = ALOOPER_POLL_CALLBACK;   // 設置回調
        } else {
            // The last message left at the head of the queue determines the next wakeup time.
            mNextMessageUptime = messageEnvelope.uptime;
            break;
        }
    }

    // Release lock.
    mLock.unlock();

    // Invoke all response callbacks.
    // 執行回調
    for (size_t i = 0; i < mResponses.size(); i++) {
        Response& response = mResponses.editItemAt(i);
        if (response.request.ident == ALOOPER_POLL_CALLBACK) {
            int fd = response.request.fd;
            int events = response.events;
            void* data = response.request.data;
            int callbackResult = response.request.callback->handleEvent(fd, events, data);
            if (callbackResult == 0) {
                removeFd(fd);  //移除fd
            }
            // Clear the callback reference in the response structure promptly because we
            // will not clear the response vector itself until the next poll.
            response.request.callback.clear();  // 清除reponse引用的回調方法
            result = ALOOPER_POLL_CALLBACK;  // 發生回調
        }
    }
    return result;
}

看到這里,我們其實可以看出來整體消息模型由 native 和 Java 2層組成,2層各自有自己的消息系統。 Java層通過調用 pollonce 來達到調用底層epoll 讓死循環進入阻塞休眠的狀態,以避免浪費CPU, 所以這也解釋了為什么Android Looper的死循環為什么不會讓主線程CPU占用率飆升。

java層和native層的對應圖如下:

備注
  • Java 層和 native 層通過 MessageQueue 里面持有一個 native 的MessageQueue 對象進行交互。WeakMessageHandler 繼承自MessageHandler,NativeMessageQueue 繼承自 MessageQueue
  • Java 層和 native 層實質是各自維護了一套相似的消息系統。C層發出的消息和Java層發出的消息可以沒有任何關系。所以 Framework 層只是很巧的利用了底層 epoll 的機制達到阻塞的目的。
  • 通過 pollOnce 的分析,可以發現消息的處理其實是有順序的,首先是處理native message,然后處理native request,最后才會執行java層,處理java層的message
可以在子線程中創建Handler嗎?為什么每個線程只會有一個Looper?

在很多時候,我們可以遇到這2個問題。既然看了 Handler 的源碼,那么,我們就順便分析一下這 2 個問題。

查看Handler的構造方法,無參構造方法最后會調用
public Handler(Callback callback, boolean async) {
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

可以看到,這里會直接獲取Looper
public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}

這里會把每個 Looper 存到相應的ThreadLocal對象中,如果子線程直接創建了Handler,Looper 就會是一個null,所以會直接跑出一個"Can't create handler inside thread that has not called Looper.prepare()"的RuntimeException

那么我們是何時把Looper放入ThreadLocal對象的呢?可以在Looper.prepare()中找到答案
private static void prepare(boolean quitAllowed) {
	if (sThreadLocal.get() != null) {
		throw new RuntimeException("Only one Looper may be created per thread");
	}
	sThreadLocal.set(new Looper(quitAllowed));
}

這也解釋了,在每個 Thread 中,只會存在一個 Looper 對象。如果我們想在子線程中正常創建 Handler,就需要提前運行當前線程的 Looper,調用
Looper.prepare()

就不會拋出異常了。

總結

消息機制作為 Android 的基礎,還是非常有深入了解的必要。對于我們遇到Handler發送消息的時候跑出的系統異常的排查也很有意義。

特別感謝

本次源碼的閱讀過程中,遇到了很多不了解的問題例如epoll,這里非常感謝IO哥(查看IO哥大佬)助和指導。讓我在某些細節問題上暫時繞過和恍然大悟。
  • 大小: 13.9 KB
來自: github
0
0
評論 共 0 條 請登錄后發表評論

發表評論

您還沒有登錄,請您登錄后再發表評論

相關推薦

  • android消息機制

    android 消息機制 深入理解android消息機制 更好開發

  • 手寫一套Java的Handler程序,深入理解Android消息機制

    手寫一套Java的Handler程序,深入理解Android消息機制

  • 深入理解Android卷1.pdf

  • Java 消息機制講解非常詳細

    Java 消息機制,講解非常詳細,另外附帶講了ActiveMQ的原理 不可多得的文檔

  • 陳文.郭依正-深入理解Android網絡編程技術詳解與最佳實踐(帶書簽目錄高清完整版).pdf

    深入理解android網絡編程:技術詳解與最佳實踐采用源碼分析的方法,十分詳細地分析了Android系統Framework層的各個方面,詳細分析了其中最為重要的Audio系統和Surface系統。文字描述得比較易懂,值得大家下載閱讀,喜歡的朋友們可以下載試試! 全書共11章,分為三個部分:概述篇(第1章)在介紹了Android開發平臺后,重點講解了Android網絡程序的功能及開發環境的配置,引領讀者走進Android網絡編程的大門;實戰篇(第2~8章),詳細講解了TCP、UDP、HTTP等基本網絡協議在Android上的應用,展示了使用Android處理JSON、SOAP、HTML、XML等數據的方法,講解了Android中的RSS編程、Email編程、OAuth認證等,解析了Android中Locations、Maps、USB、Wi-Fi、Bluetooth、NFC等網絡模塊的編程,討論了Android中線程、數據存取、消息緩存、界面更新等的處理方法,探討了SIP、XMPP等協議在Android上的應用;源碼分析篇(第9~11章)分析了Android中與HTML處理、網絡處理以及部分網絡應用相關的源代碼,幫助讀者從底層原理上加深對相關知識點的理解。 本書適合有一定基礎的Android應用開發工程師和系統工程師閱讀。通過對本書的學習,大家將能更深刻地理解Android系統,從而自如應對實際開發中遇到的難題。

  • 深入理解Android卷1(鄧凡平)pdf

  • 深入理解Android:WebKit卷

    深入理解Android:WebKit卷 深入理解Android:WebKit卷

  • 深入理解Android卷3_高清PDF版

    本書適合Android系統級開發人員,重點在底層和框架層,這是深入理解Android的第3卷。本書為完整掃描版,文字清晰,排版整齊,整體文件經過壓縮,體積更小,去除了多余重復頁面。并且糾正了錯誤的標簽,歡迎對android系統架構感興趣的朋友下載。

  • 深入理解Android之dalvik.pdf

    深入理解Android之dalvik.pdf

  • unity3d游戲框架消息機制

    Unity3d游戲框架中的消息機制,解耦合,代碼有文檔參閱

  • c++經典筆試寶典 C,C++經典問題,及面試筆試題 基本概念 Windows的消息機制

    內含多道c++ 筆試題目以及答案 c++經典筆試寶典 C,C++經典問題,及面試筆試題 基本概念 Windows的消息機制

  • 深入理解ANDROID 卷3高清完整PDF版

    深入理解Android(卷3)》是Android經典暢銷書系“深入理解Android”系列Framework卷的第III卷,從源代碼的角度,對Android系統的Audio和UI兩大功能的相關模塊的實現原理和工作機制做了系統且詳細的分析,填補了市場的空白。   《深入理解Android(卷3)》在邏輯上分為4個部分:   Part 01(第1~2章):這是本書的基礎部分,首先介紹了Android源碼環境的搭建、編譯和調試;然后講解了Android進程間通信與任務調度的工具Binder與MessageQueue。這兩項基礎工作是深入研究Android前必須做的功課。   Part 02(第3章):詳細分析了AudioService服務的實現,包括音量管理、音頻外設管理、AudioFocus機制的實現等內容。   Part 03(第4~6章):這是本書的核心內容之一,詳細分析了Android UI的通用實現,依次剖析了WindowManagerService、Android輸入系統、Android控件系統的工作原理。   Part 04(第7~8章):主要分析了SystemUI和Android壁紙相關服務的實現,包括StatusBarManagerService與NotificationManagerService兩個系統服務,以及WallpaperManagerService系統服務、動態壁紙與靜態壁紙的工作原理等內容。   除此之外,在對海量的Android源代碼進行分析的過程中,本書盡可能地對其中的精妙之處進行了分析和解讀,目的是希望幫助讀者領悟其中的優秀設計思想和方法。

  • 深入理解android telephony原理剖析與最佳實踐

    深入理解Android:Telephony原理剖析與最佳實踐》是“深入理解Android”系列的第3本,前兩本書的內容和質量在Android開發者社群內得到了高度認可,已經樹立起該系列圖書的品牌。在寫作思路和方式上,《深入理解Android:Telephony原理剖析與最佳實踐》與前兩本書一脈相承,對它們的優點進行了繼承和發揚;在內容上,《深入理解Android:Telephony原理剖析與最佳實踐》從從源代碼角度深入解析了Android Telephony的架構設計與實現原理,深刻揭示了Android系統的通信機制。對于Android應用開發工程師和系統工程師而言,《深入理解Android:Telephony原理剖析與最佳實踐》都是難得的研究和學習資料。

  • https://download.csdn.net/download/lcl497049972/10446876

  • 深入理解Android:WiFi模塊 NFC和GPS卷

    深入理解Android:WiFi模塊 NFC和GPS卷,可以用來學習802.11

  • 深入理解android 卷一至卷三 epub版本

    深入理解android 卷一至卷三,共三冊, epub版本,中文文字版。

  • C# Message (消息機制)

  • 深入理解Android內核設計思想(第2版)(上下冊)-試讀版.pdf

    深入理解Android內核設計思想(第2版)(上下冊)-試讀版.pdf

  • 深入理解Android(卷2)(帶全目錄完整版)鄧凡平.pdf

    內容簡介 《深入理解android:卷ii》是“深入理解android”系列的第二本,第一本書上市后得到了廣大讀者的高度評價,在android開發者社群內口口相傳。本書不僅繼承了第一本的優點、改正了其在細微處存在的一些不足,而且還在寫作的總體思想上進行了創新,更強調從系統設計者的角度去分析android系統中各個模塊內部的實現原理和工作機制。從具體內容上講,本書的重點是android framework的java層,對java層涉及的核心模塊和服務進行了深入而細致的分析。通過本書,讀者不僅能對android系統本身有更深入的理解,而且還能掌握分析大型復雜源代碼的能力。   全書共8章:第1章介紹了閱讀本書所需要做的準備工作,包括android 4.0源碼的下載和編譯、eclipse環境的搭建,以及android系統進程(system_process)的調試等;第2章對java binder和messagequeue的實現進行了深入分析;第3章詳細剖析了systemserver的工作原理,這些服務包括entropyservice、dropboxmanagerservice、diskstatsservice、devicestoragemonitorservice、samplingprofilerservice和clipboardservice;第4章對系統中負責package信息查詢和apk安裝、卸載、更新等工作的服務packagemanagerservice進行了詳細分析;第5章則對android系統中負責電源管理的核心服務 powermanagerservice的原理進行了一番深入的分析;第6章以activitymanagerservice為分析重點,對它的啟動、activity的創建和啟動、broadcastreceiver的工作原理、android中的進程管理等內容展開了較為深入的研究;第7章對contentprovider的創建和啟動、sqlite、cursor query和close的實現等進行了深入分析;第8章以contentservice和accountmanagerservice為分析對象,介紹了數據更新通知機制的實現,以及賬戶管理和數據同步等相關知識。 目錄 《深入理解android:卷ii》 前 言 第1章 搭建android源碼工作環境 / 1 1.1 android系統架構 / 2 1.2 搭建開發環境 / 3 1.2.1 下載源碼 / 3 1.2.2 編譯源碼 / 4 1.2.3 利用eclipse調試system_process / 5 1.3 本章小結 / 11 第2章 深入理解java binder和messagequeue / 12 2.1 概述 / 13 2.2 java層中的binder架構分析 / 13 2.2.1 binder架構總覽 / 13 2.2.2 初始化java層binder框架 / 14 2.2.3 addservice實例分析 / 17 2.2.4 java層binder架構總結 / 26 2.3 心系兩界的messagequeue / 27 2.3.1 messagequeue的創建 / 27 2.3.2 提取消息 / 28 2.3.3 nativepollonce函數分析 / 31 2.3.4 messagequeue總結 / 41 2.4 本章小結 / 42 第3章 深入理解systemserver / 44 3.1 概述 / 45 3.2 systemserver分析 / 45 3.2.1 main函數分析 / 45 3.2.2 service群英會 / 48 3.3 entropyservice分析 / 49 3.4 dropboxmanagerservice分析 / 50 3.4.1 dbms構造函數分析 / 51 3.4.2 dropbox日志文件的添加 / 51 3.4.3 dbms和settings數據庫 / 56 3.5 diskstatsservice和devicestoragemonitorservice分析 / 56 3.5.1 diskstatsservice分析 / 56 3.5.2 devicestoragemanagerservice分析 / 58 3.6 samplingprofilerservice分析 / 60 3.6.1 samplingprofilerservice構造函數分析 / 61 3.6.2 samplingprofilerintegration分析 / 62 3.7 clipboardservice分析 / 64 3.7.1 復制數據到剪貼板 / 64 3.7.2 從剪切板粘貼數據 / 67 3.7.3 cbs中的權限管理 / 69 3.8 本章小結 / 73 第4章 深入理解packagemanagerservice / 74 4.1 概述 / 75 4.2 初識packagemanagerservice / 76 4.3 pkms的main函數分析 / 77 4.3.1 構造函數分析之前期準備工作 / 78 4.3.2 構造函數分析之掃描package / 90 4.3.3 構造函數分析之掃尾工作 / 105 4.3.4 pkms構造函數總結 / 105 4.4 apk installation分析 / 105 4.4.1 adb install分析 / 105 4.4.2 pm分析 / 107 4.4.3 installpackagewithverification函數分析 / 109 4.4.4 apk 安裝流程總結 / 121 4.4.5 verification介紹 / 122 4.5 queryintentactivities分析 / 124 4.5.1 intent及intentfilter介紹 / 124 4.5.2 activity信息的管理 / 125 4.5.3 intent 匹配查詢分析 / 128 4.5.4 queryintentactivities總結 / 131 4.6 installd及usermanager介紹 / 131 4.6.1 installd介紹 / 131 4.6.2 usermanager介紹 / 136 4.7 本章學習指導 / 138 4.8 本章小結 / 138 第5章 深入理解powermanagerservice / 139 5.1 概述 / 140 5.2 初識powermanagerservice / 140 5.2.1 pms構造函數分析 / 141 5.2.2 init分析 / 141 5.2.3 systemready分析 / 147 5.2.4 bootcomplete處理 / 148 5.2.5 初識powermanagerservice總結 / 149 5.3 pms wakelock分析 / 149 5.3.1 wakelock客戶端分析 / 149 5.3.2 pms acquirewakelock分析 / 151 5.3.3 power類及lightservice類介紹 / 160 5.3.4 wakelock總結 / 163 5.4 useractivity及power按鍵處理分析 / 164 5.4.1 useractivity分析 / 164 5.4.2 power按鍵處理分析 / 167 5.5 batteryservice及batterystatsservice分析 / 168 5.5.1 batteryservice分析 / 169 5.5.2 batterystatsservice分析 / 172 5.5.3 batteryservice及batterystatsservice總結 / 182 5.6 本章學習指導 / 183 5.7 本章小結 / 183 第6章 深入理解activitymanagerservice / 184 6.1 概述 / 185 6.2 初識activitymanagerservice / 186 6.2.1 activitymanagerservice的main函數分析 / 187 6.2.2 ams的 setsystemprocess分析 / 197 6.2.3 ams的 installsystemproviders函數分析 / 202 6.2.4 ams的 systemready分析 / 211 6.2.5 初識activitymanagerservice總結 / 218 6.3 startactivity分析 / 219 6.3.1 從am說起 / 219 6.3.2 ams的startactivityandwait函數分析 / 221 6.3.3 startactivitylocked分析 / 230 6.4 broadcast和broadcastreceiver分析 / 265 6.4.1 registerreceiver流程分析 / 267 6.4.2 sendbroadcast流程分析 / 272 6.4.3 broadcast_intent_msg消息處理函數 / 276 6.4.4 應用進程處理廣播分析 / 282 6.4.5 廣播處理總結 / 284 6.5 startservice之按圖索驥 / 285 6.5.1 service知識介紹 / 285 6.5.2 startservice流程圖 / 286 6.6 ams中的進程管理 / 287 6.6.1 linux進程管理介紹 / 287 6.6.2 關于android中的進程管理的介紹 / 289 6.6.3 ams進程管理函數分析 / 294 6.6.4 ams進程管理總結 / 305 6.7 app的 crash處理 / 305 6.7.1 應用進程的crash處理 / 306 6.7.2 ams的handleapplicationcrash分析 / 306 6.7.3 appdeathrecipient binderdied分析 / 309 6.7.4 app的crash處理總結 / 313 6.8 本章學習指導 / 314 6.9 本章小結 / 315 第7章 深入理解contentprovider / 316 7.1 概述 / 317 7.2 mediaprovider的啟動及創建 / 318 7.2.1 context的getcontentresolver函數分析 / 318 7.2.2 mediastore.image.media的query函數分析 / 319 7.2.3 mediaprovider的啟動及創建總結 / 329 7.3 sqlite創建數據庫分析 / 330 7.3.1 sqlite及sqlitedatabase家族 / 330 7.3.2 mediaprovider創建數據庫分析 / 335 7.3.3 sqlitedatabase創建數據庫的分析總結 / 344 7.4 cursor 的query函數的實現分析 / 345 7.4.1 提取query關鍵點 / 346 7.4.2 mediaprovider 的query分析 / 349 7.4.3 query關鍵點分析 / 356 7.4.4 cursor query實現分析總結 / 368 7.5 cursor close函數實現分析 / 368 7.5.1 客戶端close的分析 / 369 7.5.2 服務端close的分析 / 371 7.5.3 finalize函數分析 / 372 7.5.4 cursor close函數總結 / 373 7.6 contentresolver openassetfiledescriptor函數分析 / 373 7.6.1 openassetfiledescriptor之客戶端調用分析 / 374 7.6.2 contentprovider的 opentypedassetfile函數分析 / 376 7.6.3 跨進程傳遞文件描述符的探討 / 379 7.6.4 openassetfiledescriptor函數分析總結 / 384 7.7 本章學習指導 / 384 7.8 本章小結 / 385 第8章 深入理解contentservice和accountmanagerservice / 386 8.1 概述 / 387 8.2 數據更新通知機制分析 / 387 8.2.1 初識contentservice / 388 8.2.2 contentresovler 的registercontentobserver分析 / 389 8.2.3 contentresolver的 notifychange分析 / 391 8.2.4 數據更新通知機制總結和深入探討 / 393 8.3 accountmanagerservice分析 / 395 8.3.1 初識accountmanagerservice / 396 8.3.2 accountmanager addaccount分析 / 402 8.3.3 accountmanagerservice的分析總結 / 414 8.4 數據同步管理syncmanager分析 / 415 8.4.1 初識syncmanager / 415 8.4.2 contentresolver 的requestsync分析 / 424 8.4.3 數據同步管理syncmanager分析總結 / 436 8.5 本章學習指導 / 437 8.6 本章小結 / 437 “深入理解android”系列書籍的規劃路線圖 / 438

  • 許奔-深入理解Android自動化測試(帶書簽完整版).pdf

    聯想集團董事長兼CEO楊元慶、ZUKCEO常程鼎力推薦,資深測試專家多年經驗總結。本書以漫畫和對話風格對Android平臺的各種自動化測試工具、框架的原理、使用技巧和二次開發進行了詳細的講解。 《深入理解Android自動化測試》分為四篇,共21章: 基礎篇(第1~7章),簡單介紹Android常用自動化測試工具和框架的基本使用技巧與相關理論,幫助讀者直接上手操作這些工具或使用框架撰寫自動化腳本。 原理篇(第8~13章),通過對Android常用自動化測試工具和框架的源碼剖析,讓大家更直觀地了解工具的運行原理。讓讀者不但可以更靈活地運用這些工具和框架,清楚地知道應用這些工具和框架的局限性,還可以基于這些源碼更深入地對工具和框架進行二次開發。 實戰篇(第14~18章),通過項目中的各種需求和實際問題來分析工具的不足,從而開發一些小工具或對框架進行二次封裝,循著這條線索開發出更多、更實用的工具,或對框架進行更深入的封裝。 反思篇(第19~21章),結合實際工作中領導們提出的各種問題,對工具、測試本身以及人深入進行討論和反思,深入思考Android自動化測試以及軟件自動化測試從業人員都在面臨的問題。

Global site tag (gtag.js) - Google Analytics 真人娱乐官方网站 通化县| 万荣县| 黄冈市| 洮南市| 宜昌市| 南投县| 新竹县| 金沙县| 天峨县| 宁远县| 怀仁县| 府谷县| 鲁山县| 西安市| 唐海县| 鲁山县| 武汉市| 新乡县| 保康县| 嘉荫县| 锡林浩特市| 马龙县| 迭部县| 维西| 达孜县| 浮梁县| 大同县| 三都| 蚌埠市| 鲁山县| 射阳县| 民权县| 孝昌县| 策勒县| 巴里| 厦门市| 长治市| 宁强县| 黎川县| 鄂州市| 南华县| 福建省| 延川县| 大冶市| 道孚县| 扎囊县| 马关县| 伽师县| 清原| 浏阳市| 察哈| 普定县| 承德市| 蒲城县| 兰考县| 绥阳县| 清苑县| 当阳市| 巢湖市| 合江县| 安塞县| 仪陇县| 门源| 凤翔县| 开封市| 张家港市| 滨海县| 普兰店市| 黄冈市| 曲松县| 和林格尔县| 义乌市| 澄迈县| 凤台县| 岳西县| 大余县| 岳阳县| 虞城县| 荔波县| 甘泉县| 博野县| 石柱| 星子县| 元谋县| 临武县| 亚东县| 东乡县| 贵港市| 丰镇市| 武清区| 宜春市| 含山县| 洛宁县| 建平县| 南开区| 丰原市| 察隅县| 巫山县| 和政县| 闽侯县| 邵东县| 昌宁县| 天祝| 南溪县| 镇雄县| 津南区| 长丰县| 那曲县| 江孜县| 青神县| 盐津县| 怀集县| 清水县| 平邑县| 嵊州市| 蒙山县| 西乡县| 定西市| 淳安县| 锡林浩特市| 高碑店市| 东海县| 梧州市| 太康县| 油尖旺区| 奉节县| 玉龙| 普定县| 江陵县| 安平县| 太原市| 蒙城县| 沙坪坝区| 两当县| 绿春县| 长泰县| 北碚区|