Android에서 VSync 동작 원리 및 초기화 과정(1)

안드로이드/프레임워크 2015. 8. 29. 18:51


 안드로이드 기반 디바이스에서 화면의 출력되는 정보가 변경될 경우 이를 지속적으로 갱신해 줄 필요가 있습니다. 안드로이드에서 이 기능을 수행하는 것으로 VSync가 있습니다. VSync란 안드로이드 기기에 표출되는 화면의 정보가 변경되었을 때 이를 호출하는 신호로 이는 Choreographer 클래스에서 정의하고 있습니다. 자세한 설명은 아래 그림을 통해 해 보도록 하겠습니다.


 VSync는 주기적으로 신호를 발생하여 디스플레이의 화면을 갱신시키는 함수를 호출합니다. 하드웨어의 설정대로 VSync의 발생 주기는 60Hz입니다. VSync는 HWComposer에서 설정되며 설정 과정을 소스코드를 통해 분석해 보도록 합니다. HWComposer는 SurfaceFlinger가 초기화될 때 동시에 진행됩니다. SurfaceFlinger가 생성되는 과정에 대해서는 아래 링크를 참조해 주시기 바랍니다.


http://elecs.tistory.com/131


/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
....
 
void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");
 
    status_t err;
    Mutex::Autolock _l(mStateLock);
 
....
 
    // 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));
 
    // First try to get an ES2 config
    err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES2_BIT,
            &mEGLConfig);
 
    if (err != NO_ERROR) {
        // If ES2 fails, try ES1
        err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(),
                EGL_OPENGL_ES_BIT, &mEGLConfig);
    }
 
    if (err != NO_ERROR) {
        // still didn't work, probably because we're on the emulator...
        // try a simplified query
        ALOGW("no suitable EGLConfig found, trying a simpler query");
        err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), 0, &mEGLConfig);
    }
 
    if (err != NO_ERROR) {
        // this EGL is too lame for android
        LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
    }
 
....
 
    // 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<BufferQueue> bq = new BufferQueue(new GraphicBufferAlloc());
            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, bq);
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, allocateHwcDisplayId(type), isSecure, token,
                    fbs, bq,
                    mEGLConfig);
            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 %d as acquired/unblanked", i);
                hw->acquireScreen();
            }
            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);
 
    // start the EventThread
    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            vsyncPhaseOffsetNs, true);
    mEventThread = new EventThread(vsyncSrc);
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, false);
    mSFEventThread = new EventThread(sfVsyncSrc);
    mEventQueue.setEventThread(mSFEventThread);
 
    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();
}
 
....
cs


 위의 소스코드에서 보시는 바와 같이 HWComposer가 새롭게 생성되고 있는 것을 확인하실 수 있습니다. 이번에는 HWCompose가 생성되는 과정을 보도록 하겠습니다.


/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class HWComposer
{
....
    sp<SurfaceFlinger>              mFlinger;
    framebuffer_device_t*           mFbDev;
    struct hwc_composer_device_1*   mHwc;
    // invariant: mLists[0] != NULL iff mHwc != NULL
    // mLists[i>0] can be NULL. that display is to be ignored
    struct hwc_display_contents_1*  mLists[MAX_HWC_DISPLAYS];
    DisplayData                     mDisplayData[MAX_HWC_DISPLAYS];
    size_t                          mNumDisplays;
 
    cb_context*                     mCBContext;
    EventHandler&                   mEventHandler;
    size_t                          mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
    sp<VSyncThread>                 mVSyncThread;
    bool                            mDebugForceFakeVSync;
    BitSet32                        mAllocatedDisplayIDs;
....
}
cs


/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
....
 
