Boot Animation 변경 방법

========================================================================================================
출처 : http://blog.daum.net/baramjin/16010965

사실 Surface Flinger 응용이라고 했지만 맞는 표현은 아닌것 같다.

 

BootAnimation은 Surface Flinger가 생성되고 가장 먼저 동작하는 것이다. 당연히 아직 안드로이드 플랫폼의 어플리케이션이 동작하지 않은 상태에서 초기화 과정 중에 화면을 표시하는 영역이라서 한번 쯤 봐두어야 하는 부분이다.

 

단 이 부분에서 Surface Flinger와 관련된 전체적인 내용이 있다고는 생각되지 않는다. (도리어 EGL 초기화 과정이 한번 더 반복되고 OpenGL 사용 예가 나온다는 말이 맞다.)

 

Surface Flinger 에서 초기화를 위하여 사용하는 클래스가 DisplayHardware 이고 여기서는 surface를 생성하기 위하여 EGLDisplaySurface 클래스를 생성한다(여기서 Fb 디바이스 드라이버가 열리고, Frame Buffer 관련된 정보를 얻는다.) 이미 이런 초기화 작업이 이루어 졌기 때문에 BootAnimation에서 Fb 디바이스 드라이버 관련된 내용은 없고 새로운 surface를 EGLNativeWindowSurface로 생성한다.

 

생성자에서 보면 composer를 받아서 binding 하는 과정만 있다 (관련 정보는 mSession에 저장된다) 사실 binding이라는 의미는 아직도 낯설다.

BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
    Thread(false) {
    mSession = SurfaceComposerClient::clientForConnection(
            composer->createConnection()->asBinder());
}

 

초기화 과정을 보면 다음과 같다.

 

status_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();

 

    DisplayInfo dinfo;
    status_t status = session()->getDisplayInfo(0, &dinfo);
    if (status)
        return -1;

 

    // create the native surface
    sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
            PIXEL_FORMAT_RGB_565);
    session()->openTransaction();
    s->setLayer(0x40000000);
    session()->closeTransaction();

 

    // initialize opengl and egl
    const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
            EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
    EGLint w, h, dummy;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);

    mNativeWindowSurface = new EGLNativeWindowSurface(s);
    surface = eglCreateWindowSurface(display, config, 
            mNativeWindowSurface.get(), NULL);

 

    context = eglCreateContext(display, config, NULL, NULL);
    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
    eglMakeCurrent(display, surface, surface, context);
    mDisplay = display;
    mContext = context;
    mSurface = surface;
    mWidth = w;
    mHeight = h;
    mFlingerSurface = s;

 

    // initialize GL
    glShadeModel(GL_FLAT);
    glEnable(GL_TEXTURE_2D);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    return NO_ERROR;
}

 

초기화 과정을 보면 DisplayHardware 에서 했던 EGL 초기화와 같다. (위에서 말한 것처럼 다른 클래스를 이용하여 Fb 디바이스 드라이버를 오픈하지 않는 것만 다르다)

 

BootAnimation에서 일단 EGL 초기화가 되었으면 쓰레드에서 일정 시간 단위로 로고를 변화시켜주는 역활이 다이다.

이 부분은 대부분 OpenGL API 로 구현되어 있기 때문에 대충 이해하면 될 것 같고 하나의 준비가 되면 버퍼 스왑하는 과정이 보여진다.

 

bool BootAnimation::android() {
    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");

 

    // clear screen
    glDisable(GL_DITHER);
    glDisable(GL_SCISSOR_TEST);
    glClear(GL_COLOR_BUFFER_BIT);
    eglSwapBuffers(mDisplay, mSurface);

 

    const GLint xc = (mWidth  - mAndroid[0].w) / 2;
    const GLint yc = (mHeight - mAndroid[0].h) / 2;
    const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);

 

    // draw and update only what we need
    mNativeWindowSurface->setSwapRectangle(updateRect.left,
            updateRect.top, updateRect.width(), updateRect.height());

 

    glEnable(GL_SCISSOR_TEST);
    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
            updateRect.height());

 

    // Blend state
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

 

    const nsecs_t startTime = systemTime();
    do {
        nsecs_t now = systemTime();
        double time = now - startTime;
        float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
        GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
        GLint x = xc - offset;

 

        glDisable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);

 

        glEnable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);

        eglSwapBuffers(mDisplay, mSurface);
        
        // 12fps: don't animate too fast to preserve CPU
        const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
        if (sleepTime > 0)
            usleep(sleepTime); 
    } while (!exitPending());

 

    glDeleteTextures(1, &mAndroid[0].name);
    glDeleteTextures(1, &mAndroid[1].name);
    return false;
}

 

흠 정리하고 보니 사실 Surface Flinger와 관련된 내용은 초기에 SurfaceComposerClient의 API로 session을 구성하는 것은 관련이 있지만 대부분은 EGL 초기화와 Buffer Swap 관련된 내용이 대부분이다.

 

단 BootAnimation::android()에서 png 파일을 바꾸면 다른 부팅 화면을 구현할 수 있다는 정도 정리한 것에 만족해야 할 것 같다.


http://blog.daum.net/baramjin/16010965

'Platform > Android' 카테고리의 다른 글

[Android] Android 부팅  (0) 2010.03.18
[Android] Android 의 개요  (0) 2010.03.18
[Android] SGL  (0) 2010.03.18
[Android] Surface Flinger의 쓰레드  (1) 2010.03.18
[Android] Surface Flinger와 초기화 과정  (0) 2010.03.18

SGL 이 무엇인지 이 글을 읽고 처음 알게 되었다.
해야할건 많은데 어디서부터 해야할지 잘 모르겠다. 

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

출처 : http://blog.daum.net/baramjin/16010901

안드로이드의 기본 구조를 보면 library에 SGL이란 것이 있다. 

 


SGL은 "Scalable Graphic Library"의 약자로 안드로이드에서 Low Level Graphic (2D Graphic)을 담당하고 있는 것 같다. native code로 rendering (vector graphic rendering)을 담당하고 있다고 하는데 프레임워트의 High Level Graphic이라고 하는 Window Manager나 Surface Manager와 연결되어 있는 것 같다.


