2017年10月30日 星期一

公開金鑰加密簡述

常常會看到公開金鑰加密 (Public-key cryptography), 但是好像大家都寫得太複雜了 XD

看到 Public-key, 很自然的我們會想到那應該還有 Private-key 吧?
=> 是的沒錯, 公開金鑰加密的演算法中有一副成對的鑰匙, 公鑰(A)以及私鑰(B).
所以也稱作 非對稱式加密 (asymmetric cryptography) (鑰匙只有一把的狀況叫做對稱式)

它們的功能很簡單:

假設你現在有一份文件 X
Case. 1) 公鑰加密
  以公鑰加密文件得到 A(X)
  此時可以用私鑰解密得到 B(A(X)) = X
  但公鑰無法解密 A(A(X)) = ?_?

Case. 2) 私鑰加密
  以私鑰加密文件得到 B(X)
  此時可以用公鑰解密得到 A(B(X)) = X

看看 Case. 1 (公鑰加密) 的狀況:
  假設小明跟小花進行通訊
  小明把公鑰(A)給了小花, 小花用公鑰加密內容傳送回來給小明 A(X).
  => 因為私鑰(B)不會公開給別人, 所以別人傳送給小明的內容不會被解密.

再看看 Case. 2 (私鑰加密) 的狀況:
  小明現在用私鑰加密B(X)...結果發現:  咦? 怎麼大家都可以解開 @@!
  => 因為公鑰是公開的嘛, A(B(X)) = X
  所以私鑰不是這樣直接在通訊上面使用,
  而是小花用她自己的私鑰(D)來加密訊息, 然後再用小明的公鑰加密A(D(X))丟給小明.
  小明先用自己的私鑰(B)解開得到B(A(D(X))) = D(X)
  再用小花的公鑰(C)解開C(D(X)) = X

以上~

2017年10月19日 星期四

Android系統筆記 - EGL library 的接入口

對 Android 來說, 我們呼叫 eglXXX 的 API 時是呼叫到 libEGL 內部的實作

舉個 BootAnimation 的例子,  在創建 EGLSurface 會呼叫 eglCreateWindowSurface
frameworks/base/cmds/bootanimation/BootAnimation.cpp

status_t BootAnimation::readyToRun() {
    ...
    EGLSurface surface;
    surface = eglCreateWindowSurface(display, config, s.get(), NULL);
    ...
}

那我們可以看到 libEGL 最後又呼叫了 cnx->egl.eglCreateWindowSurface
frameworks/native/opengl/libs/EGL/eglApi.cpp


EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                    NativeWindowType window,
                                    const EGLint *attrib_list)
{
    ...
    EGLSurface surface = cnx->egl.eglCreateWindowSurface
}

那這個 cnx->egl 又是哪裡來的?
我們往前面看到開頭的地方呼叫的 validate_display_connection
EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
                                    NativeWindowType window,
                                    const EGLint *attrib_list)
{ egl_connection_t* cnx = NULL; const egl_display_ptr dp = validate_display_connection(dpy, cnx); ... }

跳轉進入 egl.cpp
frameworks/native/opengl/libs/EGL/egl.cpp

egl_display_ptr validate_display_connection(EGLDisplay dpy,
        egl_connection_t*& cnx) {
    cnx = NULL;
    egl_display_ptr dp = validate_display(dpy);
    if (!dp)
        return dp;
    cnx = &gEGLImpl;
    if (cnx->dso == 0) {
        return setError(EGL_BAD_CONFIG, egl_display_ptr(NULL));
    }
    return dp;
}

這邊把 cnx 指向了 gEGLImpl 的地址, 一般這種形式可以預期他指向一個 function pointer
搜尋一下, 可以發現到在 init 的時候確實做了這件事:
static EGLBoolean egl_init_drivers_locked() {
    if (sEarlyInitState) {
        // initialized by static ctor. should be set here.
        return EGL_FALSE;
    }

    // get our driver loader
    Loader& loader(Loader::getInstance());

    // dynamically load our EGL implementation
    egl_connection_t* cnx = &gEGLImpl;
    if (cnx->dso == 0) {
        cnx->hooks[egl_connection_t::GLESv1_INDEX] =
                &gHooks[egl_connection_t::GLESv1_INDEX];
        cnx->hooks[egl_connection_t::GLESv2_INDEX] =
                &gHooks[egl_connection_t::GLESv2_INDEX];
        cnx->dso = loader.open(cnx);
    }

    return cnx->dso ? EGL_TRUE : EGL_FALSE;
}