HWComposer::HWComposer(
        const sp<SurfaceFlinger>& flinger,
        EventHandler& handler)
    : mFlinger(flinger),
      mFbDev(0), mHwc(0), mNumDisplays(1),
      mCBContext(new cb_context),
      mEventHandler(handler),
      mDebugForceFakeVSync(false)
{
 
....
 
    // Note: some devices may insist that the FB HAL be opened before HWC.
    int fberr = loadFbHalModule();
    loadHwcModule();
 
    if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
        // close FB HAL if we don't needed it.
        // FIXME: this is temporary until we're not forced to open FB HAL
        // before HWC.
        framebuffer_close(mFbDev);
        mFbDev = NULL;
    }
 
    // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
    if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
            && !mFbDev) {
        ALOGE("ERROR: failed to open framebuffer (%s), aborting",
                strerror(-fberr));
        abort();
    }
 
    // these display IDs are always reserved
    for (size_t i=0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
        mAllocatedDisplayIDs.markBit(i);
    }
 
    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, 0sizeof(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;
        } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
            // 1.1 adds support for multiple displays
            mNumDisplays = NUM_BUILTIN_DISPLAYS;
        } else {
            mNumDisplays = 1;
        }
    }
 
    if (mFbDev) {
        ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
                "should only have fbdev if no hwc or hwc is 1.0");
 
        DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
        disp.connected = true;
        disp.width = mFbDev->width;
        disp.height = mFbDev->height;
        disp.format = mFbDev->format;
        disp.xdpi = mFbDev->xdpi;
        disp.ydpi = mFbDev->ydpi;
        if (disp.refresh == 0) {
            disp.refresh = nsecs_t(1e9 / mFbDev->fps);
            ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
        }
        if (disp.refresh == 0) {
            disp.refresh = nsecs_t(1e9 / 60.0);
            ALOGW("getting VSYNC period from thin air: %lld",
                    mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
        }
    } else if (mHwc) {
        // here we're guaranteed to have at least HWC 1.1
        for (size_t i =0 ; i<NUM_BUILTIN_DISPLAYS ; i++) {
            queryDisplayProperties(i);
        }
    }
 
    if (needVSyncThread) {
        // we don't have VSYNC support, we need to fake it
        mVSyncThread = new VSyncThread(*this);
    }
}
 
....
cs

 HWComposer가 생성될 때 실행되는 loadHwcModule() 함수를 살펴보도록 합니다. 먼저 해당 함수를 이해하기 위해 해당 함수에서 사용하는 헤더파일의 내용 중 일부를 살펴보겠습니다.


/hardware/libhardware/include/hardware/hardware.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
....
 
/**
 * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;
 
    /**
     * The API version of the implemented module. The module owner is
     * responsible for updating the version when a module interface has
     * changed.
     *
     * The derived modules such as gralloc and audio own and manage this field.
     * The module user must interpret the version field to decide whether or
     * not to inter-operate with the supplied module implementation.
     * For example, SurfaceFlinger is responsible for making sure that
     * it knows how to manage different versions of the gralloc-module API,
     * and AudioFlinger must know how to do the same for audio-module API.
     *
     * The module API version should include a major and a minor component.
     * For example, version 1.0 could be represented as 0x0100. This format
     * implies that versions 0x0100-0x01ff are all API-compatible.
     *
     * In the future, libhardware will expose a hw_get_module_version()
     * (or equivalent) function that will take minimum/maximum supported
     * versions as arguments and would be able to reject modules with
     * versions outside of the supplied range.
     */
    uint16_t module_api_version;
#define version_major module_api_version
    /**
     * version_major/version_minor defines are supplied here for temporary
     * source code compatibility. They will be removed in the next version.
     * ALL clients must convert to the new version format.
     */
 
    /**
     * The API version of the HAL module interface. This is meant to
     * version the hw_module_t, hw_module_methods_t, and hw_device_t
     * structures and definitions.
     *
     * The HAL interface owns this field. Module users/implementations
     * must NOT rely on this value for version information.
     *
     * Presently, 0 is the only valid value.
     */
    uint16_t hal_api_version;
#define version_minor hal_api_version
 
    /** Identifier of module */
    const char *id;
 
    /** Name of this module */
    const char *name;
 
    /** Author/owner/implementor of the module */
    const char *author;
 
    /** Modules methods */
    struct hw_module_methods_t* methods;
 
    /** module's dso */
    void* dso;
 
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
 
} hw_module_t;
 
 
typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);
 
hw_module_methods_t;
 
/**
 * Every device data structure must begin with hw_device_t
 * followed by module specific public methods and attributes.
 */
typedef struct hw_device_t {
    /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t tag;
 
    /**
     * Version of the module-specific device API. This value is used by
     * the derived-module user to manage different device implementations.
     *
     * The module user is responsible for checking the module_api_version
     * and device version fields to ensure that the user is capable of
     * communicating with the specific module implementation.
     *
     * One module can support multiple devices with different versions. This
     * can be useful when a device interface changes in an incompatible way
     * but it is still necessary to support older implementations at the same
     * time. One such example is the Camera 2.0 API.
     *
     * This field is interpreted by the module user and is ignored by the
     * HAL interface itself.
     */
    uint32_t version;
 
    /** reference to the module this device belongs to */
    struct hw_module_t* module;
 
    /** padding reserved for future use */
    uint32_t reserved[12];
 
    /** Close this device */
    int (*close)(struct hw_device_t* device);
 
} hw_device_t;
 
....
cs


/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
....
 