솔직히 Nucleus 기반의 프로젝트에서 GDI API를 만들기도 해서 이부분이 상당히 궁금하다.

Web에서 검색해보면 Skia란 곳에서 개발되었고 2005년에 Google이 합병했다고 하는 것 외에 거의 알려진 정보가 없다.


일단 적용된 프로젝트는 안드로이드와 크롬(Chrome)인 것 같다.


기본 기능은 텍스트, 기하학(Geometries) 모형, 이미지 그리는 2D 라이브러리이고, 다음 기능을 지원하는 것 같다.

  • 3x3 matrices w/ perspective
  • antialiasing, transparency, filters
  • shaders, xfermodes, maskfilters, patheffects


일단 관련 라이브러리는 libsgl.so 이다.


공식적인 위치는 


http://code.google.com/p/skia/


크롬이 발표되면서 관련 소스가 공개되었다. 관련 포스팅은 


http://www.kandroid.org/board/board.php?board=kandroidshow&command=body&no=25

http://www.atoker.com/blog/2008/09/06/skia-graphics-library-in-chrome-first-impressions/


시간 나면 한번 분석해 봐야 겠다.


http://blog.daum.net/baramjin/16010901

'Platform > Android' 카테고리의 다른 글

[Android] Android 의 개요  (0) 2010.03.18
[Android] Boot Animation  (0) 2010.03.18
[Android] Surface Flinger의 쓰레드  (1) 2010.03.18
[Android] Surface Flinger와 초기화 과정  (0) 2010.03.18
[Android] EGL 이란?  (0) 2010.03.18

Surface Flinger 의 연속~

========================================================================================================
출처 : http://blog.daum.net/baramjin/16010960


Surface Flinger의 초기화가 끝나면 사실 쓰레드가 하나 돌면서 Event를 처리하고 2-3가지의 일을 해주는 것이 주된 업무다. (맞나? 쓰레드 하는 일이 다 그렇지...)

 

SurfaceFlinger의 threadLoop()를 보면 다음과 같다.

 

bool SurfaceFlinger::threadLoop()
{
    waitForEvent();

    // check for transactions
    if (UNLIKELY(mConsoleSignals)) {
        handleConsoleEvents();
    }

 

    if (LIKELY(mTransactionCount == 0)) {
        // if we're in a global transaction, don't do anything.
        const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
        uint32_t transactionFlags = getTransactionFlags(mask);
        if (LIKELY(transactionFlags)) {
            handleTransaction(transactionFlags);
        }
    }

 

    // post surfaces (if needed)
    handlePageFlip();

 

    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    if (LIKELY(hw.canDraw())) {
        // repaint the framebuffer (if needed)

        handleRepaint();

 

        // release the clients before we flip ('cause flip might block)
        unlockClients();
        executeScheduledBroadcasts();

 

        // sample the cpu gauge
        if (UNLIKELY(mDebugCpu)) {
            handleDebugCpu();
        }

 

        postFramebuffer();
    } else {
        // pretend we did the post
        unlockClients();
        executeScheduledBroadcasts();
        usleep(16667); // 60 fps period
    }
    return true;
}

 

handleRepaint()는 flags에 따라서 업데이트할 방법이나 영역을 결정하고 모든 surface를 조합한다(이게 결국 Surface Flinger의 역활이지...)

 

void SurfaceFlinger::handleRepaint()
{
    // set the frame buffer
    const DisplayHardware& hw(graphicPlane(0).displayHardware());
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

 

    if (UNLIKELY(mDebugRegion)) {
        debugFlashRegions();
    }

 

    // compute the invalid region
    mInvalidRegion.orSelf(mDirtyRegion);

 

    uint32_t flags = hw.getFlags();
    if (flags & DisplayHardware::BUFFER_PRESERVED) {
        // here we assume DisplayHardware::flip()'s  implementation
        // performs the copy-back optimization.
    } else {
        if (flags & DisplayHardware::UPDATE_ON_DEMAND) {
            // we need to fully redraw the part that will be updated
            mDirtyRegion.set(mInvalidRegion.bounds());
        } else {
            // we need to redraw everything
            mDirtyRegion.set(hw.bounds());
            mInvalidRegion = mDirtyRegion;
        }

    }

 

    // compose all surfaces
    composeSurfaces(mDirtyRegion);

 

    // clear the dirty regions
    mDirtyRegion.clear();
}

 

void SurfaceFlinger::composeSurfaces(const Region& dirty)
{
    if (UNLIKELY(!mWormholeRegion.isEmpty())) {
        // should never happen unless the window manager has a bug
        // draw something...
        drawWormhole();
    }
    const SurfaceFlinger& flinger(*this);
    const LayerVector& drawingLayers(mDrawingState.layersSortedByZ);
    const size_t count = drawingLayers.size();
    LayerBase const* const* const layers = drawingLayers.array();
    for (size_t i=0 ; i<count ; ++i) {
        LayerBase const * const layer = layers[i];
        const Region& visibleRegion(layer->visibleRegionScreen);
        if (!visibleRegion.isEmpty())  {
            const Region clip(dirty.intersect(visibleRegion));
            if (!clip.isEmpty()) {
                layer->draw(clip);
            }
        }
    }
}

 

코드를 보면 조건에 따라 Update할 영역이 일부인지 전체인지를 결정하고 결국 composerSurfaces()를 호출하여 surface들을 조합하게 된다. composerSurfaces()는 Layer에서 보여지는 영역을 잘라오고 이를 draw 한다. (음 이는 Layer도 또 분석하라는 말인가?)

 

다시 threadLoop()를 가면 handleRepaint()에 의해서 그려질 내용은 정리되었고 이를 실제 FrameBuffer로 내보내야 한다. 이를 하는 것이 postFrameBuffer()이다.

 

void SurfaceFlinger::postFramebuffer()
{
    const bool skip = mOrientationAnimation->run();
    if (UNLIKELY(skip)) {
        return;
    }

 

    if (!mInvalidRegion.isEmpty()) {
        const DisplayHardware& hw(graphicPlane(0).displayHardware());

        if (UNLIKELY(mDebugFps)) {
            debugShowFPS();
        }

 

        hw.flip(mInvalidRegion);

 

        mInvalidRegion.clear();

 

        if (Layer::deletedTextures.size()) {
            glDeleteTextures(
                    Layer::deletedTextures.size(),
                    Layer::deletedTextures.array());
            Layer::deletedTextures.clear();
        }
    }
}

 