我們再看看 Loader::open 做了什麼
void* Loader::open(egl_connection_t* cnx)
{
    void* dso;
    driver_t* hnd = 0;

    dso = load_driver("GLES", cnx, EGL | GLESv1_CM | GLESv2);
    if (dso) {
        hnd = new driver_t(dso);
    } else {
        // Always load EGL first
        dso = load_driver("EGL", cnx, EGL);
        if (dso) {
            hnd = new driver_t(dso);
            hnd->set( load_driver("GLESv1_CM", cnx, GLESv1_CM), GLESv1_CM );
            hnd->set( load_driver("GLESv2",    cnx, GLESv2),    GLESv2 );
        }
    }
    ...
}

展開 load_driver...完畢!

void *Loader::load_driver(const char* kind,
        egl_connection_t* cnx, uint32_t mask)
{
    /* 定義了 MatchFile 的 class, 設定搜尋路徑是 /vendor/lib/egl 與 /system/lib/egl */
    ...

    // 假設已經找到了對應的 so
    void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
    if (mask & EGL) {
        /*
          比較麻煩的是這個 getProcAddress 也是從 dlsym 拿出來的...所以如果你都是 prebuilt library 就找不到實作
          不過我們可以隨便找一個實作來看, 都是大同小異的.
          簡單來說就是對照 name, 取出 API 的型態
        */
        getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");

        // 這裡取出了 cnx->egl 的地址, 並轉型為 __eglMustCastToProperFunctionPointerType (其實就是void)
        egl_t* egl = &cnx->egl;
        __eglMustCastToProperFunctionPointerType* curr =
            (__eglMustCastToProperFunctionPointerType*)egl;

        /* 這個 elg_names 的定義是從 egl_entries.in 來的, 放在 frameworks/native/opengl/libs/EGL/egl_entries.in
  char const * const egl_names[] = {
      #include "egl_entries.in"
      NULL    
  };
        */
        char const * const * api = egl_names;
        while (*api) {
            char const * name = *api;
            __eglMustCastToProperFunctionPointerType f =
                (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
            // 如果 dlsym 找不到才會嘗試去使用 getProcAddress 來做對照, 應該是為了擴充性的考量.
            if (f == NULL) {
                // couldn't find the entry-point, use eglGetProcAddress()
                f = getProcAddress(name);
                if (f == NULL) {
                    f = (__eglMustCastToProperFunctionPointerType)0;
                }
            }
            // 把 function pointer 一個一個 mapping... 完畢
            *curr++ = f;
            api++;
        }
    }
    ...
}

另外, 由於你的 library 可能都是 vendor 封裝好的, 所以要看 EGL 的行為的話,
可以參考 Google 為了 Emulator 所寫的 Software OpenGL ES library
檔案放在這裡: frameworks/native/opengl/libagl/egl.cpp

2017年10月11日 星期三

Android系統筆記 - Surface simple flow (2) Surface Flinger 的創建

作為一個 Native 的 Service, 想當然爾是在某個 main_xxx 帶起來的.
讓我們看看 init.rc, 果然找到了服務如下:


service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc
    onrestart restart zygote

surfaceflinger 的 Makefile 放在 frameworks/native/services/surfaceflinger 下面
=> main_surfaceflinger.cpp

int main(int, char**) {
    ...
    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();

    // initialize before clients can connect
    flinger->init();

    // publish surface flinger
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
    ...

    // run in this thread
    flinger->run();
}

1.) new SurfaceFlinger();
=> 建構子讀了一些 property 並設置對應的 debug 訊息, 暫時跳過.
     這邊可以看到它繼承了 BnSurfaceComposer

SurfaceFlinger::SurfaceFlinger()
    :   BnSurfaceComposer(), xxx

=> 第一次建立 SurfaceFlinger 時, 呼叫 MessageQueue 的 init
void SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this);
}