// Load and prepare the hardware composer module.  Sets mHwc.
void HWComposer::loadHwcModule()
{
    hw_module_t const* module;
    //Hardware로부터 module을 받아옵니다.
    if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
        ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
        return;
    }
    //위의 과정으로 부터 얻어온 module을 통해 HWComposer에 적용합니다.
    int err = hwc_open_1(module, &mHwc);
    if (err) {
        ALOGE("%s device failed to initialize (%s)",
              HWC_HARDWARE_COMPOSER, strerror(-err));
        return;
    }
    if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
            hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
            hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
        ALOGE("%s device version %#x unsupported, will not be used",
              HWC_HARDWARE_COMPOSER, mHwc->common.version);
        hwc_close_1(mHwc);
        mHwc = NULL;
        return;
    }
}
 
....
cs

 hw_get_module을 통해 하드웨어의 모듈 정보를 받아옵니다. hw_get_module의 함수는 아래와 같이 구성되어 있습니다.


/hardware/libhardware/hardware.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
....
 
int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int status;
    int i;
    const struct hw_module_t *hmi = NULL;
    char prop[PATH_MAX];
    char path[PATH_MAX];
    char name[PATH_MAX];
 
    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);
 
    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */
 
    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
        if (i < HAL_VARIANT_KEYS_COUNT) {
            if (property_get(variant_keys[i], prop, NULL) == 0) {
                continue;
            }
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH2, name, prop);
            if (access(path, R_OK) == 0break;
 
            snprintf(path, sizeof(path), "%s/%s.%s.so",
                     HAL_LIBRARY_PATH1, name, prop);
            if (access(path, R_OK) == 0break;
        } else {
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH2, name);
            if (access(path, R_OK) == 0break;
 
            snprintf(path, sizeof(path), "%s/%s.default.so",
                     HAL_LIBRARY_PATH1, name);
            if (access(path, R_OK) == 0break;
        }
    }
 
    status = -ENOENT;
    if (i < HAL_VARIANT_KEYS_COUNT+1) {
        /* load the module, if this fails, we're doomed, and we should not try
         * to load a different variant. */
        status = load(class_id, path, module);
    }
 
    return status;
}
 
int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}
cs


 hw_get_modlue() 함수는 이어서 hw_get_module_by_class()함수를 호출하게 되며 load()함수가 호출되면서 module 변수의 값을 설정하게 됩니다.


/hardware/libhardware/hardware.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
 * Load the file defined by the variant and if successful
 * return the dlopen handle and the hmi.
 * @return 0 = success, !0 = failure.
 */
static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status;
    void *handle;
    struct hw_module_t *hmi;
 
    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    handle = dlopen(path, RTLD_NOW);
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }
 
    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }
 
    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }
 
    hmi->dso = handle;
 
    /* success */
    status = 0;
 
    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, *pHmi, handle);
    }
 
    *pHmi = hmi;
 
    return status;
}
cs


위 과정을 통해 pHmi가 설정되는 것을 보실 수 있습니다.이 때 dlsym()함수는 동적 적제 라이브러리로 해당 기기의 Library와 연결되게 됩니다.


 다음으로 hwc_open_1() 함수와 hwc_close_1() 함수를 살펴보도록 하겠습니다.


/hardware/libhardware/include/hardware/hwcomposer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
....
/** convenience API for opening and closing a device */
 
static inline int hwc_open_1(const struct hw_module_t* module,
        hwc_composer_device_1_t** device) {
    return module->methods->open(module,
            HWC_HARDWARE_COMPOSER, (struct hw_device_t**)device);
}
 
static inline int hwc_close_1(hwc_composer_device_1_t* device) {
    return device->common.close(&device->common);
}
....
cs


 hwc_open_1() 함수는 위의 과정에서 동적 라이브러리와 연결되어 있는 method 내의 open()함수를 통해 hwc_device_open()함수를 호출하게 됩니다.


/hardware/qcom/display/msm8960/libhwcomposer/hwc.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
static int hwc_device_open(const struct hw_module_t* module, const char* name,
                           struct hw_device_t** device)
{
    int status = -EINVAL;
 
