ZygoteConnection.java
=> boolean runOnce() 最後會 fork 出新的 process
#################################################
ActivityThread.java
main ()
=> handleLaunchActivity
-----------------------------------------------------------------------------------------------------------------
=> performLaunchActivity
// 生出 Activity
=> activity = mInstrumentation.newActivity(cl,component.getClassName(), r.intent);
=> activity.attach
// 生出 PhoneWindow, 並取得 WindowManager "WindowManagerImpl", 他的 parentWindow 是 mWindow (PhoneWindow)
=> mWindow = new PhoneWindow(this);
=> mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
=> mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
// new WindowManagerImpl(mDisplay, parentWindow);
// 呼叫 Activity 的 onCreate (這裡已經被你的Activity override掉了)
=> onCreate
// 呼叫setContentView();
=> setContentView(R.layout.activity_main);
// 呼叫 PhoneWindow::setContentView()
=> getWindow().setContentView(view);
// 取得 mDecor 以及 mContentParent
// 其中 mContentParent 是 ViewGroup, 在創建的時候我們會把這個 mDecor帶入
=> installDecor(); // new DecorView(getContext(), -1);
=> generateLaout(mDecor); // ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
// 呼叫 addView, 這邊的 view 是一開始帶進來的 R.layout.activity_main
=> mContentParent.addView(view, params);
// 將傳入的 view 作為 child 保存起來, 並指定 parent為自己
=> addViewInner(child, index, params, false);
=> child.mParent = this;
-----------------------------------------------------------------------------------------------------------------
=> handleResumeActivity
// 呼叫 Activity 的 onResume()Activity的onResume()方法
=> ActivityClientRecord r = performResumeActivity(token, clearHide);
// 呼叫 WindowManager, 也就是 WindowManagerImpl 的 addView
=> wm.addView(decor, l);
// 實作在 WindowManagerGlobal
=> mGlobal.addView(view, params, mDisplay, mParentWindow);
// 建立 ViewRootImpl
=> ViewRootImpl root;
root = new ViewRootImpl(view.getContext(), display);
// 在 ViewRootImpl 的建構子內部又透過了 windowManager 去呼叫 openSession
// 最後取得了 Session 用來作為跟 WindowManagerService 通信的手段
=> sWindowSession = windowManager.openSession(
new IWindowSessionCallback.Stub() {
@Override
public void onAnimatorScaleChanged(float scale) {
ValueAnimator.setDurationScale(scale);
}
},
imm.getClient(), imm.getInputContext());
// Session session = new Session(this, callback, client, inputContext);
// 對於 ViewRootImpl 來說是他內部的 mWindowSession
// 另外這裡還 new 了一個 W class, 用處是收取發生的事件
// 他繼承了 IWindow, 可以看到裡面實作的 API 諸如 dispatchGetNewSurface, dispatchAppVisibility 這種
mWindow = new W(this);
// 注意 ViewRootImpl 內部有個 mSurface 對象, 之後會拿這個對象來繪圖
=> final Surface mSurface = new Surface();
// 接著我們繼續回到 WindowManagerGlobal 的 addView 函數,
// 接下來是呼叫了 ViewRootImpl 的 setView, 這邊的 view 參數是 decorView 而不是一開始傳入的 R.layout.activity_main
=> root.setView(view, wparams, panelParentView);
// ViewRootImpl 的 requestLayout 可就做了不少事情
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
=> requestLayout();
// 規劃了接下來的 Traversal callback
=> scheduleTraversals();
// Posts a callback to run on the next frame
// The callback runs once then is automatically removed.
// 怎麼觸發的後面再看, 我們先跳離 requestLayout()
=> mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// mWindowSession 就是前面 new 出來的 Session
=> mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mOutsets, mInputChannel);
// mService 是 WindowManagerService (前面有提到說透過 Session 來跟 WindowManagerService 溝通)
=> mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outStableInsets, outOutsets, outInputChannel);
// 創建一個 WindowState 對象, 並呼叫他的 attach() 函數
=> WindowState win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);
=> win.attach();
// 呼叫 Session 的 windowAddedLocked();
=> mSession.windowAddedLocked();
// new 出一個 SurfaceSession 對象
=> mSurfaceSession = new SurfaceSessionSurfaceSession();
/** Create a new connection with the surface flinger. */
// 跟 SurfaceFlinger 搭上線了
=> mNativeClient = nativeCreate();
// 生成了一個 SurfaceComposerClient 對象, 他之後會被用來跟 SurfaceControl 進行溝通
=> SurfaceComposerClient* client = new SurfaceComposerClient();
// 把這個 WindowState 對象放進mWindowMap, 後面畫圖的時候會用到
=> mWindowMap.put(client.asBinder(), win);
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// 回到 scheduleTraversals(), 從 mTraversalRunnable 進入
=> final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
=> doTraversal();
=> performTraversals();
**************************************************************************
=> relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
=> performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
=> performLayout(lp, desiredWindowWidth, desiredWindowHeight);
=> performDraw();
**************************************************************************
// 先從 relayoutWindow 開始
=> relayoutResult = mWindowSession.relayout(
mWindow, mSeq, params,
(int) (mView.getMeasuredWidth() * appScale + 0.5f),
(int) (mView.getMeasuredHeight() * appScale + 0.5f),
viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface);
// Session
// 注意這個 mSurface 傳入以後命名變成了 outSurface (這是在 ViewRootImpl 建構子生成的那個 Surface 對象
=> mService.relayoutWindow(this, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outOverscanInsets, outContentInsets, outVisibleInsets,
outStableInsets, outsets, outConfig, outSurface);
// WindowManagerService
// 拿出剛剛在 addWindow 生出來的 WindowState
=> WindowState win = windowForClientLocked(session, client, false); // WindowState win = mWindowMap.get(client);
=> WindowStateAnimator winAnimator = win.mWinAnimator; // 在 WindowState 建構時, new WindowStateAnimator(this);
// 建構出 SurfaceControl ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
=> SurfaceControl surfaceControl = winAnimator.createSurfaceLocked();
=> mSurfaceControl = new SurfaceControl(
mSession.mSurfaceSession,
attrs.getTitle().toString(),
width, height, format, flags);
// 又是一個 nativeCreate, 這次是經由 SurfaceComposerClient 產生一個 SurfaceControl 對象
=> mNativeObject = nativeCreate(session, name, w, h, format, flags);
=> sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
// 在 SurfaceComposerClient 的 createSurface 還會去申請 gbp (IGraphicBufferProducer)
=> sp<SurfaceControl> surface = client->createSurface(String8(name.c_str()), w, h, format, flags);
// 這裡的 mClient 是 SuffaceFlinger 的 Client 對象
=> mClient->createSurface(name, w, h, format, flags, &handle, &gbp);
=> sp<MessageBase> msg = new MessageCreateLayer(mFlinger.get(), name, this, w, h, format, flags, handle, gbp);
// 這裡會通過 SurfaceFlinger 的 mEventQueue 才會完成
/*
簡易流程大致如下:
1.) SurfaceFlinger Init 的時候, mEventQueue 開始等待 Message
=> PollOnce, 時間是無限長, 最後會停在 epoll_wait 等待事件
2.) 透過 mFlinger->postMessageSync(msg); 塞入 Message
3.) epoll_wait() return, 取得各個 Message (messageEnvelope = mMessageEnvelopes.itemAt(0);)
4.) 取出 Message 中的 handler 跟 message, 執行 handler->handleMessage(message);
在這個 case 中會先執行完 handler
virtual bool handler() {
result = flinger->createLayer(name, client, w, h, format, flags,
handle, gbp);
return true;
}
並且將 barrier unlock (open)
void MessageBase::handleMessage(const Message&) {
this->handler();
barrier.open();
};
*/
// createLayer
=> SurfaceFlinger::createNormalLayer
// 取得 handle 與 bufferProducer
=> *outLayer = new Layer(this, client, name, w, h, flags);
status_t err = (*outLayer)->setBuffers(w, h, format, flags);
if (err == NO_ERROR) {
*handle = (*outLayer)->getHandle();
*gbp = (*outLayer)->getProducer();
}
// 將 Layer 放置到 client 上
=> result = addClientLayer(client, *handle, *gbp, layer);
// ------------------------------------------------------------------ 建構出 SurfaceControl
// 接著呼叫 outSurface 也就是 Surface 對象的 copyFrom
=> outSurface.copyFrom(surfaceControl);
=> long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
// 取得 native 的 Surface 對象
=> sp<Surface> surface(ctrl->getSurface());
// 這裡的 mGraphicBufferProducer 就是前面帶進去的 gbp, 已經在 SurfaceFlinger 裡面創建了
// 它就是 mProducer = new MonitoredProducer(producer, mFlinger);
=> mSurfaceData = new Surface(mGraphicBufferProducer, false);\
// 將這個 native 的 Surface 對象保存起來
=> setNativeObjectLocked(newNativeObject); // mNativeObject = ptr;
**************************************************************************
// 待續...接下來是 performMeasure, performLayout, performDraw
2017年10月6日 星期五
2017年10月5日 星期四
C++ 語法小技巧 - array[0]
在看SurfaceFlinger的時候看到了一個奇妙的 array[0] 參數
標準C/C++中不支援長度為0的array,
但GNU C允許這種宣告方式, 目的是為了access不定長度的結構體時,
可以節省空間與便利性.
範例, 宣告一個 demo struct如下:
接著要在程式中使用這個 struct demo, 並在其後分配長度為LEN的char空間.
接著你就可以使用 demo->follow 來存取到這段空間.
另外一個作法是宣告為 char *follow, 但這樣在不定長度為 0 時則會多佔用一個 char 的 pointer.
標準C/C++中不支援長度為0的array,
但GNU C允許這種宣告方式, 目的是為了access不定長度的結構體時,
可以節省空間與便利性.
範例, 宣告一個 demo struct如下:
struct demo_t { int a; char b[256]; char follow[0]; };
接著要在程式中使用這個 struct demo, 並在其後分配長度為LEN的char空間.
struct demo_t *demo = (struct demo_t *) malloc (sizeof(strcut demo_t) + LEN);
接著你就可以使用 demo->follow 來存取到這段空間.
另外一個作法是宣告為 char *follow, 但這樣在不定長度為 0 時則會多佔用一個 char 的 pointer.
當然要記得把這個變數放在結構體的最後面 >.0
2017年8月21日 星期一
演算法筆記 - Robot路徑全展開
第一篇文章!
到大陸上班之後發現沒辦法存取大部份的網路資源....所以想找個地方來放自己的筆記.終極目標是希望在大陸工作的時候也可以輕易的存取,
不過看起來好像只有CSDN可以比較簡單做到....
就先放在Blogger暫存一下好了 XD
這是上禮拜跟Jay哥拿了一本演算法的題庫的其中一題:
[題目]
掃地機器人可以進行上下左右的任意移動, 每次移動一格, 且不能走到重複的格子
當移動 1 次的時候, 總共會有 4 種移動結果
( ↑ / ↓ / ← / → )
當移動 2 次的時候, 總共會有 12 種移動結果
(↑↑ / ↑← / ↑→ ) * 4
當移動 3 次的時候, 總共會有 36 種移動結果
{(↑↑↑ / ↑↑← / ↑↑→ ) + (↑←← / ↑←↑ / ↑←↓)
問題來了,
當移動了 13 次的時候, 總共會有幾種可能性?
[想法紀錄]
1.) 我可以固定起始方向, 之後將該計算結果*4就是答案
2.) 我需要記錄機器人走過的座標, 這樣才知道是否有走到重複的路徑上
3.) 或者....機器人的每一步都是自由的, 我應該讓他每一步都可以自由的進行上下左右移動,
再將不能移動到的位置幹掉.
羅列出來的想法大概就如上述這樣,
那麼接下來把需要的元素都展開來看看
[實作想法]
1.) 我需要紀錄座標, 那麼是不是需要一個二維Array?
2.) 我需要紀錄當前機器人所在的位置,
並且我想要初始化它的座標點到(0, 0)去, 那麼長寬最好是一個奇數.
3.) 我可能需要傳遞這個二維Array進去函數內進行運算,
而我們需要知道二維函數的傳遞形式並不是pointer to pointer:
int test[5][10];
void wrongFunc(int **array);
wrongFunc(&test[0]);
/* array 變數本身可以 decay 成記憶體起頭的位置,
所以你要描述的是一個 array 的 pointer, 長度為10,
並且這個 pointer 的 array 成員會再分別指向各自的一維 array
*/
所以你要描述的是一個 array 的 pointer, 長度為10,
並且這個 pointer 的 array 成員會再分別指向各自的一維 array
*/
rightFunc(test);
rightFunc(&test[0]); //這兩個敘述式等價
4.) 我可以先展開寬度, 或者先展開深度.
展開寬度一般是會搭配權重, 進行縮減 (像是 Beam Search 這種演算)
但由於要做的是全路徑展開, 所以我應該可以用遞迴搭配深度展開來完成
[開始實作]
我需要的元素有這些:
1.) 整個走過的點 (map[50][50])
2.) 目前的座標 (x, y)
3.) 目前的深度 (depth)
Pseudo code大概長這樣:
boolean freeRun( map, x, y, depth, target) { if (depth == target) { return true; } else { for (way = 0; way < 4; way++) { switch (way) { case 0: x++; break; ... case 3: y--; break; } depth++; if (map[x][y] == 1) {return false;} // hit end else { map[x][y] = 1; boolean result = freeRun(map, x, y, depth); if (result != true) { reset(map, x, y, depth); continue; } } } } // Should never come here return false; }
我要傳入陣列, 座標, 有時候還得Reset它們!?
是否有點太麻煩?
=> 使用Structure, 這樣我就不用管到底要怎麼傳陣列了 +_+
想複製, 那就直接傳Structure
想改值, 那就傳入&Structure
太美妙惹~~~
那麼就定義一個Structure吧~
#define COLUME_SIZE (50) #define ROW_SIZE (50) typedef struct Map { int pos[ROW_SIZE][COLUME_SIZE]; int x; int y; } Map;
把採點另外放到subFunction, 並加入debug log
void recordMap(Map *map) { int x = map->x; int y = map->y; map->pos[x][y] = 1; if (bDebug) printf("\t***record map[%d][%d] = %d\n", x-25, y-25, map->pos[x][y]); }
最後改寫freeRun函式跟main函式, 完成~
int finalCnt = 0; int bDebug = 0; int main(int argc, char** argv) { int steps = 0; cout << "Steps to go: "; cin >> steps; cout << "Calculating for " << steps << " steps." << endl; getSteps(steps); } int getSteps(int step) { Map map; memset(&map, 0, sizeof(map)); // Start from (25, 25) map.x = 25; map.y = 25; recordMap(&map); step--; // Running // - Consider only 1 ways when start running, then multiple as 4 will be the answer map.y++; recordMap(&map); step--; cout << "Ready to free run..." << endl; // - Free run freeRun(map, step); cout << "finalCnt = " << finalCnt*4 << endl; } void freeRun(Map map, int step) { int i = 0; // Backup the current step Map tempMap = map; if (bDebug) printf("+++========================================\n"); for (i = 0; i < 4; i++) { if (bDebug) printf("\nfreeRun - step %d at [%d][%d]\n", step, tempMap.x - 25, tempMap.y - 25); switch (i) { case 0: // x+ map.x++; break; case 1: // x- map.x--; break; case 2: // y+ map.y++; break; case 3: // y- map.y--; break; } if (bDebug) printf("\t (i: %d) [%d][%d] => [%d][%d]\n", i, tempMap.x-25, tempMap.y-25, map.x-25, map.y-25); step--; if (map.pos[map.x][map.y] == 1) { // Dead end, go next try if (bDebug) printf("\t\tDead end: map[%d][%d] is 1\n", map.x-25, map.y-25); } else { recordMap(&map); if (step == 0) { finalCnt++; if (bDebug) printf("Meet final count at map[%d][%d]...%d\n\n", map.x-25, map.y-25, finalCnt); // Dead end, go next try } else { // Deep first, go next layer freeRun(map, step); } } // Recover for this turn running; step++; map = tempMap; } if (bDebug) printf("===========================================\n"); }
訂閱:
文章 (Atom)
不定參數印 log
From the UNIXProcess_md.c #ifdef DEBUG_PROCESS /* Debugging process code is difficult; where to write debug output? */ static void deb...
-
作為一個 Native 的 Service, 想當然爾是在某個 main_xxx 帶起來的. 讓我們看看 init.rc, 果然找到了服務如下: service surfaceflinger / system / bin / surfaceflinger c...
-
前情提要 上一篇文章我們分析了 Layer class 裡面的 BufferQueue 相關構造, 但是還沒有看到 Layer 究竟會做哪些工作. Layer 生成了 mProducer 跟 mSurfaceFlingerConsumer, 因為 Layer 本身繼承...