=> 這裡保存了 mFlinger, 並生出 Looper & Handler
void MessageQueue::init(const sp<SurfaceFlinger>& flinger)  
{  
    mFlinger = flinger;  
    mLooper = new Looper(true);  
    mHandler = new Handler(*this);  
}

# mHandler 是定義在 MessageQueue 裡面的 subClass,
  它繼承了 MessageHandler, 並在 mQueue 保存了自己這個 MessageQueue

    class Handler : public MessageHandler {
 enum {
     eventMaskInvalidate     = 0x1,
     eventMaskRefresh        = 0x2,
     eventMaskTransaction    = 0x4
 };
 MessageQueue& mQueue;
 int32_t mEventMask;
    public:
 Handler(MessageQueue& queue) : mQueue(queue), mEventMask(0) { }
 virtual void handleMessage(const Message& message);
 void dispatchRefresh();
 void dispatchInvalidate();
 void dispatchTransaction();
    };

2.) flinger->init();

這邊先貼上完整的代碼, 下面一步一步分析

void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");

    Mutex::Autolock _l(mStateLock);

    // initialize EGL for the default display
    // EGL 是 OpenGL ES 的接點, 主要功能是完成 OpenGL 創建 Context, 繪製Surface, 配置Framebuffer属性、Swap提交繪製結果
    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(mEGLDisplay, NULL, NULL);

    // start the EventThread
    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            vsyncPhaseOffsetNs, true, "app");
    mEventThread = new EventThread(vsyncSrc);
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, true, "sf");
    mSFEventThread = new EventThread(sfVsyncSrc);
    mEventQueue.setEventThread(mSFEventThread);

    // Initialize the H/W composer object.  There may or may not be an
    // actual hardware composer underneath.
    mHwc = new HWComposer(this,
            *static_cast<HWComposer::EventHandler *>(this));

    // get a RenderEngine for the given display / config (can't fail)
    mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID());

    // retrieve the EGL context that was selected/created
    mEGLContext = mRenderEngine->getEGLContext();

    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
            "couldn't create EGLContext");

    // initialize our non-virtual displays
    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
        // set-up the displays that are already connected
        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
            // All non-virtual displays are currently considered secure.
            bool isSecure = true;
            createBuiltinDisplayLocked(type);
            wp<IBinder> token = mBuiltinDisplays[i];

            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            BufferQueue::createBufferQueue(&producer, &consumer,
                    new GraphicBufferAlloc());
            // 為什麼這裡要自己 new GraphicBufferAlloc() 而不是跟 Layer 一樣只有呼叫 producer & consumer ?

            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
                    consumer);
            int32_t hwcId = allocateHwcDisplayId(type);
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                    fbs, producer,
                    mRenderEngine->getEGLConfig());
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                // FIXME: currently we don't get blank/unblank requests
                // for displays other than the main display, so we always
                // assume a connected display is unblanked.
                ALOGD("marking display %zu as acquired/unblanked", i);
                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
            }
            mDisplays.add(token, hw);
        }
    }

    // make the GLContext current so that we can create textures when creating Layers
    // (which may happens before we render something)
    getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext);

    mEventControlThread = new EventControlThread(this);
    mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);

    // set a fake vsync period if there is no HWComposer
    if (mHwc->initCheck() != NO_ERROR) {
        mPrimaryDispSync.setPeriod(16666667);
    }

    // initialize our drawing state
    mDrawingState = mCurrentState;

    // set initial conditions (e.g. unblank default device)
    initializeDisplays();

    // start boot animation
    startBootAnim();
}

=> 先跳過EGL, 來看 DispSyncSource,
     它繼承了 VSyncSource 跟 DispSync::Callback, 並傳入了 mPrimaryDispSync 的 address.
     這個 mPrimaryDispSync 的類型是 DispSync, 它會啟動一個 DispSyncThread
DispSync::DispSync() :
 mRefreshSkipCount(0),
 mThread(new DispSyncThread()) {
    
    mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
  
    reset();
    beginResync();
}