    if (!strcmp(name, HWC_HARDWARE_COMPOSER)) {
        struct hwc_context_t *dev;
        dev = (hwc_context_t*)malloc(sizeof(*dev));
        memset(dev, 0sizeof(*dev));
 
        //Initialize hwc context
        initContext(dev);
 
        //Setup HWC methods
        dev->device.common.tag          = HARDWARE_DEVICE_TAG;
        dev->device.common.version      = HWC_DEVICE_API_VERSION_1_2;
        dev->device.common.module       = const_cast<hw_module_t*>(module);
        dev->device.common.close        = hwc_device_close;
        dev->device.prepare             = hwc_prepare;
        dev->device.set                 = hwc_set;
        dev->device.eventControl        = hwc_eventControl;
        dev->device.blank               = hwc_blank;
        dev->device.query               = hwc_query;
        dev->device.registerProcs       = hwc_registerProcs;
        dev->device.dump                = hwc_dump;
        dev->device.getDisplayConfigs   = hwc_getDisplayConfigs;
        dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
        *device = &dev->device.common;
        status = 0;
    }
    return status;
}
cs


 위의 과정을 mhwc이 모두 정의되면 되면 다음으로 callback으로  각 함수들이 적용됩니다.


/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
....
 
struct HWComposer::cb_context {
    struct callbacks : public hwc_procs_t {
        // these are here to facilitate the transition when adding
        // new callbacks (an implementation can check for NULL before
        // calling a new callback).
        void (*zero[4])(void);
    };
    callbacks procs;
    HWComposer* hwc;
};
 
....
 
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, 0sizeof(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;
        } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
            // 1.1 adds support for multiple displays
            mNumDisplays = NUM_BUILTIN_DISPLAYS;
        } else {
            mNumDisplays = 1;
        }
    }
 
....
cs

 위에서 보시는 바와 같이 Callback 함수로 vsync 함수가 등록되어 지는 것을 확인하실 수 있습니다. 설정이 완료된 후 registerProcs()함수가 실행되여 Callback 함수를 등록하게 됩니다. 이는 이전에 hwc_device_open()함수에서 등록되어 있는 것이 실행됩니다.


/hardware/qcom/display/msm8960/libhwcomposer/hwc.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * Save callback functions registered to HWC
 */
static void hwc_registerProcs(struct hwc_composer_device_1* dev,
                              hwc_procs_t const* procs)
{
    ALOGI("%s", __FUNCTION__);
    hwc_context_t* ctx = (hwc_context_t*)(dev);
    if(!ctx) {
        ALOGE("%s: Invalid context", __FUNCTION__);
        return;
    }
    ctx->proc = procs;
 
    // Now that we have the functions needed, kick off
    // the uevent & vsync threads
    init_uevent_thread(ctx);
    init_vsync_thread(ctx);
}
cs


 위 hwc_registerProcs() 함수가 호출되면서 init_vsync_thread()를 호출함으로서 vsync thread가 만들어집니다.


/hardware/qcom/display/msm8960/libhwcomposer/hwc_vsync.cpp

1
2
3
4
5
6
7
8
9
10
11
void init_vsync_thread(hwc_context_t* ctx)
{
    int ret;
    pthread_t vsync_thread;
    ALOGI("Initializing VSYNC Thread");
    ret = pthread_create(&vsync_thread, NULL, vsync_loop, (void*) ctx);
    if (ret) {
        ALOGE("%s: failed to create %s: %s", __FUNCTION__,
              HWC_VSYNC_THREAD_NAME, strerror(ret));
    }
}
cs


 위의 과정을 통해 VSync를 담당하는 thread가 생성되었음을 확인하였습니다. 여기서 VSync Thread의 소스코드를 확인해 보는 것으로 이번 포스팅을 마치도록 하겠습니다. 다음 포스팅에서 계속 이어서 소스코드 설명을 진행하도록 하겠습니다.