일단 처음에 보면 Animation이 돌고 있으면 바로 return하게 된다. 이는 BootAnmation을 통해서 나중에 좀 더 생각해 보고 일단 주된 동작은

graphicPlane으로부터 처음 초기화에서 만들어 놓은 DisplayHardware의 포인터를 얻고 DisplayHardware의 flip을 호출해서 버퍼을 swap 시켜주게 된다.

 

handleRepaint()와 postFrameBuffer()를 보면 Surface Flinger는 업데이트할 영역 관리를 두개의 영역 변수로 관리한다. 하나는 mDirtyRegion으로 handleRepaint()에서 계산해서 필요한 일을 한 후에 mInvalidRegion에 저장하고 mDirtyRegion은 클리어 된다. postFrameBuffer()는 mInvalidRegion이 있는 경우에만 더블 버퍼 스왑을 하고 역시 mInvalidRegion은 클리어 한다.

 

void DisplayHardware::flip(const Region& dirty) const
{
    checkGLErrors();

 

    EGLDisplay dpy = mDisplay;
    EGLSurface surface = mSurface;

 

    Region newDirty(dirty);
    newDirty.andSelf(Rect(mWidth, mHeight));

 

    if (mFlags & BUFFER_PRESERVED) {
        const Region copyback(mDirty.subtract(newDirty));
        mDirty = newDirty;
        mDisplaySurface->copyFrontToBack(copyback);
    }

 

    if (mFlags & SWAP_RECTANGLE_EXTENSION) {
        const Rect& b(newDirty.bounds());
        mDisplaySurface->setSwapRectangle(
                b.left, b.top, b.width(), b.height());

    }

 

    eglSwapBuffers(dpy, surface);
    checkEGLErrors("eglSwapBuffers");

}

 

 사실 코드를 보면 eglSwapBuffers만 부르기 때문에 어떻게 더블 버퍼를 관리하는지는 다시 EGL의 몫으로 넘겨졌다. 또한 copyFrontToBack등을 통해서 기존에 그려진 내용을 저장해 두는 과정 등이 있는데 이 부분이 왜 필요한지, 또 성능에 영향은 없는지도 고민되는 사항이다.

 

모 그런 부분은 일단 알아서 다 잘 되겠지 하는 생각 또는 나중에 시간나면 분석하는 것 둘 중에 하나의 일일 것이다.


http://blog.daum.net/baramjin/16010960


'Platform > Android' 카테고리의 다른 글

[Android] Boot Animation  (0) 2010.03.18
[Android] SGL  (0) 2010.03.18
[Android] Surface Flinger와 초기화 과정  (0) 2010.03.18
[Android] EGL 이란?  (0) 2010.03.18
[Android] Hello Android 출력하기  (0) 2010.03.09

화면에 보여주기 위한 기본 Surface Flinger

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

출처 : http://blog.daum.net/baramjin/16010959

Android Native Server 개념에 크게 Surface Flinger와 Audio Flinger란 것이 있다.

사실 Flinger란 단어가 참 낯설게 느껴지는데 사전적인 의미로는 투수(무언가 던지거나 차는 사람)란 의미가 가장 의미가 와 닿는 것 같은데 Application에서의 데이터를 한데 모아서 출력쪽으로 던져주는 역활을 한다는 의미로 사용한 것이 아닐까 싶다. (언제나 그렇듯이 추측이다)

 

Surface Flinger는 단연히 여러가지 Surface 데이터를 한데 모아서 Frame Buffer를 업데이트하는 것이고 Audio Flinger는 여러가지 오디오 샘플을 한데 모아서, 즉 Audio Mixing을 해서 ALSA 쪽으로 보내는 역활을 한다고 볼 수 있다.

 

Surface Flinger에 대한 가장 잘 표현된 그림은 다음과 같다.

 

Surface Flinger가 하는 기본적인 내용을 번역해 보면 다음과 같다.

 

  • Provides system-wide surface "composer", handling all surface rendering to frame buffer device

composer라고 하는 surface들을 합치는 기능을 제공한다는 의미인 것 같다. (비슷한 말들이 계속 나온다)

 

  • Can combine 2D and 3D surfaces and surfaces from multiple applications

2D, 3D surface를 결합하거나, 여러 응용들의 surface를 결합할 수 있다. 이 말이 결국 Suface Flinger의 역활을 한마디로 표현한 것이 아닌가 싶다.

 

  • Surfaces passed as buffers via Binder IPC calls

Binder IPC calls에 의하여 버퍼를 패스한다. (사실 아직 Binder란 개념이 낯설어서 이 말은 이해가 전혀 안된다.)

 

  • Can use OpenGL ES and 2D hardware accelerator for its compositions

Surface 들을 결합하기 위하여 OpenGL ES와 2D H/W 가속을 이용할 수 있다.

 

  • Double-buffering using page-flip

Page Flip을 위해서 더블 버퍼링을 사용한다.

 

결론적으로 OpenGL ES와 연동이 되면서 Surface들을 합쳐서 Frame Buffer로 전달할 수 있는 구조이며 page flip을 위해 double buffering을 사용한다는 것으로 요약할 수 있을 것이다.

 

OpenGL ES와 연동하기 위하여 Surface Flinger의 초기화 과정을 보면 EGL을 이용하여 Display와 Surface 등을 생성하는 과정을 확인할 수 있다.

 

관련 소스를 보면 다음과 같다.

\frameworks\base\libs\surfaceflinger\SurfaceFlinger.cpp

\frameworks\base\libs\surfaceflinger\displayhardware\DisplayHardware.cpp

\frameworks\base\libs\ui\EGLDisplaySurface.cpp

\frameworks\base\opengl\libagl\Egl.cpp

 

SurfaceFlinger.cpp를 보면 SurfaceFlinger 클래스는 여러 클래스로부터 다중 상속된 클래스이다. 특히 Thread 클래스로부터 상속된 클래스인테 이는 실행되면 하나의 threadLoop()가 동작함을 의미한다. 이 threadLoop가 동작하기 전에 readyToRun()으로 초기화 과정이 이루어 진다.

 

