2014年3月11日 星期二

Git 常用指令

1. git status
    可以看到目前 Git 的狀態
2. git add <filename>
    將檔案 filename 加入 staged
3. .gitignore 檔案讓你避免加入一些類型的檔案。格式大致上如下
# 註解,會被忽略。 # 不要追蹤檔名為 .a 結尾的檔案 *.a # 但是要追蹤 lib.a,即使上方已指定忽略所有的 .a 檔案 !lib.a # 只忽略根目錄下的 TODO 檔案。 不包含子目錄下的 TODO /TODO # 忽略build/目錄下所有檔案 build/ # 忽略doc/notes.txt但不包含doc/server/arch.txt doc/*.txt # ignore all .txt files in the doc/ directory doc/**/*.txt

4. git diff
命令比對目前工作目錄及暫存區域後告訴讀者哪些變更尚未被暫存。
5. git diff --staged
    這命令比對暫存區域及最後一個提交。
6. git commit -m "message" 或 git commit -m '可換行' 
7. git rm
    從已被追蹤檔案中移除並且提交
8. git log -p
    列出每次的更新之間差別的內容
9. git log --stat
    列出更新之間差別的內容的大綱
10. git commit --amend (會出現一個文書編輯器)
重新 commit ,例如想要修改上次 commit 或上次commit 漏掉了一些檔案沒 commit 可以用這個
11. git reset HEAD <filename>
將 filename 從 staged 中移除,取消暫存。
12. git checkout <PATH>
將 PATH 以下的檔案都 checkout。復原到最後一次 commit 的狀態。
13. git remote add [shortname] [url]
增加新的遠端儲存庫
14. git fetch [remote-name]
將所有本地端沒有的資料拉下來。僅僅將資料拉到本地端的儲存庫,但沒有合併,跟 git pull 不同。
15. git remote show [remote-name]
      看資訊可以看到remote branch, 跟 local branck track 的情形

16. git reset --hard 某個版本的 hash 編號   # 整個 Repository 恢復到某個版本的狀態

17. git branch 
       看 branch, 加 -d [branch name] 可以刪除 branch
18. git checkout -b [branch_name]
       直接開啟一個 branch_name 的分支並把 head 指向他。
19. git merge [branch_name]
       將 branch_name 分支和到目前 head 指向的分支。


20. git checkout --track origin/serverfix 建立一個 "tracking branch" for remote branch " origin/serverfix "

21. git branch -vv   觀察local branch 跟 remote branch 的關係

22. git reflog
      git reset [sha] 
      可以回復 git reset --hard

23. 查看 git repository 是從哪個地方 clone 的 url 位置
git config --get remote.origin.url

24. git rev-parse --verify HEAD
查看 HEAD 所指的 SHA-1 value

25. git push -u origin new_branch # 建立遠端 branch (將 new_branch 建立到遠端)

2014年2月9日 星期日

int& a = b 的解釋

以下是在 cplusplus 網頁上看到的

int a = b is setting a's VALUE to b's VALUE
int* a = &b is setting a's VALUE to the ADDRESS of b
int& a = b is setting a's ADDRESS to b's ADDRESS (a is a reference to b)

上面話的用我自己的理解來解釋如下
int& a = b 的用法就是說,將 a 的 address 設定為 b 的 address,換居話說 a 幾乎就跟 b 一模一樣。

用 printf 來表示應該如下

================================
第一個 case int a=b

int b = 5;
int a = b
pintf ( a, b, &a, &b ) 可能會有如下結果

(5, 5, 0xdfe0, 0xad06) 兩個 address 不一樣
================================


================================
第二個 case int* a=b

int b = 5;
int *a = b
pintf ( a, b, &a, &b ) 可能會有如下結果

(0xad06, 5, 0xdfe0, 0xad06)     a 的值就是 b 的 address
================================

================================
第三個 case int& a=b

int b = 5;
int &a = b
pintf ( a, b, &a, &b ) 可能會有如下結果

a = 5, b = 5, &a = 0x2a1ae39c, &b = 0x2a1ae39c
a 就是 b 
================================


第三個 case 我有真的打印來看,不會有問題。

Android 4.3 surfaceflinger 中的 handleMessageTransaction