/hardware/qcom/display/msm8960/libhwcomposer/hwc_vsync.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
static void *vsync_loop(void *param)
{
    const char* vsync_timestamp_fb0 = "/sys/class/graphics/fb0/vsync_event";
    const char* vsync_timestamp_fb1 = "/sys/class/graphics/fb1/vsync_event";
    int dpy = HWC_DISPLAY_PRIMARY;
 
    hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
 
    char thread_name[64= HWC_VSYNC_THREAD_NAME;
    prctl(PR_SET_NAME, (unsigned long) &thread_name, 000);
    setpriority(PRIO_PROCESS, 0, HAL_PRIORITY_URGENT_DISPLAY +
                android::PRIORITY_MORE_FAVORABLE);
 
    const int MAX_DATA = 64;
    static char vdata[MAX_DATA];
 
    uint64_t cur_timestamp=0;
    ssize_t len = -1;
    int fd_timestamp = -1;
    int ret = 0;
    bool fb1_vsync = false;
    bool logvsync = false;
 
    char property[PROPERTY_VALUE_MAX];
    if(property_get("debug.hwc.fakevsync", property, NULL) > 0) {
        if(atoi(property) == 1)
            ctx->vstate.fakevsync = true;
    }
 
    if(property_get("debug.hwc.logvsync", property, 0> 0) {
        if(atoi(property) == 1)
            logvsync = true;
    }
 
    /* Currently read vsync timestamp from drivers
       e.g. VSYNC=41800875994
       */
    fd_timestamp = open(vsync_timestamp_fb0, O_RDONLY);
    if (fd_timestamp < 0) {
        // Make sure fb device is opened before starting this thread so this
        // never happens.
        ALOGE ("FATAL:%s:not able to open file:%s, %s",  __FUNCTION__,
               (fb1_vsync) ? vsync_timestamp_fb1 : vsync_timestamp_fb0,
               strerror(errno));
        ctx->vstate.fakevsync = true;
    }
 
    do {
        if (LIKELY(!ctx->vstate.fakevsync)) {
            len = pread(fd_timestamp, vdata, MAX_DATA, 0);
            if (len < 0) {
                // If the read was just interrupted - it is not a fatal error
                // In either case, just continue.
                if (errno != EAGAIN &&
                    errno != EINTR  &&
                    errno != EBUSY) {
                    ALOGE ("FATAL:%s:not able to read file:%s, %s",
                           __FUNCTION__,
                           vsync_timestamp_fb0, strerror(errno));
                }
                continue;
            }
            // extract timestamp
            const char *str = vdata;
            if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) {
                cur_timestamp = strtoull(str + strlen("VSYNC="), NULL, 0);
            }
        } else {
            usleep(16666);
            cur_timestamp = systemTime();
        }
        // send timestamp to HAL
        if(ctx->vstate.enable) {
            ALOGD_IF (logvsync, "%s: timestamp %llu sent to HWC for %s",
                      __FUNCTION__, cur_timestamp, "fb0");
            ctx->proc->vsync(ctx->proc, dpy, cur_timestamp);
        }
 
    } while (true);
    if(fd_timestamp >= 0)
        close (fd_timestamp);
 
    return NULL;
}
cs


다음 포스팅에서 내용을 이어서 진행하도록 하겠습니다.


http://elecs.tistory.com/133

300x250

안드로이드 프레임워크 프로그래밍(22) [SurfaceFlinger(시스템 서비스) 등록 및 초기화 과정]

안드로이드/프레임워크 2015. 8. 28. 02:37

※ 본 포스팅은 Android KitKat 4.4.4 를 기준으로 작성되었습니다. Kitkat 이전의 버전에서는 소스코드의 구조가 다름을 알립니다.


 안드로이드 기반 디바이스에 있어 화면을 출력하는 데 가장 중요한 기능으로 SurfaceFlinger가 있습니다. 본 포스팅에서는 시스템 서비스 중 하나인SurfaceFlinger에 대한 간단한 설명과 Framework 소스코드를 통해 SurfaceFlinger가 생성되는 과정을 살펴보도록 하겠습니다.




 안드로이드 운영체제가 실행되는 동안 내부에는 수많은 Application들이 실행되고 있습니다. 이러한 Application 중 화면에 정보를 출력하는 애플리케이션이 있는데 이는 Surface를 통해 화면의 정보를 구성합니다. Surface는 화면에 출력하는 그림의 단위로서 하나의 Application이 2개 이상의 Surface를 가지고 있을 수 있습니다.

 Application들이 가지고 있는 각 Surface들은 각각 BufferQueue에 연결되어 있으며 Surface에서 생성되는 화면의 정보가 BufferQueue에 축적되게 되면 이후 SurfaceFlinger에서 BufferQueue에 있는 Surface의 정보를 수신하게 됩니다.

 각 Surface로부터 화면을 받은 SurfaceFlinger는 수신된 화면의 정보를 합성하게 되고 이를 디스플레이를 담당하는 HAL에 정보를 전달하게 되면 해당 화면이 안드로이드 기반 디바이스의 Display에 출력됩니다.


 SurfaceFlinger의 기능에 대해 그림을 통해 간단하게 살펴보았습니다. 다음으로는 Framework를 통해 SurfaceFlinger가 어떻게 생성되는지 살펴보도록 하겠습니다.


/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*
 * Copyright (C) 2010 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#if defined(HAVE_PTHREADS)
#include <sys/resource.h>
#endif
 
#include <cutils/sched_policy.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "SurfaceFlinger.h"
 
using namespace android;
 
int main(int argc, char** argv) {
    // When SF is launched in its own process, limit the number of
    // binder threads to 4.
    ProcessState::self()->setThreadPoolMaxThreadCount(4);
 
    // start the thread pool
    sp<ProcessState> ps(ProcessState::self());
    ps->startThreadPool();
 
    // instantiate surfaceflinger
    sp<SurfaceFlinger> flinger = new SurfaceFlinger();
 
#if defined(HAVE_PTHREADS)
    setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
#endif
    set_sched_policy(0, SP_FOREGROUND);
 
    // initialize before clients can connect
    flinger->init();
 
    // publish surface flinger
    sp<IServiceManager> sm(defaultServiceManager());
    sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);
 
    // run in this thread
    flinger->run();
 
    return 0;
}
cs


 C++에 대해 어느 정도 이해하시는 분이라면 위의 소스코드를 보신다면 각 기능의 기능에 대해 바로 이해 하시리라 생각합니다.  각 소스코드를 한 줄씩 분석해 보도록 하겠습니다.