=> 這個 threadLoop 會進行計時, 並在計時結束時,
             把所有需要觸發 callback 的 listener 蒐集到 callbackInvocations 裡面一起觸發
        while (true) {
            Vector<CallbackInvocation> callbackInvocations;

            nsecs_t targetTime = 0;

     // Scope for lock
            {
                if (mPeriod == 0) {
                    err = mCond.wait(mMutex);
                    continue;
                }

                nextEventTime = computeNextEventTimeLocked(now);
                targetTime = nextEventTime;

                bool isWakeup = false;

                if (now < targetTime) {
                    err = mCond.waitRelative(mMutex, targetTime - now);

                    if (err == TIMED_OUT) {
                        isWakeup = true;
                    }
                }
                now = systemTime(SYSTEM_TIME_MONOTONIC);

                if (isWakeup) {
                    mWakeupLatency = ((mWakeupLatency * 63) +
                            (now - targetTime)) / 64;
                    if (mWakeupLatency > 500000) {
                        // Don't correct by more than 500 us
                        mWakeupLatency = 500000;
                    }
                }

                callbackInvocations = gatherCallbackInvocationsLocked(now);
            }

            if (callbackInvocations.size() > 0) {
                fireCallbackInvocations(callbackInvocations);
            }
        }

=> 觸發就是呼叫 onDispSyncEvent
void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
   for (size_t i = 0; i < callbacks.size(); i++) {
       callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
   }
}

=> 回到一開始 DispSyncSource 繼承的 DispSync::Callback 如下, 需要 implement onDispSyncEvent
class Callback: public virtual RefBase {
public:
    virtual ~Callback() {};
    virtual void onDispSyncEvent(nsecs_t when) = 0;
};

=> 可以看到在內部的實作如下
class DispSyncSource : public VSyncSource, private DispSync::Callback {
private:
    virtual void onDispSyncEvent(nsecs_t when) {
        sp<VSyncSource::Callback> callback;
        {
            Mutex::Autolock lock(mCallbackMutex);
            callback = mCallback;
            if (mTraceVsync) {
                mValue = (mValue + 1) % 2;
                ATRACE_INT(mVsyncEventLabel.string(), mValue);
            }
        }
        if (callback != NULL) {
            callback->onVSyncEvent(when);
        }
    }
}

=> 那麼 mCallback 又是從哪來的?
=> 答案是透過 setCallback 來的,
                   下一行的 mEventThread = new EventThread(vsyncSrc);
  透過它的 EventThread::enableVSyncLocked function 來呼叫,
   他的 Callback class 如下:
class Callback: public virtual RefBase {
    public:
        virtual ~Callback() {}
        virtual void onVSyncEvent(nsecs_t when) = 0;
};

=> 而實作的形式為
void EventThread::onVSyncEvent(nsecs_t timestamp) {
    Mutex::Autolock _l(mLock);
    mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
    mVSyncEvent[0].header.id = 0;
    mVSyncEvent[0].header.timestamp = timestamp;
    mVSyncEvent[0].vsync.count++;
    mCondition.broadcast();
}
所以當一個 DispSync 的 Event 來時, 會透過 onDispSyncEvent => onVSyncEvent

=> 下一行的 mSFEventThread 也做了差不多的事情,
   只是這邊多呼叫了 mEventQueue.setEventThread(mSFEventThread),
   將 mSFEventThread 保存到 MessageQueue 裡面的 mEventThread 變量
   (這邊看不出來要幹嘛...好像沒用到?)

=> 再來生成了一個 HW Composer
    mHwc = new HWComposer(this,
            *static_cast<HWComposer::EventHandler *>(this));

=> 這裡會跟 VSync 掛勾 (mCBContext->procs.vsync = &hook_vsync,
              把Callback function註冊給HWC)

HWComposer::HWComposer(const sp<SurfaceFlinger>& flinger, EventHandler& handler)
{
    ...
    // Note: some devices may insist that the FB HAL be opened before HWC.
    int fberr = loadFbHalModule();
    loadHwcModule();
    if (mHwc) {
        ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
           (hwcApiVersion(mHwc) >> 24) & 0xff,
           (hwcApiVersion(mHwc) >> 16) & 0xff);
        if (mHwc->registerProcs) {
             mCBContext->hwc = this;
             mCBContext->procs.invalidate = &hook_invalidate;
             mCBContext->procs.vsync = &hook_vsync;
             if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
                 mCBContext->procs.hotplug = &hook_hotplug;
             else
                 mCBContext->procs.hotplug = NULL;
             memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
             mHwc->registerProcs(mHwc, &mCBContext->procs);
        }

        // don't need a vsync thread if we have a hardware composer
        needVSyncThread = false;
        // always turn vsync off when we start
        eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
        // the number of displays we actually have depends on the
        // hw composer version
        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
            // 1.3 adds support for virtual displays
            mNumDisplays = MAX_HWC_DISPLAYS;
        }
    }
}