在我工作的平台上,HDMI output ,每次 vsync 發生時 surfaceflinger 收到的 message 是 MessageQueue::INVALIDATE。然後surfaceflinger 會執行下面 function ,

        handleMessageTransaction();
        handleMessageInvalidate();
        signalRefresh();

這篇主要先分析 handleMessageTransaction()。而這個 function 全文在 4.3 中如下

void SurfaceFlinger::handleMessageTransaction() {
    uint32_t transactionFlags = peekTransactionFlags(eTransactionMask);
    if (transactionFlags) {
        handleTransaction(transactionFlags);
    }
}

他會先透過 peekTransactionFlags(eTransactionMask),來窺視 mTransactionFlags 是否非零,如果是才會進入 handleTransaction(transactionFlags)。mTransactionFlags 是 surfaceflinger 中的一個 member ,當有某個 surface 狀態有改變或createSurface、 removeSurface、addLayer 等等的行為發生時都會透過 SurfaceFlinger::setTransactionFlags() 設定這個 flag 。目前有三個 bit 可被設置,分別如下

enum {
    eTransactionNeeded        = 0x01,  (二進位表示0001)
    eTraversalNeeded          = 0x02,    (二進位表示0010)
    eDisplayTransactionNeeded = 0x04,   (二進位表示0100)
    eTransactionMask          = 0x07    (二進位表示0111)
};

其中個別代表什麼還不是很清楚,在 surfaceflinger 搜尋 setTransactionFlags 看到 eTransactionNeeded 會在 createLayer、removeLaye 中被設置。eDisplayTransactionNeeded 則在 createDisplay() 跟 onHotplugReceived () 中被設置,。eTraversalNeeded 則是在 surfaceFlinger 裡面我搜尋不到,應該是由別的地方去設置,將來有看到再補。

========================================================================
回到 handleMessageTransaction 中,上面的任何一個情況有發生,才會呼叫 handleTransaction 。

void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
    ATRACE_CALL();

    Mutex::Autolock _l(mStateLock);
    const nsecs_t now = systemTime();
    mDebugInTransaction = now;

    // Here we're guaranteed that some transaction flags are set
    // so we can call handleTransactionLocked() unconditionally.
    // We call getTransactionFlags(), which will also clear the flags,
    // with mStateLock held to guarantee that mCurrentState won't change
    // until the transaction is committed.

    transactionFlags = getTransactionFlags(eTransactionMask);
    handleTransactionLocked(transactionFlags);

    mLastTransactionTime = systemTime() - now;
    mDebugInTransaction = 0;
    invalidateHwcGeometry();
    // here the transaction has been committed
}

這個很短沒什麼特別需要解釋的,其中 invalidateHwcGeometry 這個 function 只是執行 mHwWorkListDirty = true,實際上做什麼目前還不清楚,之後有看到再補。
所以接下來就是進入 handleTransactionLocked()中。

========================================================================
handleTransactionLocked 比較長,主要就是去檢視上面提到的 mTransactionFlags 來執行對應的工作。還是照著順序來吧。

首先,檢查 eTraversalNeeded 是否有被拉起來,有的話,顧名思義 traversal 所有 layer。
    if (transactionFlags & eTraversalNeeded) {
        for (size_t i=0 ; i<count ; i++) {
            const sp<Layer>& layer(currentLayers[i]);
            uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
            if (!trFlags) continue;

            const uint32_t flags = layer->doTransaction(0);
            if (flags & Layer::eVisibleRegion)
                mVisibleRegionsDirty = true;
        }
    }

layer->getTransactionFlags(eTransactionNeeded) 會檢查 layer 類別中的成員 mTransactionFlags 的 eTransactionNeeded 是否被設置。注意這裡的 mTransactionFlags 只給每個 layer 自己用 ,surfaceflinger 中也有一個名稱一樣的(也就是上面提的),不要搞混了。如果目前掃到的 layer 的 eTransactionNeeded 有被設置,就執行 
layer->doTransaction。

接著分析 Layer 中的 doTransaction 在做什麼。首先

    const Layer::State& front(drawingState());
    const Layer::State& temp(currentState());

    const bool sizeChanged = (temp.requested.w != front.requested.w) ||
                             (temp.requested.h != front.requested.h);


    if (sizeChanged) {
        // record the new size, form this point on, when the client request
        // a buffer, it'll get the new size.
        mSurfaceFlingerConsumer->setDefaultBufferSize(
                temp.requested.w, temp.requested.h);
    }