sp<SurfaceFlinger> flinger = new SurfaceFlinger()

SurfaceFlinger를 생성합니다. 생성시 소스코드는 아래와 같습니다.



/frameworks/native/services/surfaceflinger/SurfaceFlinger.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
....
 
class SurfaceFlinger : public BnSurfaceComposer,
                       private IBinder::DeathRecipient,
                       private HWComposer::EventHandler
{
public:
    static char const* getServiceName() ANDROID_API {
        return "SurfaceFlinger";
    }
 
    SurfaceFlinger() ANDROID_API;
 
    // must be called before clients can connect
    void init() ANDROID_API;
 
    // starts SurfaceFlinger main loop in the current thread
    void run() ANDROID_API;
 
    enum {
        EVENT_VSYNC = HWC_EVENT_VSYNC
    };
 
    // post an asynchronous message to the main thread
    status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
 
    // post a synchronous message to the main thread
    status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
 
....
 
}
cs


 SurfaceFlinger는 총 3개의 클래스를 상속하고 있는 것을 알 수 있습니다. SurfaceFlinger 생성자가 생성되는 동안 중요한 부분들을 소스코드를 통해 확인해 보도록 합시다.


/frameworks/native/services/surfaceflinger/DisplayHardware/HWComposer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
....
 
class HWComposer
{
public:
    class EventHandler {
        friend class HWComposer;
        virtual void onVSyncReceived(int disp, nsecs_t timestamp) = 0;
        virtual void onHotplugReceived(int disp, bool connected) = 0;
    protected:
        virtual ~EventHandler() {}
    };
 
    enum {
        NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
        MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
        VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
    };
 
    HWComposer(
            const sp<SurfaceFlinger>& flinger,
            EventHandler& handler);
 
....
 
}
cs


/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
....
 
SurfaceFlinger::SurfaceFlinger()
    :   BnSurfaceComposer(),
        mTransactionFlags(0),
        mTransactionPending(false),
        mAnimTransactionPending(false),
        mLayersRemoved(false),
        mRepaintEverything(0),
        mRenderEngine(NULL),
        mBootTime(systemTime()),
        mVisibleRegionsDirty(false),
        mHwWorkListDirty(false),
        mAnimCompositionPending(false),
        mDebugRegion(0),
        mDebugDDMS(0),
        mDebugDisableHWC(0),
        mDebugDisableTransformHint(0),
        mDebugInSwapBuffers(0),
        mLastSwapBufferTime(0),
        mDebugInTransaction(0),
        mLastTransactionTime(0),
        mBootFinished(false),
        mPrimaryHWVsyncEnabled(false),
        mHWVsyncAvailable(false),
        mDaltonize(false)
{
    ALOGI("SurfaceFlinger is starting");
 
    // debugging stuff...
    char value[PROPERTY_VALUE_MAX];
 
    property_get("ro.bq.gpu_to_cpu_unsupported", value, "0");
    mGpuToCpuSupported = !atoi(value);
 
    property_get("debug.sf.showupdates", value, "0");
    mDebugRegion = atoi(value);
 
    property_get("debug.sf.ddms", value, "0");
    mDebugDDMS = atoi(value);
    if (mDebugDDMS) {
        if (!startDdmConnection()) {
            // start failed, and DDMS debugging not enabled
            mDebugDDMS = 0;
        }
    }
    ALOGI_IF(mDebugRegion, "showupdates enabled");
    ALOGI_IF(mDebugDDMS, "DDMS debugging enabled");
}
 
....
cs

 SurfaceFlinger가 초기화가 이루어지는 동안 각 변수에 특정한 값이 저장되는 것이 보일 것입니다. 각 변수는 SurfaceFlinger.h에 정의되어 있습니다.


/frameworks/native/services/surfaceflinger/SurfaceFlinger.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
....
 
enum {
    eTransactionNeeded        = 0x01,
    eTraversalNeeded          = 0x02,
    eDisplayTransactionNeeded = 0x04,
    eTransactionMask          = 0x07
};
 