SurfaceFlinger의 readyToRun()을 보면 초기화 과정 중 main display를 초기화 하는 과정과 OpenGL ES를 초기화하는 과정이 있음을 알 수 있다. main display를 초기화 하는 과정을 보면 다음과 같다.

 

status_t SurfaceFlinger::readyToRun()

        ......

 

        // initialize the main display
        GraphicPlane& plane(graphicPlane(dpy));
        DisplayHardware* const hw = new DisplayHardware(this, dpy);
        plane.setDisplayHardware(hw);

 

 

즉 DisplayHardware를 생성하는 과정이 필요하다. 생성되는 DisplayHaraware는 GraphicPlane에 설정된다.

DisplayHardware 클래스를 보면 init 함수에서 EGL 관련된 내용들을 초기화 하고 있다.

DisplayHardware::DisplayHardware(
        const sp<SurfaceFlinger>& flinger,
        uint32_t dpy)
    : DisplayHardwareBase(flinger, dpy)
{
    init(dpy);
}

 

 

init() 함수에서 하는 내용을 순서대로 정리하면 다음과 같다.

 

1) Display 정보 얻어서 EGL 초기화

- EGL extenstion 정보 얻는 과정도 포함하며 이를 이용하여 mFlag에 조건 저장

2) Surface 생성

3) OpenGL ES의 Context 생성

4) OpenGL ES의 Extension 정보 얻음

- 이를 위해서 Display와 Surface, Context를 bind 하는 과정 있음, 모든 정보를 얻으면 다시 unbind

- Extension 정보를 저장하여 mFlag에 조건 저장

5) 생성된 내용을 저장

6) Hardware Module 초기화

- copybit

- overlay

 

init()에서 하는 과정은 대부분은 EGL 초기화 과정과 디바이스 드라이버(특히 fb, scaler 등)를 여는 것이라고 볼 수 있으며 이에 대한 내용은

http://www.khronos.org/registry/egl/specs/eglspec.1.3.pdf 을 참고하는 것이 좋다.

 

1) Display 정보 얻어서 EGL 초기화

 

void DisplayHardware::init(uint32_t dpy)

{

    ......

 

    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, NULL, NULL);
    eglGetConfigs(display, NULL, 0, &numConfigs);
    eglChooseConfig(display, attribs, &config, 1, &n); 

}

 

2) Surface 생성

Surface 생성은 크게 EGLDisplaySurface 클래스를 생성하는 과정과 이로부터 실제 EGL의 windows surface를 생성하는 과정으로 나뉘어 진다.

EGL은 세종류의 surface type(windows, pbuffers, pixmaps)를 지원하는데 windows는 onscreen rendering에 사용되고, pbuffers는 offscreen rendering에 사용되며 pixmaps는 nativa API로 접근하는 버퍼들에 대한 offscreen rendering에 사용된다. 말이 좀 어려운데 결국 onscreen rendering은 우리가 보통 얘기하는 frame buffer와 직접적인 관련이 있다는 것을 알 수 있다.

결국 여기에서 frame buffer로의 기본 출력 (fb device와의 연결)을 위한 기본 동작이 수행된다.

 

void DisplayHardware::init(uint32_t dpy)

{

    ......

 


    /*
     * Create our main surface
     */
 

    mDisplaySurface = new EGLDisplaySurface();

    surface = eglCreateWindowSurface(display, config, mDisplaySurface.get(), NULL);
    //checkEGLErrors("eglCreateDisplaySurfaceANDROID");

 

    if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
        if (dummy == EGL_BUFFER_PRESERVED) {
            mFlags |= BUFFER_PRESERVED;
        }
    }
    
    GLint value = EGL_UNKNOWN;
    eglQuerySurface(display, surface, EGL_HORIZONTAL_RESOLUTION, &value);
    if (value == EGL_UNKNOWN) {
        mDpiX = 160.0f;
    } else {
        mDpiX = 25.4f * float(value)/EGL_DISPLAY_SCALING;
    }
    value = EGL_UNKNOWN;
    eglQuerySurface(display, surface, EGL_VERTICAL_RESOLUTION, &value);
    if (value == EGL_UNKNOWN) {
        mDpiY = 160.0f;
    } else {
        mDpiY = 25.4f * float(value)/EGL_DISPLAY_SCALING;
    }
    mRefreshRate = 60.f;

}

 

EGLDisplaySurface  클래스를 생성하는 것을 보면 mapFrameBuffer()를 호출하는데  

EGLDisplaySurface::EGLDisplaySurface()
    : EGLNativeSurface<EGLDisplaySurface>()
{
    egl_native_window_t::version = sizeof(egl_native_window_t);
    egl_native_window_t::ident = 0;
    egl_native_window_t::incRef = &EGLDisplaySurface::hook_incRef;
    egl_native_window_t::decRef = &EGLDisplaySurface::hook_decRef;
    egl_native_window_t::swapBuffers = &EGLDisplaySurface::hook_swapBuffers;
    egl_native_window_t::connect = 0;
    egl_native_window_t::disconnect = 0;

    mFb[0].data = 0;
    mFb[1].data = 0;
    mBlitEngine = 0;
    egl_native_window_t::fd = mapFrameBuffer();

 

    ......

 

status_t EGLDisplaySurface::mapFrameBuffer()
{
    char const * const device_template[] = {
            "/dev/graphics/fb%u",
            "/dev/fb%u",

            0 };
    int fd = -1;
    int i=0;
    char name[64];
    while ((fd==-1) && device_template[i]) {
        snprintf(name, 64, device_template[i], 0);
        fd = open(name, O_RDWR, 0);
        i++;
    }
     if (fd < 0)
        return -errno;

 

    struct fb_fix_screeninfo finfo;
    if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
        return -errno;

 

    struct fb_var_screeninfo info;
    if (ioctl(fd, FBIOGET_VSCREENINFO, &info) == -1)
        return -errno;

 

   ......

 

    /*
     * Open and map the display.
     */

 

    void* buffer  = (uint16_t*) mmap(
            0, finfo.smem_len,
            PROT_READ | PROT_WRITE,
            MAP_SHARED,
            fd, 0);

 

    if (buffer == MAP_FAILED)
        return -errno;

 

    // at least for now, always clear the fb
    memset(buffer, 0, finfo.smem_len);

 

    uint8_t* offscreen[2];
    offscreen[0] = (uint8_t*)buffer;
    if (flags & PAGE_FLIP) {
        offscreen[1] = (uint8_t*)buffer + finfo.line_length*info.yres;
    } else {
        offscreen[1] = (uint8_t*)malloc(finfo.smem_len);
        if (offscreen[1] == 0) {
            munmap(buffer, finfo.smem_len);
            return NO_MEMORY;
        }
    }

 

    mFlags = flags;
    mInfo = info;
    mFinfo = finfo;
    mSize = finfo.smem_len;
    mIndex = 0;
    for (int i=0 ; i<2 ; i++) {
        mFb[i].version = sizeof(GGLSurface);
        mFb[i].width   = info.xres;
        mFb[i].height  = info.yres;
        mFb[i].stride  = finfo.line_length / (info.bits_per_pixel >> 3);
        mFb[i].data    = (GGLubyte*)(offscreen[i]);
        mFb[i].format  = GGL_PIXEL_FORMAT_RGB_565;
    }
    return fd; 


}

 

간단히 정리하면 여기에서는

1) fb device를 찾아서 열고