drawingState 會回傳 Layer 中的 mDrawingState ,代表的是 " 上一次 drawing " 的 layer 狀態;而 currentState 會回傳 mCurrentState,代表此 layer 目前狀態。得到狀態後,首先檢查是否發生尺寸上的變化(sizeChanged),如果有發生改變就執行 mSurfaceFlingerConsumer->setDefaultBufferSize(temp.requested.w, temp.requested.h); 這裡實際運作情況待補,現在就把他理解成會根據不同的尺寸來設定 mDefaultWidth 跟 mDefaultHeight,之後會根據這兩個值來設定 Buffer 大小。

接著

    if (!isFixedSize()) {

        const bool resizePending = (temp.requested.w != temp.active.w) ||
                                   (temp.requested.h != temp.active.h);

        if (resizePending) {
            // don't let Layer::doTransaction update the drawing state
            // if we have a pending resize, unless we are in fixed-size mode.
            // the drawing state will be updated only once we receive a buffer
            // with the correct size.
            //
            // in particular, we want to make sure the clip (which is part
            // of the geometry state) is latched together with the size but is
            // latched immediately when no resizing is involved.

            flags |= eDontUpdateGeometryState;
        }
    }
    // always set active to requested, unless we're asked not to
    // this is used by Layer, which special cases resizes.
    if (flags & eDontUpdateGeometryState)  {
    } else {
        Layer::State& editTemp(currentState());
        editTemp.active = temp.requested;
    }

調用 isFixedSize 來判斷 mCurrentScalingMode 是否為 FixedSize mode,如果不是 fixed size 的則進去判斷 current state 中的 request 跟 active 的 width 跟 height 是否相同,不相同的話,就把 eDontUpdateGeometryState 這個 flag 拉起來。然後進入下列的幾個判斷式

   // always set active to requested, unless we're asked not to
    // this is used by Layer, which special cases resizes.
    if (flags & eDontUpdateGeometryState)  {
    } else {
        Layer::State& editTemp(currentState());
        editTemp.active = temp.requested;
    }

    if (front.active != temp.active) {
        // invalidate and recompute the visible regions if needed
        flags |= Layer::eVisibleRegion;
    }

    if (temp.sequence != front.sequence) {
        // invalidate and recompute the visible regions if needed
        flags |= eVisibleRegion;
        this->contentDirty = true;

        // we may use linear filtering, if the matrix scales us
        const uint8_t type = temp.transform.getType();
        mNeedsFiltering = (!temp.transform.preserveRects() ||
                (type >= Transform::SCALE));
    }

上面有三個 if 判斷式,第一個就是如果 eDontUpdateGeometryState 被拉起來,那就不會把 requested assign 給 active,如果這邊猜測沒有問題的話,接下來的判斷式
    if (front.active != temp.active) 
會檢查上一次跟這一次的 active 一不一樣,不一樣的話會拉 eVisibleRegion 表示 visible region 有改變。
第三個判斷式是判斷 drawing  跟 current 的 sequence 值是否一樣,mCurrentState.sequence 在很多 Layer 的改變的操作被呼叫時(例如:setLayer、setSize 等)就會被累加一 。如果不一樣的話也拉 eVisibleRegion,然後將 contentDirty 設為 true ,接著會修改 mNeedsFiltering 值。

雖然從程式邏輯上很容易可以理解這些步驟,但是這些東西到底是要做什麼的從這邊不太容易看出來。尤其是 eDontUpdateGeometryState 這個東西該怎麼理解 。之後理解了再補上。

最後會呼叫 commitTransaction(),這個 function 內容如下,很簡單。

void Layer::commitTransaction() {
    mDrawingState = mCurrentState;
}

最後 return flag,然後我們離開 doTrasaction 啦! 程式回到 handleTransactionLocked,doTrasaction 之後馬上有人檢查 return 的值

 if (flags & Layer::eVisibleRegion)
          mVisibleRegionsDirty = true;

如果有任何一個 Layer 有變動,就會把 mVisibleRegionsDirty 設為 true。
========================================================================