class SurfaceFlinger : public BnSurfaceComposer,
                       private IBinder::DeathRecipient,
                       private HWComposer::EventHandler
{
....
    // constant members (no synchronization needed for access)
    HWComposer* mHwc;
    RenderEngine* mRenderEngine;
    nsecs_t mBootTime;
    bool mGpuToCpuSupported;
    sp<EventThread> mEventThread;
    sp<EventThread> mSFEventThread;
    sp<EventControlThread> mEventControlThread;
    EGLContext mEGLContext;
    EGLConfig mEGLConfig;
    EGLDisplay mEGLDisplay;
    EGLint mEGLNativeVisualId;
    sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
 
....
 
    // don't use a lock for these, we don't care
    int mDebugRegion;
    int mDebugDDMS;
    int mDebugDisableHWC;
    int mDebugDisableTransformHint;
    volatile nsecs_t mDebugInSwapBuffers;
    nsecs_t mLastSwapBufferTime;
    volatile nsecs_t mDebugInTransaction;
    nsecs_t mLastTransactionTime;
    bool mBootFinished;
 
....
 
}
cs


 property란 안드로이드 system에서 각 프로세서들이 system의 설정값을 공유하는 저장소입니다. 설정값들은 Hash 테이블로 구성되어 있으며 각 key와 value는 string으로 구성되어 있습니다.

 property_get(key, value) 함수에서 key는 우리들이 찾고자 하는 해당 system의 property의 key값을 나타내며 value는 key를 통해 찾아낸 value값을 포인터를 통해 SurfaceFlinger에 사용할 수 있게 저장합니다. 아래 소스코드는 property_get() 함수가 정의된 모습입니다.


/frameworks/rs/rsCompatibilityLib.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "rsCompatibilityLib.h"
#include <string.h>
#include <sys/system_properties.h>
 
// Implementation of property_get from libcutils
int property_get(const char *key, char *value, const char *default_value) {
    int len;
 
    len = __system_property_get(key, value);
    if (len > 0) {
        return len;
    }
 
    if (default_value) {
        len = strlen(default_value);
        memcpy(value, default_value, len + 1);
    }
    return len;
}
 
cs


flinger->init();

 새로 생성된 SurfaceFlinger을 초기화 시킵니다. 소스코드는 아래와 같습니다.


/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
void SurfaceFlinger::init() {
    ALOGI(  "SurfaceFlinger's main thread ready to run. "
            "Initializing graphics H/W...");
 
    status_t err;
    Mutex::Autolock _l(mStateLock);
 
    // initialize EGL for the default display
    mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglInitialize(mEGLDisplay, NULL, NULL);
 
    // 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));
 
    // First try to get an ES2 config
    err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), EGL_OPENGL_ES2_BIT,
            &mEGLConfig);
 
    if (err != NO_ERROR) {
        // If ES2 fails, try ES1
        err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(),
                EGL_OPENGL_ES_BIT, &mEGLConfig);
    }
 
    if (err != NO_ERROR) {
        // still didn't work, probably because we're on the emulator...
        // try a simplified query
        ALOGW("no suitable EGLConfig found, trying a simpler query");
        err = selectEGLConfig(mEGLDisplay, mHwc->getVisualID(), 0, &mEGLConfig);
    }
 
    if (err != NO_ERROR) {
        // this EGL is too lame for android
        LOG_ALWAYS_FATAL("no suitable EGLConfig found, giving up");
    }
 
    // print some debugging info
    EGLint r,g,b,a;
    eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_RED_SIZE,   &r);
    eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_GREEN_SIZE, &g);
    eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_BLUE_SIZE,  &b);
    eglGetConfigAttrib(mEGLDisplay, mEGLConfig, EGL_ALPHA_SIZE, &a);
    ALOGI("EGL informations:");
    ALOGI("vendor    : %s", eglQueryString(mEGLDisplay, EGL_VENDOR));
    ALOGI("version   : %s", eglQueryString(mEGLDisplay, EGL_VERSION));
    ALOGI("extensions: %s", eglQueryString(mEGLDisplay, EGL_EXTENSIONS));
    ALOGI("Client API: %s", eglQueryString(mEGLDisplay, EGL_CLIENT_APIS)?:"Not Supported");
    ALOGI("EGLSurface: %d-%d-%d-%d, config=%p", r, g, b, a, mEGLConfig);
 
    // get a RenderEngine for the given display / config (can't fail)
    mRenderEngine = RenderEngine::create(mEGLDisplay, mEGLConfig);
 
    // retrieve the EGL context that was selected/created
    mEGLContext = mRenderEngine->getEGLContext();
 
    // figure out which format we got
    eglGetConfigAttrib(mEGLDisplay, mEGLConfig,
            EGL_NATIVE_VISUAL_ID, &mEGLNativeVisualId);
 
    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<BufferQueue> bq = new BufferQueue(new GraphicBufferAlloc());
            sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i, bq);
            sp<DisplayDevice> hw = new DisplayDevice(this,
                    type, allocateHwcDisplayId(type), isSecure, token,
                    fbs, bq,
                    mEGLConfig);
            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 %d as acquired/unblanked", i);
                hw->acquireScreen();
            }
            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);
 
    // start the EventThread
    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            vsyncPhaseOffsetNs, true);
    mEventThread = new EventThread(vsyncSrc);
    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
            sfVsyncPhaseOffsetNs, false);
    mSFEventThread = new EventThread(sfVsyncSrc);
    mEventQueue.setEventThread(mSFEventThread);
 
    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();
}
cs

 sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false);

 SurfaceFlinger를 SystemService에 등록합니다. SystemService에 등록됨과 동시에 Surface에서 BaseRef로부터 overriding한  onFirstRef() 함수가 실행됩니다.