2) FSCREEN_INFO와 VSCREEN_INFO를 얻은 후,

3) mmap()으로 fb device에 직접 억세스할 수 있는 버퍼 포인터를 얻고 (mmap은 리눅스의 char형 Device Driver를 File I/O 형태로 접근하지 않고 pointer 형태로 접근하도록 해준다. 이와 관련된 내용은 추후 다시 정리)

4) 이를 mFb에 저장한다.

 

즉 EGLDisplaySurface 클래스를 만듬으로써 SurfaceFlinger가 실제 Fb Devie Driver로 접근하기 위한 준비를 하게 되는 것이다. eglCreateWindowSurface를 호출하여 window surface를 만드는 것은 EGL을 사용하기 위하여 반드시 필요한 과정이다. 또한 이 과정이 EGLDisplaySurface 클래스로 생성된 내용을 실제 연결하는 과정이라고 생각해도 될 것 같다.

 

 

3) OpenGL ES의 Context 생성은 원래 EGL의 초기화 과정 중의 하나이다. 부담없이 보면 다음과 같다. context를 생성한 후, width와 height 정보를 얻어서 저장한다.

 

void DisplayHardware::init(uint32_t dpy)

{

    ......

 

    /*
     * Create our OpenGL ES context
     */
    
    context = eglCreateContext(display, config, NULL, NULL);
    //checkEGLErrors("eglCreateContext");
    
    eglQuerySurface(display, surface, EGL_WIDTH, &mWidth);
    eglQuerySurface(display, surface, EGL_HEIGHT, &mHeight); 

}

 

4)의 과정은 정보를 얻기 위하여 display, surface, context를 bind, unbind 하는 과정을 볼 수 있다는 것 외에 특별히 유의 사항은 없을 것 같다. 5)의 과정도 생성된 내용을 저장해 둔다는 것에만 주의하면 된다.

 

6) Hardware Module 초기화 과정에서는 2개의 중요한 모듈 copybit과 overlay를 초기화 한다. 6의 과정은 여기에서 하드웨어 모듈이 초기화 된다는 것이 중요하다. 이러한 하드웨어 모듈은 다시 말하면 GPU가 제공해주는 기능이다. 안드로이드의 경우 다양한 CPU Platform을 지원할 수 있고, 이는 같은 ARM 코어를 사용하는 경우라도 GPU 인터페이스는 다르다는 것을 의미한다. 즉 copybit 과 overlay 엔진에 대한 코드는 Chip vendor에서 만들어 두고 제공해 주어야만 바로 여기에서 그 장치를 열고 추후에 Surface Flinger를 사용할 때, CPU Platform의 고유한 성능을 낼 수 있는 것이다.

 

void DisplayHardware::init(uint32_t dpy)

{

    ......

 

    hw_module_t const* module;

    mBlitEngine = NULL;
    if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
        copybit_open(module, &mBlitEngine);

    }

    mOverlayEngine = NULL;
    if (hw_get_module(OVERLAY_HARDWARE_MODULE_ID, &module) == 0) {
        overlay_control_open(module, &mOverlayEngine);

    } 

}

 

copybit에 대해서는 추후에 더 정리해야 겠지만 bitblt와 stretchbitblt를 지원하는 모듈이다. 여기에서 무슨 기능인지 알 수 있는 사람도 있겠지만 다시 설명하면 이미지 드로잉에서 많이 사용하는 복사와 Scaleing을 지원하는 장치라고 생각하면 될 것 같다. 즉 fb device 외에도 GPU의 scaler와 copy 기능을 위한 장치도 여기에서 열리게 된다.

 

초기화 과정에서 얻은 EGL의 정보로부터 mFlag에 특정 조건을 저장하는데 이는 나중에 Surface Flinger의 더블 버퍼 스왑 등의 처리 조건으로 사용된다. 이는 추후 다시 정리한다.

 

대략적인 초기화 과정에 대한 설명은 이것으로 끝이다. 그런데 왜 Surface Flinger의 초기화 과정 대부분이 EGL 초기화 과정일까?

모 이에 대한 답은 추론할 수 밖에 없다. 안드로이는 처음부터 2D Drawing은 Skia를 이용하면서 OpenGL ES를 지원하도록 설계되어 있다. OpenGL ES를 지원하려면 EGL를 이용하여 Native Window와 연결할 수 있는 구조를 만들어 주어야 한다. 따라서 일반적인 Embedded System의 단순한 GDI 함수와 Screen Buffer (Frame Buffer)의 개념이 아닌 EGL를 통한 display, surface, context를 이용한 개념으로 부터 출발할 수 밖에 없다. 만약 OpenGL ES를 지원하지 않도록 설계되었다면 Surface Flinger라고 하지 않고 Display Flinger나 Screen Flinger라고 했을 수도 있을 것 같다.

 