=> 呼叫 RenderEngine::create(), 將 EGLDisplay 與 hwc format 放入

 RenderEngine* RenderEngine::create(EGLDisplay display, int hwcFormat) {
     RenderEngine* engine = NULL;
     switch (version) {
        engine = new GLESXXRenderEngine();
     }
     engine->setEGLHandles(config, ctxt);

     return engine;
 }

=> 對所有 non-virtual diplay 進行初始化

    // initialize our non-virtual displays
    for (size_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
        DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);

        // set-up the displays that are already connected
        if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
            // All non-virtual displays are currently considered secure.
            bool isSecure = true;
            createBuiltinDisplayLocked(type);
            wp<IBinder> token = mBuiltinDisplays[i];

            sp<IGraphicBufferProducer> producer;
            sp<IGraphicBufferConsumer> consumer;
            BufferQueue::createBufferQueue(&producer, &consumer,
                    new GraphicBufferAlloc());
            /* 不曉得為什麼這裡要自己 new GraphicBufferAlloc(),
               而不是跟 Layer 一樣只有呼叫 producer & consumer ? */

            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
                    consumer);
            int32_t hwcId = allocateHwcDisplayId(type);
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
                    fbs, producer,
                    mRenderEngine->getEGLConfig());
            if (i > DisplayDevice::DISPLAY_PRIMARY) {
                // FIXME: currently we don't get blank/unblank requests
                // for displays other than the main display, so we always
                // assume a connected display is unblanked.
                ALOGD("marking display %zu as acquired/unblanked", i);
                hw->setPowerMode(HWC_POWER_MODE_NORMAL);
            }
            mDisplays.add(token, hw);
        }
    }

=> createBufferQueue 之前會先 new 一個 allocator 出來 (new GraphicBufferAlloc())
           不過在 createBufferQueue 內部也會檢查 allocator 是否為 NULL ... 然後最終還是會呼叫到 new GraphicBufferAlloc()

=> 之後在 BufferQueueProducer 呼叫 dequeueBuffer / allocateBuffers 時會透過這個 allocator 生成 GraphicBuffer
  透過 GraphicBuffer 與 GraphicBufferAlloctor 也就是 gralloc module 進行交互 (注意是 GraphicBufferAlloctor 而不是 GraphicBufferAlloc ...)
                   主要是透過 gralloc module 去進行緩衝區的分配 (Either on RAM or Framebuffer)

=> createBufferQueue 對 producer 跟 consumer 進行了配置, 分別對應到 BufferQueueProducer 跟 BufferQueueConsumer
  他們藉由 BufferQueueCore(allocator) 進行交互. (另外雖然 allocator 也帶入了 core, 但好像沒有拿來用)

=> 接下來生成一個 FramebufferSurface, 並帶入了 HWComposer 與剛剛生成的 consumer
=> consumer 作為 FramebufferSurface 繼承的父類別的 ConsumerBase 內部的 mConsumer 對象被保存起來
  hwc 則保存在 mHwc 對象中, 稍微爬了一下代碼, 裡面會呼叫 Hwc 對於 fence 的操作等功能

=> 後面在 BufferQueueProducer 的內部, 我們會看到它取出了 frameAvailableListener = mCore->mConsumerListener;
  並去呼叫 frameAvailableListener->onFrameAvailable(item);
  mCore->mConsumerListener = consumerListener; 則是在 BufferQueueConsumer::connect() 賦值的, 這個我們後面會再看到.