接著再繼續 handleTransactionLocked,第二個要確認的 flag 是 eDisplayTransactionNeeded
從上面可以稍微了解到 eDisplayTransactionNeeded 是在 createDisplay 或 onHotplugReceived 發生時會被拉起來。所以這邊我可以稍微猜想一下他會做什麼。基本上他應該會‧‧‧‧,痾‧‧‧,算了!看 code 吧。

以 createDisplay 為例,createDisplay 中會呼叫

mCurrentState.displays.add(token, info);

加入一個 DisplayDeviceState 進 display 這個 DefaultKeyedVector 中。 DefaultKeyedVector 宣告如下

class DefaultKeyedVector : public KeyedVector<KEY, VALUE>

它繼承自 KeyedVector,可以透過  valueFor(const KEY& key)用 key 值找到對應的物件(value),或透過 isIdenticalTo(const KeyedVector& rhs) 比對兩個 KeyedVector 是否相同。

所以當 createDisplay 發生時,下面兩個 if 判斷式應該都會成立,所以這個 case 主要的工作就是 if (!curr.isIdenticalTo(draw)) 成立後裡面做的事。(這邊舉 createDisplay 只是要知道有那些時候會進入這個條件,後面的介紹跟這個 function 在沒關係。)

 if (transactionFlags & eDisplayTransactionNeeded) {
        // here we take advantage of Vector's copy-on-write semantics to
        // improve performance by skipping the transaction entirely when
        // know that the lists are identical
        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
        const KeyedVector<  wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
        if (!curr.isIdenticalTo(draw)) {
                       ●
                       ●
                       ●
        }
}

而裡面的工作主要是歷遍整個 mDrawingState.displays 中的所有物件,然後利用

const ssize_t j = curr.indexOfKey(draw.keyAt(i));

來判斷是否存在於 mCurrentState.displays 中, j < 0 的話表示沒有,代表在新的 state 中已被移除。如果已被移除,判斷如果不是 DISPLAY_PRIMARY ( 代表手機螢幕) 則先將 defaultDisplay makeCurrent (此處跟 EGL 相關,簡單講就是將 display 設回手機螢幕),接著在移除這個 display 。

如果  j > 0 表示他還沒被移除,就檢查一下他的狀態是否有被改變,有的話再做對應的動作 (setLayerStack、setProjection 等等)。

上面是遍歷整個 mDrawingState.displays 來判斷是否有物件被移除,接著反過來歷遍整個 mCurrentState.displays 看是否有物件被新加進來,然後作對應的處理 (先略)。

========================================================================
在 4.2 的 MessageQueue::INVALIDATE 的訊息處理還有兩個 function 被執行

        handleMessageInvalidate();
        signalRefresh();

signalRefresh 看似會發 MessageQueue::REFRESH ,所以等於還是會執行 handleMessageRefresh
裡面還有好幾個 function 。



2014年1月2日 星期四

Android 4.3 sp<> 與 wp<> 、Smart Pointer、紀錄

Google Android Smart Pointer 會有很多相關的知識可以參考,這邊只列一些簡單的用法跟注意事項。

普通指標宣告如下,

MyClass *p;

改成用 Smart pointer 如下,

sp<MyClass> p;

p 是指標 (注意不要寫成 sp<MyClass> *p; ), <XXX> 的用法是 C++ 的 template 。然後就可以用這個指標指向一個 new 出來的 object。

p = new MyClass(); 

而且不需要去 delete 。在 Android 中,上面的等號是經過重載的,表面上意義跟一般等號一樣,實際上的行為除了設定 sp 中的 private 成員 m_ptr,還會執行"目前物件的 incStrong" 跟"原本這個指標指向的物件的 decStrong" 等,後面會再詳述 。

sp 是一個 object,常常會把要指定給 p 的 object 直接傳給 sp 的建構式,下面列出 4.3 版的 sp 建構式。

1.    sp(T* other);
2.    sp(const sp<T>& other);
3.    template<typename U> sp(U* other);
4.    template<typename U> sp(const sp<U>& other);

(1)是最常見的,舉例如下

sp<Client> client (new Client());  

 會直接把  new 出來的 object assigne 到 m_ptr,m_ptr是 sp 這個 class 的 private 成員,型別是