/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

1
2
3
4
void SurfaceFlinger::onFirstRef()
{
    mEventQueue.init(this);
}
cs


flinger->run();

 SurfaceFlinger의 Thread를 실행합니다.


/frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

1
2
3
4
5
6
7
8
9
10
11
void SurfaceFlinger::waitForEvent() {
    mEventQueue.waitMessage();
}
 
....
 
void SurfaceFlinger::run() {
    do {
        waitForEvent();
    } while (true);
}
cs





300x250

안드로이드 Camera의 Framework 구조

안드로이드/카메라 2015. 8. 27. 19:13

 안드로이드의 카메라는 HAL과 Framework와 연결되어 있습니다. Camera를 활용하여 애플리케이션을 제작하는 분이라면 Framework 단계에서 만들어진 API를 활용하여 안드로이드의 Camera를 제어합니다. 안드로이드 카메라의 동작 원리를 안드로이드 운영체제의 구조를 통해 각 단계에서의 역할을 확인해 보도록 하겠습니다. 본 포스팅에서는 안드로이드 OS의 구조를 각 부분으로 나누어진 구조도로 살펴보겠습니다. 각 기능에 대한 자세한 내용은 본 포스팅에 일부 다루어진 부분이 있으니 참조해 주시길 바랍니다.





 위의 그림에서 붉은 글씨로 작성된 부분들에 대해 설명해 드리도록 하겠습니다.


Java Application

 우리들이 실제 사용하는 애플리케이션들이 작동되는 위치 입니다. 안드로이드 메인화면에서 카메라 애플리케이션 실행시 동작합니다. Java Framework에서 제공하는 API들을 활용하여 프로그램을 제작합니다.


Java Framework

  Application에게 카메라의 동작을 위한 API를 제공합니다. 주로 사용되는 클래스는 android.hardware.Camera API입니다. 이 API는 Camera의 실제 하드웨어와 연결됩니다. 소스코드가 Java로 구성되어 있어 Application 제작자들도 Java에 대한 이해가 깊다면 기능들을 쉽게 이해할 수 있습니다.


JNI(Java Native Interface)

 Java로 작성된 소스코드를 C/C++로 작성된 소스코드와 연결해주는 역할을 합니다. android.hardware.Camera의 JNI는 아래 경로에 있는 것을 확인하실 수 있습니다.


/frameworks/base/core/jni/android_hardware_Camera.cpp


 위 코드는 실제 카메라와의 연결된 low level의 native code를 호출하여 기능을 구현합니다. 해당 return 값을 Java Framework 단계에 있는 android.hardware.Camera에 전달합니다.


Native Framework

 해당 단계에서는 Java Framework 단계에 있는 android.hardware.Camera 클래스에게 native단계에서 구현된 기능을 제공합니다. 소스코드는 C++로 구성되어 있으며 Binder를 통해 camera service를 호출합니다. 해당 소스코드는 아래 경로에 있는 것을 확인하실 수 있습니다.


/frameworks/av/camera/Camera.cpp


HAL(Hardware Abstraction Layer)

 실제 안드로이드의 Camera 하드웨어와 C를 통해 긴밀하게 연결되어 있는 하드웨어 추상 단계입니다. 해당 단계에서는 Native Framework 단계에서의 camera service 클래스와 연결되어 있습니다. camera와 driver는 디바이스 기기의 화면을 통한 preview와 동영상 녹화 기능을 구현하기 위해 YV12와 NV21 이미지 포멧을 제공하니다.



출저 : http://source.android.com/devices/camera/

300x250