=> 再來, 生成 DisplayDevice, 這裡將 producer 帶入

  DisplayDevice::DisplayDevice()
  {
      mNativeWindow = new Surface(producer, false);
      ANativeWindow* const window = mNativeWindow.get();

      /*
       * Create our display's surface
       */

      EGLSurface surface;
      EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      if (config == EGL_NO_CONFIG) {
   config = RenderEngine::chooseEglConfig(display, format);
      }
      surface = eglCreateWindowSurface(display, config, window, NULL);

      ...

      if (mType >= DisplayDevice::DISPLAY_VIRTUAL) {
   // reset virtual display buffer format.
   // because it is changed by eglCreateWindowSurface().
   native_window_set_buffers_format(window, format);
   window->setSwapInterval(window, 0);
      }
  }


=> 可以看到這邊又生成了一個 Surface 對象,
     把 producer 帶入, 保存在 mGraphicBufferProducer 內

   Surface::Surface(
    const sp<IGraphicBufferProducer>& bufferProducer,
    bool controlledByApp)
       : mGraphicBufferProducer(bufferProducer),
         mGenerationNumber(0)
   {
       // Initialize the ANativeWindow function pointers.
       ANativeWindow::setSwapInterval  = hook_setSwapInterval;
       ANativeWindow::dequeueBuffer    = hook_dequeueBuffer;
       ANativeWindow::cancelBuffer     = hook_cancelBuffer;
       ...
   }
=> 之後會透過 Surface 對象來呼叫 BufferQueueProducer 的 allocateBuffers / dequeueBuffer 等動作

=> 取得剛剛設定好的 Surface 對象, 在 Constructor 裡面已經完成了一些指定 ANativeWindow* const window = mNativeWindow.get();
  生成 EGL 用的 surface, display 等對象

      /*
       * Create our display's surface
       */
      EGLSurface surface;
      EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      if (config == EGL_NO_CONFIG) {
   config = RenderEngine::chooseEglConfig(display, format);
      }
      surface = eglCreateWindowSurface(display, config, window, NULL);

      mSurface = surface;
      mDisplay = display;

=> 先總結一下, 現在的 producer 藉由 DisplayDevice 的 mNativeWindow 傳遞給了 EGL
  而 consumer 則是給了 FramebufferSurface, 等收到了 onFrameAvailable 之後, 就會呼叫 HWComposer 的 fbPost 函數開始輸出

void FramebufferSurface::onFrameAvailable(const BufferItem& /* item */) {  
    sp<GraphicBuffer> buf;  
    sp<Fence> acquireFence;  
    status_t err = nextBuffer(buf, acquireFence);  
    if (err != NO_ERROR) {  
        ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",  
            strerror(-err), err);  
        return;  
    }  
    err = mHwc.fbPost(mDisplayType, acquireFence, buf);  
    if (err != NO_ERROR) {  
        ALOGE("error posting framebuffer: %d", err);  
    }
}

=> 啟動 EventControlThread, 並呼叫一次 eventControl (一開始 mVsyncEnabled 是 false)
    mFlinger->eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC,
            mVsyncEnabled);

=> 這個 eventControl 最終會呼叫到 HWComposer 的 HAL 的 eventControl, 以 mx6 為例,
  它會呼叫 hwc_eventControl, 並設定 VSyncThread 的 mEnabled 值
ctx->m_vsync_thread->setEnabled(enabled);

=> mEnabled = false 的時候會讓 threadLoop 卡在這邊等 mCondition


bool VSyncThread::threadLoop()
{
    { // scope for lock
        Mutex::Autolock _l(mLock);
        while (!mEnabled) {
            mCondition.wait(mLock);
        }
    }
    if (mFakeVSync) {
        performFakeVSync();
    }
    else {
        performVSync();
    }
    return true;
}


=> 呼叫 initializeDisplays(); 送出一個 Async 的 command (MessageScreenInitialized)
=> 前面追過了, 收到之後會執行 handler, 所以會呼叫 onInitializeDisplays

=> SurfaceFlinger 啟動完成, 呼叫 property_set 來啟動 bootAnimation

2017年10月6日 星期五

Android系統筆記 - Surface simple flow (1)

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月5日 星期四

C++ 語法小技巧 - array[0]

在看SurfaceFlinger的時候看到了一個奇妙的 array[0] 參數

標準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

不定參數印 log

From the UNIXProcess_md.c #ifdef DEBUG_PROCESS   /* Debugging process code is difficult; where to write debug output? */ static void deb...