이런 개념 때문에 OpenGL 등을 잘 모르는 Embedded Programer 입장에서는 단순히 GDI 개념을 이해하기에도 머리 복잡한 내용이 너무 많아진다. 당연히 fb 디바이스 드라이버만 오픈하고 이렇게 오픈된 디바이스로부터 mmap으로 메모리 포인터를 얻어와서 GDI 함수를 구현하는 것에 익숙해져 있는데 (사실 이것도 리눅스 하는 사람 아니면 익숙하지 않다) 여기에 한가지 개념이 더 포함된 것이다.

 

하여간 추측으로 분석하고 적당히 마무리하지만 안드로이드 시스템에서 표준 방식으로 fb 디바이스 드라이버를 여는 곳은 여기이고 이의 구조를 이해해야만 middleware의 접근이 쉬워진다.

 

 

기타 참고로 부팅시 로그를 받아보면 다음과 같다.

 

I/SurfaceFlinger(  739): SurfaceFlinger is starting
I/SurfaceFlinger(  739): showcpu enabled
I/SurfaceFlinger(  739): showfps enabled
I/SurfaceFlinger(  739): SurfaceFlinger's main thread ready to run. Initializing graphics H/W...
I/SurfaceFlinger(  739): EGL informations:
I/SurfaceFlinger(  739): # of configs : 6
I/SurfaceFlinger(  739): vendor    : Android
I/SurfaceFlinger(  739): version   : 1.31 Android META-EGL
I/SurfaceFlinger(  739): extensions:
I/SurfaceFlinger(  739): Client API: OpenGL ES
I/EGLDisplaySurface(  739): using (fd=21)
I/EGLDisplaySurface(  739): id           = xxx_fb
I/EGLDisplaySurface(  739): xres         = 800 px
I/EGLDisplaySurface(  739): yres         = 480 px
I/EGLDisplaySurface(  739): xres_virtual = 800 px
I/EGLDisplaySurface(  739): yres_virtual = 960 px
I/EGLDisplaySurface(  739): bpp          = 16
I/EGLDisplaySurface(  739): r            = 11:5
I/EGLDisplaySurface(  739): g            =  5:6
I/EGLDisplaySurface(  739): b            =  0:5
I/EGLDisplaySurface(  739): width        = 800 mm (25.400000 dpi)
I/EGLDisplaySurface(  739): height       = 480 mm (25.400000 dpi)
I/EGLDisplaySurface(  739): refresh rate = 60.00 Hz
W/SurfaceFlinger(  739): ro.sf.lcd_density not defined, using 160 dpi by default.
I/SurfaceFlinger(  739): OpenGL informations:
I/SurfaceFlinger(  739): vendor    : Android
I/SurfaceFlinger(  739): renderer  : Android PixelFlinger 1.0
I/SurfaceFlinger(  739): version   : OpenGL ES-CM 1.0
I/SurfaceFlinger(  739): extensions: GL_OES_byte_coordinates GL_OES_fixed_point GL_OES_single_precision GL_OES_read_format G
L_OES_compressed_paletted_texture GL_OES_draw_texture GL_OES_matrix_get GL_OES_query_matrix GL_ARB_texture_compression GL_AR
B_texture_non_power_of_two GL_ANDROID_direct_texture GL_ANDROID_user_clip_plane GL_ANDROID_vertex_buffer_object GL_ANDROID_g
enerate_mipmap

 


http://blog.daum.net/baramjin/16010959

'Platform > Android' 카테고리의 다른 글

[Android] SGL  (0) 2010.03.18
[Android] Surface Flinger의 쓰레드  (1) 2010.03.18
[Android] EGL 이란?  (0) 2010.03.18
[Android] Hello Android 출력하기  (0) 2010.03.09
[Android] 개발환경6 - Virtual Device 생성(에뮬레이터)  (0) 2010.03.09

Application 개발보다는 Android 내부에 대해 좀 더 공부해야겠다.. ㅠ_ㅠ
근데 자료가 많지 않아 공부하기가 쉽진 않은것 같다.

========================================================================================================
출처 : http://blog.daum.net/baramjin/16010958

관련 내용은 http://www.khronos.org/egl/ 의 내용을 번역한 것이다.

 

EGL

EGL at a glance

EGL provides mechanisms for creating rendering surfaces onto which client APIs like OpenGL ES and OpenVG can draw, creates graphics contexts for client APIs, and synchronizes drawing by client APIs as well as native platform rendering APIs. This enables seamless rendering using both OpenGL ES and OpenVG for high-performance, accelerated, mixed-mode 2D and 3D rendering.

 

EGL은 OpenGL ES, OpenVG 와 같은 클라이언트 API가 그림을 그리거나, Graphic context를 생성하거나, nativa platfrom rendering API뿐만 아니라 클라이언트 API에 의해서 그려진 내용을 동기화할 수 있는 rendering surface를 생성할 수 있는 방법을 제공한다.

이것은 고성능, 가속화된 2D와 3D 혼합 redering을 위하여 OpenGL ES와 OpenVG를 사용하는 한결같은 rendering을 가능하게 한다.

 

(흠 번역해도 말이 이해가 바로 되지는 않네요? 중요한 것은 redering surface를 생성할 수 있는 방법을 제공한다는 것이겠죠)

EGL (Native Platform Graphics Interface)

EGL Native Platform Graphics Interface is an interface portable layer for graphics resource management - and works between rendering APIs such as OpenGL ES or OpenVG and the underlying native platform window system. Learn More...

The EGL 1.4 specification, header files, and optional extension specifications are available in theKhronos Registry

 

EGL Native Platform Graphic Interface는 graphics resource 관리를 위한 interface portable layer이다. OpenGL ES나 OpenVG와 같은 rendering API와 native platform window system(X window와 windows와 같은 GUI 기반의 windows UI platform을 의미) 사이에서 동작한다.

 

 

 

EGL이 하는 것을 정리하면....

 

1. 클라이언트 API들이 그림을 그리거나 공유할 수 있는 rendering surfaces(windows, pbuffers, pixmaps)를 생성하는 매커니즘 제공 