T* m_ptr;

用來指向實際物件的位置。當你用 smart pointer 要存取Client的成員的時候,例如

client->initCheck();

實際上 -> 運算子會 return m_ptr。所以是透過 m_ptr 來執行 initCheck() 的,

m_ptr->initCheck();

接著看有沒有其他建構方式的例子。

(2) sp(const sp<T>& other); 就是把另一個在其他地方 new 好的 sp 指標,指定給目前的 sp 指標,例如

sp<const DisplayDevice> hw(getDefaultDisplayDevice());

getDefaultDisplayDevice 裡面太複雜就不分析了,有機會看能不能找到其他例子把他替換掉,整體來講這個的觀念如下

sp<Myclass> p1( new MyClass() );

sp<Myclass> p2 (p1)


補充一下,sp(const sp<T>& other) 中的 sp<T>& ,表示調用 sp 建構式時,參數 other 是以 call by reference 方式傳遞的。

(3)跟(4) 分別對應到上面兩種方式,差別在於參數中的型別是不一樣的,template<typename U>,建構時會把 U 轉型成 T,通常 U 跟 T 應該會有繼承關係。

====================================================================

那 sp 是如何做到自動釋放記憶體呢? 答案在 RefBase 這個 object 中,每當 object 透過 sp 來引用的時候,都會執行 incStrong() 這個 RefBase 的成員,incStrong會把引用計數 mStrong 加 1,然後如果是第一次被引用,還會順便執行 onFirstRef(),

反之,當物件不在被引用時,例如 client = NULL時,會執行 decStrong 來把引用計數 mStrong 減 1,如果 mStrong 變為 0,就會執行 delete 把物件存記憶體釋放,藉此達到自動釋放的功能。

所以,注意啦!所有要用到 smart pointer 的類別,都必須繼承自 RefBase 或 LightRefBase。例如上例的Client,慢慢追你會追到他就是繼承自 RefBase 。

class Client : public BnSurfaceComposerClient
class BnSurfaceComposerClient: public BnInterface<ISurfaceComposerClient> 
class BnInterface : public INTERFACE, public BBinder
class ISurfaceComposerClient : public IInterface
class IInterface : public virtual RefBase

如上,包很厚。

注:Client 這個類別定義在\frameworks\native\services\surfaceflinger\Client.h
========================================================================

wp 的觀念基本上跟 sp 一樣,但要用 wp 的 object 一定得是繼承自 RefBase。

而 wp 的引用計數是 mWeak,當 wp 被建構或解構時分別會呼叫 incWeak() 跟 decWeak() 來改變引用計數。另外 sp 在 incStrong (decStrong) 執行時也會呼叫 incWeak (decWeak)。這個部分在觀念上有點像是 sp 是 wp 的 superset。但也不能完全這樣講,因為有些 wp 的運算 sp 也不能直接使用的樣子。

wp 不能直接存取所指物件的成員,如果要存取所指物件的成員,需要透過  promote() 將 wp 升級為 sp。例如:

sp<A>  p1 ;

wp<A> p2 ( new A());


p1 = p2.promote();


A->member();



wp 只重載比較運算子 (==、 != 、 >=、 <= 等),所以只能透過 wp 來比較兩個物件 (上段講的sp  不能說完全是  wp 的 superset 就是這裡,我從程式看起來似乎 sp 無法直接使用這些比較運算)。

========================================================================

RefBase 提供 extendObjectLifetime(int32_t mode); 讓使用者改變物件的生命週期,決定何時要 delete 物件, 參數 mode 的值可以如下定義:

    enum {
        OBJECT_LIFETIME_STRONG  = 0x0000,  // mStrong 為 0 時 delete 物件
        OBJECT_LIFETIME_WEAK    = 0x0001,    // mWeak 為 0 時 delete 物件
        OBJECT_LIFETIME_MASK    = 0x0001     //
    };

所以當你設定為 OBJECT_LIFETIME_WEAK 時,表示就算只有 wp ,物件還是不會被刪除。會保留到當連 wp 都沒有的時候才會 delete 掉物件。至於這個使用的時機跟目的該怎麼解釋,目前我還不甚了解,改天有看到例子再補。