(결국 OpenGL ES나 OpenVG를 위한 그림판을 제공한다고 생각하면 되겠네요, surface는 아무래도 그림판이라고 이해하는 것이 가장 좋을 듯...)

2. 클라이언트 API들을 위한 graphic contexts를 생성하거나 관리하는 방법

3. nativa platform rendering APIs들과 클라이언트 API들에 의해 그려진 내용을 동기화(synchronize) 하는 방법

(이 내용을 안드로이드 개념에서 이해하면 결국 Skia로 그려진 2D내용과 OpenGL ES에 그려진 3D 내용을 합칠수 있다는 말로 이해되지요?)

 

 

 

 

안드로이드의 \frameworks\base\opengl\include\EGL을 보면 EGL 1.2 가 포팅되어 있는 것 같다.

안드로이드에서 EGL에 대하여 봐야 하는 이유는 SufaceFlinger의 초기화 과정을 보면 EGL을 이용하여 display, surface, context 등을 초기화하는 과정이 있기 때문이다.


따라해서 하긴 했지만 드디어~!!

Hello Android 를 찍었습니다.

음.. 여기서부터 Android 가 시작인가보네요~

========================================================================================================
출처 : http://moozi.tistory.com/trackback/28

프로그램밍언어를 처음 공부할 때 책에서  일반적으로 처음 접하는 프로그램이 "Hello World"와 같은 문자를 출력하는 것입니다.

안드로이드 개발자 사이트도 예외는 아니어서 "Hello Android"를 출력하는 예제를 소개하고 있습니다.

이번 강좌에서는 "Hello Android"를 출력 예제를 다루도록 하겠습니다.

1. 먼저 AVD(Android Virtual Device)를 생성해 두어야 합니다.
(AVD생성은 http://moozi.tistory.com/26 글을 참조하세요)

2. 이클립스에서 새로운 안드로이드 프로젝트를 생성합니다.

1) File -> New -> Project 선택


2) New Project창에서 Android Projcet 선택 후 Next버튼 클릭

3) New Android Project 창에서 다음과 같이 입력한 후 Finish버튼을 누릅니다. 
Min SDK Version 은 Build Target을 지정하면 자동 입력됩니다.


4.프로젝트가 생성되면, 왼쪽 탐색기에서 HelloAndroid.java 를 더블클릭합니다.


HelloAndroid.java 파일을 열면 기본적으로 코드가 생성됩니다. 위 그림에서 빨간색 네모상자로 표시한 + 기호를 클릭하면 다른 코드를 더 볼 수 있습니다.

5. 다음 코드를 추가로 입력합니다.

6. 이제 실행할 차례입니다.

1) Run -> Run 을 선택합니다.

2) Run As 창에서 Android Application을 선택 한 후 OK를 누릅니다.

3) 만일 코딩후 저장을 안 했다면 Yes버튼을 눌러서 저장합니다.



7. 결과화면입니다.

필자의 경우은 Run 실행후 에뮬레이터초기 화면상태에서 오른쪽의 동그란 MENU버튼을 눌러야 위의 결과화면을 볼 수 있었습니다. (MENU버튼을 누른 후에도 몇개의 경고메세지가 나왔는데, 버튼을 눌러 닫고 나니 결과물이 보입니다.)

간단한 프로그램이지만 시작이 반이라고 많은 것을 한 느낌이에요 ^^;

http://moozi.tistory.com/trackback/28

Android 는 Virtual Device 가 잘되어 있어, 개발하기 편한거 같다


========================================================================================================
출처 : http://moozi.tistory.com/trackback/26

irtual Device는 안드로이드폰 에뮬레이터를 말합니다. 이것은 사용자컴퓨터에서 가상의 안드로이드폰을 실행하는 것입니다.

이클립스 툴바에서 핸드폰모양 버튼을 클릭합니다.

Android SDK and AVD Manager창의 왼쪽패널에서 Virtual Devices를 선택하면, 생성된 AVD(Android Virtual Device)가 아무것도 없음을 알 수 있습니다.  New버튼을 클릭해서 AVD를 만들어 보겠습니다.



Create new AVD 창에서 Name을 입력하고, Target은 Android 2.0 을 선택합니다.
그리고 Create AVD 버튼을 누릅니다.




중간에 해상도등 설정하는 조그만 창이 나오면 그냥 다음으로 진행해주세요.

처음엔 다음과 같은 화면이 나옵니다.

AVD가 완전히 로딩이 끝날때까지는 시간이 꽤 많이 걸립니다. ( 3 ~5분 정도 걸리는것 같아요) 
처음엔 에러가 나는 줄 알았습니다. 그래서 중간화면도 보여드립니다.


다음으로 나오는 화면입니다.


그리고나서 드디어 로딩이 완료된 화면입니다.



다음은 menu버튼을 눌러서 google에 접속한 모습입니다.


이제 안드로이드2.0을 개발할 기본적인 준비가 되었습니다.

http://moozi.tistory.com/trackback/26

Available package 를 단순히 시도하는 경우 잘 안되는 경우가 있어 설정값을 추가해주면 됩니다.

Android 설정값이 있는 폴더로 이동하여 저의 경우 아래 폴더에 설치가 되어 있었습니다.
C:\Documents and Settings\sec\.android

폴더에 androidtool.cfg 파일을 생성한 후 
cfg 파일안에 아래와 같이 추가하여 저정한 후에 Available packages 를 시도하면 쉽게 됩니다.

sdkman.force.http=true


========================================================================================================
출처 : http://moozi.tistory.com/trackback/25

이번에 할 작업은 Available Packages 추가등록입니다.

이클립스의 툴바에서 핸드폰모양버튼을 클릭합니다.
Android SDK adn AVD Manager창 왼쪽패널에서 Availble Packages를 선택합니다.
오른쪽에 보면 버젼별로 나와 있는데, 필자는 가장 최근버젼만 선택하였습니다. (위의 세개와 맨 마지막 항목에 체크하세요)
그리고나서 Install Selected를 누릅니다.




다음 Choose Packages to Install 창에서 오른쪽하단의 Accept All 체크박스를 클릭한 후 Install Accepted 버튼을 누릅니다.



[ 인스톨이 진행중인 모습 ]

참고로 이 과정이 시간이 오래 걸립니다. 

인스톨이 완료된 후 Installed Packages를 선택하면 다음과 같이 인스톨된 패키지를 확인할 수 있습니다.
[ 추가로 설치된 패키지들 ]

앞으로 더 필요한 패키지들이 있다면 이와 같은 방법으로 추가 설치하면 되겠습니다.


http://moozi.tistory.com/trackback/25
Android SDK 도 그렇고 이클립스도 그렇고 
설치하는 것이 아니라 압축만 푼 후에 바로 실행 / 설정 후 사용하도록 되어 있습니다.

이클립스 실행파일을 바탕화면에 "바로가기"를 하나 만들어 놓는것이 좋습니다. 

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

출처 : http://moozi.tistory.com/trackback/24 (원본글을 약간 수정했습니다)

SDK와 이클립스를 연동하기 전에 먼저 다운 받아 놓은 이클립스를 실행해 보겠습니다.

참고로 이클립스를 이용해서 안드로이드를 개발하시려면 Java SDK는 미리 설치되어 있어야 합니다.
(Android 개발환경1 을 보면 Java SDK 설치 방법에 대해 나와 있습니다.)

다운로드 받은 이클립스를 압축을 풉니다.


[ 다운로드 받은 이클립스를 압축을 푼 모습 ]


eclipse.exe를 더블클릭하면 실행됩니다.


처음에 위와 같이 workspace 설정화면이 나옵니다. 
workspace 경로는 변경할 수 있습니다. (필자는 변경하지 않았습니다)

지정한 경로를 계속 기본값으로 사용하려면 왼쪽 하단의 체크박스를 체크하세요.


[ 이클립스 실행 화면 ]

위와 같이 실행화면이 보인다면 일단 이클립스가 정상적으로 실행된 것입니다.


이제 이클립스 안드로이드 플러그인을 다운로드 해 보겠습니다.

http://developer.android.com/ => 안드로이드 개발자 사이트로 갑니다.

(안드로이드 개발자 사이트는 IE6.0에서는 접속되지 않습니다. IE8.0 이나 구글크롬브라우저를 이용하세요!
저의 글 http://moozi.tistory.com/19 를 참조하기 바랍니다.)


상단의 SDK 탭 -> 왼쪽의 ADT Plugin for Eclipse 메뉴의 Installing adn Updating 을 클릭해서

Installing the ADT plugin 부분으로 이동하면 오른쪽에 Eclipse 3.5 (Galileo) 에 해당하는 글이 있습니다.
이 글의 설명대로 진행하면 됩니다.

1. Eclipase를 실행해서 Help > Install New Software 선택

2. Available Software 윈도우창에서 Add버튼 클릭


3. Add Site 윈도우에서 Name란에 "Android Plugin"을 입력(다른 이름으로 바꿔도 됩니다.)하고 Location란에https://dl-ssl.google.com/android/eclipse/ 을 입력한 후 OK를 누릅니다.


만일 플러그인이 검색되지 않는다면, https에서 s를 뺀 http://dl-ssl.google.com/android/eclipse/ 로 다시 시도해 보세요.
(필자의 경우는 https://dl-ssl.google.com/android/eclipse/ 로 입력하여 아래 5번과정을 진행하다가 에러가 나서 이클립스를 종료한 후 s를 뺀 http://dl-ssl.google.com/android/eclipse/ 로 다시 시도해서 성공했습니다.)


4. 검색된 플러그인 목록을 모두 체크한 후 Next를 누릅니다.


5.  Install Details 창에서 Android DDMS 와 Android Development Tools 를 확인 하고 Next를 누릅니다.

사용자 약관에 동의한 후 Finish버튼을 누릅니다.


[인스톨이 진행되는 화면]


6. 이클립스를 재실행한다.

[ 이클립스 툴바에 핸드폰 아이콘이 등록된 모습 ]

위와 같이 툴바에 핸드폰 아이콘이 보이면 성공한 것입니다.

만약 툴바가 아예 보이지 않는다면 welcome 화면의 x 버튼을 눌러 welcome 화면을 종료시키면 보입니다.


이제 다음으로 할 일은 Android SDK Directory를 가리키도록 이클립스에서 Preferences를 수정하는 것입니다.

1. 이클립스 메뉴 Window -> Preferences 선택

2. 왼쪽 패널에서 Android선택 후 오른쪽 화면에서 SDK Location 항목에 안드로이드 SDK 압축을 푼 폴더의 경로를 지정합니다. (필자의 경우는 압축을 풀어 생긴 android-sdk-windows 폴더를 D드라이브에 옮겨 놓고 "D:\android-sdk-windows" 로 지정하였습니다.)


3. Apply를 클릭하고, OK를 클릭합니다.
이 과정에서 아무 작업도 발생 안하는 것 같이 보이지만, 이클립스 화면 오른쪽 하단에 보면 SDK Ping 부분에 작업진행바가 동작하는 것을 볼 수 있습니다.

작업 완료되면 툴바의 핸드폰 아이콘을 클릭합니다.

왼쪽패널의 두번째 항목인 Installed Package를 선택해 보면 오른쪽에 Android SDK Tools, revision 4 가 등록되어 있는 것을 확인해 볼 수 있습니다.

http://moozi.tistory.com/trackback/24



C나 C++ 등을 개발할때에는 Visual studio 를 사용했었으나,
Java 는 이클립스로 사용한다고 하네요~

이클립스를 다운로드 받는 방법입니다.

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

출처 : http://moozi.tistory.com/trackback/21

이클립스는 통합개발환경(IDE)을 제공하는 Tool입니다. 

http://www.eclipse.org/   => 이클립스 홈페이지입니다.




Download 메뉴를 클릭한 후, 두번째 항목을 선택합니다. 첫번째 항목인 Eclipse IDE fro Java EE Developers (189 MB) 보다는 두번째 항목인 Eclipse IDE for Java Developers(92MB)가 안드로이드개발에 더 적합합니다.



그림에서 빨간색 박스로 표시한 부분 을 클릭하여 다운로드합니다.

필자가 이글을 작성할 당시 이클립스버젼은 Galileo Eclipse 3.5 입니다.


http://moozi.tistory.com/trackback/21


+ Recent posts