[펌] http://blog.naver.com/PostView.nhn?blogId=free2824&logNo=60108857440

어떤 분이 친절하게 chatting 프로그램을 만들어서 공유를 하셨다.
소스 다운받아 두 개의 device에 apk 설치하고 테스트 하면 된다.
특별히 할 건 없고 서로 pairing만 해주고 프로그램 실행시켜 chatt 해보면 된다.

[펌] http://taehyo.egloos.com/4091452

출처: http://kzjblog.appsp0t.com/2010/11/20/suspend-en.html
       (원문 번역과 더불어 내용을 추가/수정/보완/삭제 하였음을 밝힙니다.)


개요

Suspend/Resume 은 리눅스 커널이 제공하는 기능으로 모바일 환경이 점점 보급되고 빠른 부팅 시간에 대한 요구가 늘어나면서 필요성이 증대되었다. 이 글은 리눅스의 Suspend/Resume을 개괄적으로 알아보고 안드로이드가 전원을 관리하는 방법에 대해 소개한다.


Version
Linux Kernel: v2.6.35.7
Android: Gingerbread(v2.3.3)


Suspend 소개
Suspend 는 크게 3부분으로 나눌 수 있다: 프로세스와 태스크들을 프리징하고(Freezing)/모든 드라이버의 suspend 콜백 함수를 호출하고/CPU와 코어 시스템 디바이스를 Suspend한다. 프로세스의 프리징은 모든 프로세스를 멈추는 것과 동일하다. 그리고 resume을 할 때 프로세스들은 중단한 일이 없었던 것처럼 다시 실행하기 시작한다. user space프로세스와 kernel space의 태스크들은 멈췄었다는 사실을 전혀 인지하지 못한다. 그러면 사용자는 어떻게 리눅스 시스템을 suspend 시킬까? 사용자는 sys 파일시스템의 파일을 읽고 쓸 수 있다: /sys/power/state 파일을 통해 커널의 전원 관리 서비스를 이용할 수 있다.
예를 들어
      # echo standby > /sys/power/state
명령으로 시스템을 suspend 시키고,
      # cat /sys/power/state
명령으로 커널에서 제공하는 전원 관리 상태(PM method)의 수를 알 수 있다.
이 상태는 'mem' (Suspend-to-RAM), 그리고 'disk'(Suspend-to-disk)의 값으로 하드 코딩(pm_states[PM_SUSPEND_MAX])되어 있다.



리눅스 시스템의 Suspend
파일:

아래의 경로에서 해당되는 리눅스의 소스코드를 확인할 수 있다.
   - linux_soruce/kernel/power/main.c
   - linux_source/kernel/arch/xxx/mach-xxx/pm.c
이 제 Suspend가 어떻게 일어나는지 살펴보자. user space 인터페이스인 /sys/power/state는 main.c의 state_store() 함수와 관련이 있다: const char * const pm_state[]으로 정의된 문자열("mem" 또는 "standby")을 사용할 수 있다. 일반적인 리눅스 커널에서 시스템이 Suspend 상태가 될 때 제일 먼저 suspend.c의 enter_state() 함수로 들어온다. enter_state() 함수는 먼저 시스템 상태가 유효(valid)한지 검사하고 파일 시스템을 sync(do all page writeback)한다.

/-*
 * enter_state - Do common work of entering low-power state.
 * @state:  pm_state structure for state we're entering.
 *
 * Make sure we're the only ones trying to enter a sleep state. Fail
 * if someone has beat us to it, since we don't want anything weird to
 * happen when we wake up.
 * Then, do the setup for suspend, enter the state, and cleaup (after
 * we've woken up).
 *-
int enter_state(suspend_state_t state)
{
    int error;

    suspend_test_start_level(TEST_SUSPEND_TIME_TOP);

    if (!valid_state(state)) {
        error = -ENODEV;
        goto End;
    }

    if (!mutex_trylock(&pm_mutex)) {
        error = -EBUSY;
        goto End;
    }

    printk(KERN_INFO "PM: Syncing filesystems ... ");
    sys_sync();
    printk("done.\n");

    pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
    error = suspend_prepare();
    if (error)
        goto Unlock;

    if (suspend_test(TEST_FREEZER))
        goto Finish;

    pr_debug("PM: Entering %s sleep\n", pm_states[state]);
    error = suspend_devices_and_enter(state);

    Finish:
    pr_debug("PM: Finishing wakeup.\n");
    suspend_finish();
    Unlock:
    mutex_unlock(&pm_mutex);

    End:
    suspend_test_finish_level(TEST_SUSPEND_TIME_TOP, "total transition time of resume");
    return error;
}

준비, 프로세스 프리징
suspend_prepare() 함수는 suspend를 위한 콘솔을 할당하고(pm_prepare_console()) suspend notifier를 실행하고(pm_notifier_call_chain(PM_SUSPEND_PREPARE)) user 모드 헬퍼를 비활성화하고(usermodehelper_disable()) suspend_freeze_processes() 함수를 호출한다. suspend_freeze_processes() 함수는 모든 프로세스의 현재 상태를 저장한다. 프리징 단계에서 몇몇 태스크나 user space의 프로세스가 프리징되는 것을 거부하는 경우에는 suspend 상태로 들어가는 것을 취소하고 모든 프로세스의 프리징을 해제한다.

/-*
 * suspend_prepare - Do prep work before entering low-power state.
 *
 * This is common code that is called for each state that we're entering.
 * Run suspend notifiers, allocate a console and stop all processes.
 *-
static int suspend_prepare(void)
{
    int error;

    if (!suspend_ops || !suspend_ops->enter)
        return -EPERM;

    pm_prepare_console();

    error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
    if (error)
        goto Finish;

    error = usermodehelper_disable();
    if (error)
        goto Finish;

    error = suspend_freeze_processes();
    if (!error)
        return 0;

    suspend_thaw_processes();
    usermodehelper_enable();
    Finish:
    pm_notifier_call_chain(PM_POST_SUSPEND);
    pm_restore_console();
    return error;
}

Suspend Devices
이 제 모든 프로세스(process/workqueue/kthread)가 멈췄고 이 프로세스들은 lock된 세마포어를 가지고 있을 것이다. 이 때 드라이버의 suspend 함수에서 프로세스를 기다리고 있다면 데드락이 발생한다. 그리고 커널은 나중을 위하여 어느 정도의 메모리 공간을 free한다. 마지막으로 모든 장치를 suspend하기 위하여 suspend_devices_and_enter()를 호출한다. 이 함수에서는 시스템에 suspend_ops->begin()가 있는 경우 suspend_ops->begin() 함수를 호출하고 driver/base/power/main.c의 dpm_suspend() 함수를 호출한다. dpm_suspend() 함수에서는 device_suspend() 함수를 호출하여모든 non-sysdev 장치의 suspend 콜백 함수를 호출한다. 다시 suspend_devices_and_enter() 함수로 돌아와서 suspen_enter()를 호출한다. 이 함수에서는 시스템과 관련된 준비를 하기 위해 suspend_ops->prepare()를 호출하고 레이스 컨디션을 피하기 위해 nonboot CPU를 비활성화 한다. 이 과정을 마치면 단 한개의 cpu만 실행이 되는 상태가 된다. suspend_ops는 시스템 관련 전원 관리 함수를 묶어놓은 스트럭쳐로 일반적으로 arch/xxx/mach-xxx/pm.c에서 등록된다. arch_suspend_disable_irqs() 함수를 호출하여 IRQ가 비활성화하고, sysdev_suspend() 함수를 호출하여 모든 시스템 장치를 suspend한다. 이 때 /sys/devices/system/ 위치의 모든 시스템 디바이스가 suspend된다. 마지막으로 suspend_ops->enter() 함수가 호출되는데, cpu가 파워 세이브 모드로 진입하고 시스템의 동작이 여기서 모두 멈춘다(당연히 모든 코드 수행이 여기에서 멈추게 된다).

/-*
 * suspend_devices_and_enter - suspend devices and enter the desired system
 *        sleep state.
 * @state:    state to enter
 *-
int suspend_devices_and_enter(suspend_state_t state)
{
    int error;
    gfp_t saved_mask;

    if (!suspend_ops)
        return -ENOSYS;

    if (suspend_ops->begin) {
        error = suspend_ops->begin(state);
        if (error)
            goto Close;
    }
    suspend_console();
    saved_mask = clear_gfp_allowed_mask(GFP_IOFS);
    suspend_test_start();
    error = dpm_suspend_start(PMSG_SUSPEND);
    if (error) {
        printk(KERN_ERR "PM: Some devices failed to suspend\n");
        goto Recover_platform;
    }
    suspend_test_finish("suspend devices");
    if (suspend_test(TEST_DEVICES))
        goto Recover_platform;

    suspend_enter(state);

    Resume_devices:
    suspend_test_start();
    dpm_resume_end(PMSG_RESUME);
    suspend_test_finish("resume devices");
    set_gfp_allowed_mask(saved_mask);
    resume_console();
    Close:
    if (suspend_ops->end)
        suspend_ops->end();
    return error;

    Recover_platform:
    if (suspend_ops->recover)
        suspend_ops->recover();
    goto Resume_devices;
}


Resume
만 약 시스템이 인터럽트 혹은 다른 이벤트에 의해 깨어나면 코드의 수행이 다시 시작한다. 가장 먼저 resume되는 것은 /sys/devices/system/ 위치에 있는 장치들이다(sysdev_resume()). 그리고 IRQ를 활성화하고(arch_suspend_enable_irqs()) nonboot CPU를 활성화한 후(enable_nonboot_cpus()) 시스템 resume이 시작되었다는 것을 알리기 위해 suspend_ops->wake() 함수와 suspend_ops->finish() 함수를 호출한다. suspend_devices_and_enter() 함수에서 모든 장치를 깨우기 위해 dpm_resume_end() 함수를 호출하여 모든 장치의 resume() 함수를 호출하고 콘솔을 resume 하며 마지막으로 suspend_ops->end()를 호출한다. 다시 enter_state() 함수로 돌아오면 suspend_devices_and_enter() 함수를 빠져나와 장치가 실행되는 상태이지만 user space의 프로세스와 태스크들은 여전히 프리즈된 상태이다. enter_state() 함수는 나중에 suspend_finish() 함수를 호출하여 프로세스를 깨우고(suspend_thaw_processes()) user 모드 헬퍼를 활성화하며(usermodehelper_enable()) 모든 pm에 suspend 단계에서 빠져나왔다는 것을 알린 후(pm_notifier_call_chain) 콘솔을 복구(restore)한다.
이 단계가 일반적인 리눅스의 suspend와 resume가 실행되는 과정이다.



안드로이드 Suspend
안 드로이드용으로 패치된 커널에서는 Suspend가 되기 전(enter_state() 함수를 호출하기 전)에 kernel/power/earlysuspend.c 파일의 request_suspend_state()함수를 호출한다(안드로이드는 Early Suspend와 Wake Lock 기능을 커널에 추가했다). 이를 좀 더 자세한 이해를 위해 먼저 안드로이드가 추가한 새로운 기능에 대해서 소개하겠다.

파일:
   - linux_source/kernel/power/main.c
   - linux_source/kernel/power/earlysuspend.c
   - linux_source/kernel/power/wakelock.c
 
기능
Early Suspend
Early Suspend는 안드로이드가 리눅스 커널에 새로 추가한 메커니즘이다. Early Suspend는 리눅스의 '진짜' Suspend와 LCD 스크린 오프의 사이에 존재하는 상태이다. LCD 스크린을 끄면 배터리 수명과 몇몇 기능적인 요구사항에 의해 LCD 백라이트나 G-Sensor, 터치스크린 등이 멈추게 된다.



Late Resume
Late Resume은 Early Suspend와 쌍을 이루는 메커니즘으로 커널과 시스템 Resume이 끝난 후 수행이 된다. 이 때 Early Suspend에서 Suspend된 장치들이 Resume하게 된다.



Wake Lock
Wake Lock은 안드로이드 전원 관리 시스템의 핵심을 이루는 기능이다. Wake Lock은 kernel space 혹은 user space의 서비스나 어플리케이션에서 lock을 잡고 있는 경우(timeout lock이거나 timeout lock이 아니거나)에 시스템은 Sleep 상태로 진입할 수 없도록 막는다. timeout lock은 설정한 시간이 되면 자동으로 lock이 풀리고 안드로이드용으로 패치된 리눅스 커널(이하 안드로이드 커널)은 리눅스 Suspend(pm_suspend())를 불러 전체 시스템을 Suspend시킨다.



안드로이드 Suspend
사 용자가 /sys/power/state에 "mem"이나 "standby"를 write하면 state_store()가 호출된다. 그리고 request_suspend_state() 함수로 들어온다. 이 함수에서 상태를 검사하고 Suspend 요청인 경우 early_suspend_work->early_suspend()를 큐에 넣는다.

void request_suspend_state(suspend_state_t new_state)
{
    unsigned long irqflags;
    int old_sleep;

    spin_lock_irqsave(&state_lock, irqflags);
    old_sleep = state & SUSPEND_REQUESTED;
    if (debug_mask & DEBUG_USER_STATE) {
        struct timespec ts;
        struct rtc_time tm;
        getnstimeofday(&ts);
        rtc_time_to_tm(ts.tv_sec, &tm);
        pr_info("request_suspend_state: %s (%d->%d) at %lld "
            "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
            new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
            requested_suspend_state, new_state,
            ktime_to_ns(ktime_get()),
            tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
            tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
    }
    if (!old_sleep && new_state != PM_SUSPEND_ON) {
        state |= SUSPEND_REQUESTED;
        queue_work(suspend_work_queue, &early_suspend_work);
    } else if (old_sleep && new_state == PM_SUSPEND_ON) {
        state &= ~SUSPEND_REQUESTED;
        wake_lock(&main_wake_lock);
        queue_work(suspend_work_queue, &late_resume_work);
    }
    requested_suspend_state = new_state;
    spin_unlock_irqrestore(&state_lock, irqflags);
}

Early Suspend
early_suspend() 함수에서는 먼저 요청한 상태를 검사하는데, 요청한 상태가 Suspend(SUSPEND_REQUESTED)인 경우 Suspend 취소 요청을 막기 위해 상태를 Suspend로 변경한다(user 프로세스가 여전히 동작하고 있기 때문에). 그리고 early suspend에 등록된 모든 핸들러의 suspend() 함수를 호출한다. 그 다음 파일 시스템을 sync하고 main_wake_lock을 푼다(unlock).

static void early_suspend(struct work_struct *work)
{
    struct early_suspend *pos;
    unsigned long irqflags;
    int abort = 0;

    mutex_lock(&early_suspend_lock);
    spin_lock_irqsave(&state_lock, irqflags);
    if (state == SUSPEND_REQUESTED)
        state |= SUSPENDED;
    else
        abort = 1;
    spin_unlock_irqrestore(&state_lock, irqflags);

    if (abort) {
        if (debug_mask & DEBUG_SUSPEND)
            pr_info("early_suspend: abort, state %d\n", state);
        mutex_unlock(&early_suspend_lock);
        goto abort;
    }

    if (debug_mask & DEBUG_SUSPEND)
        pr_info("early_suspend: call handlers\n");
    list_for_each_entry(pos, &early_suspend_handlers, link) {
        if (pos->suspend != NULL)
            pos->suspend(pos);
    }
    mutex_unlock(&early_suspend_lock);

    if (debug_mask & DEBUG_SUSPEND)
        pr_info("early_suspend: sync\n");

    sys_sync();
abort:
    spin_lock_irqsave(&state_lock, irqflags);
    if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
    {
#ifndef CONFIG_EARLY_SUSPEND_ONLY
        wake_unlock(&main_wake_lock);
#endif /- EARLY_SUSPEND_ONLY *-
    }
    spin_unlock_irqrestore(&state_lock, irqflags);
}

 

Late Resume
모든 커널 Resume 과정을 마치면 user space의 프로세스와 서비스가 실행된다. 시스템이 깨어나는 경우는 다음과 같다.

  - 전화가 왔을 때
   전화가 오면 모뎀은 rild(RING 명령)로 명령을 모내고 rild는 Call 이벤트 처리를 위하여 WindowManager와 어플리케이션으로 이벤트 메시지를 보낸다. PowerManagerSerive는 또한 /sys/power/state에 "on"을 write하여 커널이 Late Resume을 수행하도록 한다.

  - 키 이벤트
   시스템이 파워키나 메뉴키 등의 키 이벤트에 의해 깨어난 경우 이벤트는 WindowManaver와 어플리케이션으로 보내지고 해당 이벤트를 처리한다. 키 이벤트는 두 가지 경우로 나눌 수 있는데 만약 리턴 키나 홈 키와 같이 시스템을 깨울 수 있는 키가 아닌 경우 WindowManager는 Wake Lock을 풀어 다시 시스템이 Suspend로 돌아가도록 한다. 반면에 키 이벤트가 시스템을 깨울 수 있는 키인 경우 WindowManager는 PowerManagerService를 호출하여 Late Resume을 수행할 수있도록 한다.


  - Late Resume은 Early Suspend 장치 리스트의 resume 함수를 호출한다.

static void late_resume(struct work_struct *work)
{
    struct early_suspend *pos;
    unsigned long irqflags;
    int abort = 0;

    mutex_lock(&early_suspend_lock);
    spin_lock_irqsave(&state_lock, irqflags);
    if (state == SUSPENDED)
        state &= ~SUSPENDED;
    else
        abort = 1;
    spin_unlock_irqrestore(&state_lock, irqflags);

    if (abort) {
        if (debug_mask & DEBUG_SUSPEND)
            pr_info("late_resume: abort, state %d\n", state);
        goto abort;
    }
    if (debug_mask & DEBUG_SUSPEND)
        pr_info("late_resume: call handlers\n");
    list_for_each_entry_reverse(pos, &early_suspend_handlers, link)
        if (pos->resume != NULL)
            pos->resume(pos);
    if (debug_mask & DEBUG_SUSPEND)
        pr_info("late_resume: done\n");
abort:
    mutex_unlock(&early_suspend_lock);
}


기존 리눅스 Suspend와 다른 점
안드로이드에서도 pm_suspend()가 enter_state()를 호출하여 suspend 상태가 되지만 기존 리눅스 커널의 suspend 과정과 100% 동일하지는 않다:
프로세스를 Freezing할 때 안드로이드는 wake lock이 있는지 확인하고, wake lock이 있는 경우 suspend 과정이 실행되지 않는다.



추가 참고 자료

Wake Lock 관련: http://www.kandroid.org/online-pdk/guide/power_management.html#androidPowerWakeLocks
RIL 관련: http://www.kandroid.org/board/board.php?board=AndroidLib&command=body&no=41

[펌] ODROID

1

How to fix problem of incompatibility between GCC 4.6 and Android 2.3 (Gingerbread)

Posted: May 27, 2011 by buildall in Android, Ubuntu
Tags: , ,
2
 
 
 
 
 
 
12 Votes

Hello everybody. Let’s see how we can fix one problem that can happen when you try to compile the Android 2.3 after you already have installed GCC 4.6.

During Android compilation you can receive the following error message:

host Executable: acp (out/host/linux-x86/obj/EXECUTABLES/acp_intermediates/acp)
host SharedLib: libneo_cs (out/host/linux-x86/obj/lib/libneo_cs.so)
host C++: libutils <= frameworks/base/libs/utils/RefBase.cpp
frameworks/base/libs/utils/RefBase.cpp: In member function ‘void android::RefBase::weakref_type::trackMe(bool, bool)’:
frameworks/base/libs/utils/RefBase.cpp:483:67: error: passing ‘const android::RefBase::weakref_impl’ as ‘this’ argument of ‘void android::RefBase::weakref_impl::trackMe(bool, bool)’ discards qualifiers [-fpermissive]
make: *** [out/host/linux-x86/obj/STATIC_LIBRARIES/libutils_intermediates/RefBase.o] Error 1
make: *** Waiting for unfinished jobs....

To fix that, open a terminal and run (assuming you are in the folder android):

gedit frameworks/base/libs/utils/Android.mk

Change the line:

LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)

To:

LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS) -fpermissive

After that, save the file and recompile the Android again.

That’s it. See you next time.



2

out/host/linux-x86/obj/STATIC_LIBRARIES/libcutils_intermediates/libcutils.a(threads.o): In function `thread_store_get"":

/home/leno/works/android_dev/bin/system/core/libcutils/threads.c:27: undefined reference to `pthread_getspecific""

out/host/linux-x86/obj/STATIC_LIBRARIES/libcutils_intermediates/libcutils.a(threads.o): In function `thread_store_set"":

/home/leno/works/android_dev/bin/system/core/libcutils/threads.c:36: undefined reference to `pthread_key_create""

/home/leno/works/android_dev/bin/system/core/libcutils/threads.c:44: undefined reference to `pthread_setspecific""

collect2: ld returned 1 exit status

make: *** [out/host/linux-x86/obj/EXECUTABLES/localize_intermediates/localize]

批改./framework/base/tools/localize/Android.mk文件

ifeq (¥(HOST_OS),linux)

#LOCAL_LDLIBS += -lrt       把这行注释掉,改为下面一行。

LOCAL_LDLIBS += -lrt -lpthread

endif


3

host utable: aapt (out/host/linux-x86/obj/EXECUTABLES/aapt_intermediates/aapt)

out/host/linux-x86/obj/STATIC_LIBRARIES/libcutils_intermediates/libcutils.a(threads.o): In function `thread_store_get"":

/home/leno/works/android_dev/bin/system/core/libcutils/threads.c:27: undefined reference to `pthread_getspecific""

out/host/linux-x86/obj/STATIC_LIBRARIES/libcutils_intermediates/libcutils.a(threads.o): In function `thread_store_set"":

/home/leno/works/android_dev/bin/system/core/libcutils/threads.c:36: undefined reference to `pthread_key_create""

/home/leno/works/android_dev/bin/system/core/libcutils/threads.c:44: undefined reference to `pthread_setspecific""

collect2: ld returned 1 exit status

make: *** [out/host/linux-x86/obj/EXECUTABLES/aapt_intermediates/aapt] 错误 1

解决:

打开 frameworks/base/tools/aapt/Android.mk

然后打开文件Android.mk,编辑下面一行:

ifeq (¥(HOST_OS),linux)

#LOCAL_LDLIBS += -lrt       把这行注释掉,改为下面一行。

LOCAL_LDLIBS += -lrt -lpthread



4
    <command-line>:0:0: error: "_FORTIFY_SOURCE" redefined [-Werror]
    <built-in>:0:0: note: this is the location of the previous definition
    cc1plus: all warnings being treated as errors

error: "_FORTIFY_SOURCE" redefined [-Werror]


build/core/combo/HOST_linux-x86.mk line 61: #HOST_GLOBAL_CFLAGS += -D_FORTIFY_SOURCE=0 HOST_GLOBAL_CFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0



Android.mk 파일에 다음을 넣어 준다.

LOCAL_PRELINK_MODULE:=false
[펌] http://www.androidpub.com/3715

전체 소스를 http://source.android.com/download 에서 하라는데로 다운로드 받고 한번 빌드하는 것까지는 다들 쉽게 따라하셨을 것이라 생각합니다. 그 이후에 특정부분만 다시 빌드하고 싶을 때는 다시 make를 할 필요없이 mmm이라는 커맨드를 사용하면 됩니다. 

$. build/envsetup.sh
을 실행한 후

$ mmm packages/apps/Contacts
와 같이 시행하면 Contacts부분만 다시 빌드됩니다. Android.mk가 존재하는 Path만 적용할 수 있습니다.

$ make snod
를 실행하면 위에서 빌드한 Contacts를 적용한 system.img 를 다시 빠르게 생성합니다.

그리고 한글등이 들어갈 때 utf8 인코딩을 쓰게는데 안드로이드 플랫폼 소스 빌드시에 javac가 ascii 인코딩으로 설정되어있습니다.

build/core/definitions.mk 에서 -encoding ascii 를 -encoding utf8로 바꿔주면 됩니다. utf8 소스도 사용할 수 있습니다.

그리고 mmm과 별도로
$make sdk
를 통해 SDK를 만들 수 있습니다.


안드로이드의 BlueTooth는 1.5, 1.6버젼에서는 A2DP, AVRCP(AV Remote Control), HSP(Headset), HFP(Hands Free) 정도만 지원했다. 안드로이드 2.0 버젼부터 OOP(Push Profile), PBAP(Phone Book Access Profile) 등을 지원한다고 한다.

안드로이드에서 BlueTooth를 사용하려면 Vendor에서 정의하는 BoardConfig.mk에서 BOARD_HAVE_BLUETOOTH를 true로 설정해야 한다.

 

기본 구조에 대하여 참고할만한 곳은 다음과 같다.

http://sites.google.com/a/android.com/opensource/projects/bluetooth-faq

기본 구조

system server 와  BlueZ 와의 인터페이스를 담당하는 D-Bus는 다음을 참고한다.

http://www.freedesktop.org/wiki/Software/dbus

http://daeji.tistory.com/entry/D-BUS

http://bebop.emstone.com/research/tech/dbus/dbus_overview

아직 확실하지는 않지만

BT Power on/off 를 담당하는 소스는 다음 파일 같다.

system/bluetooth/bluedroid/bluetooth.c

실제 하드웨어를 컨트롤하는 부분은 보이지 않으며 함수 Call에 따라 내부 설정 등을 변경해 놓는다.

하드웨어 컨트롤 관련된 부부은 2.01에서는 별도로 추가된 것으로 보이며 이는 1.6 버젼까지는 이 쪽에 대충 떄려 넣어야 할 것 같다.

Make파일을 보면 공유 라이브러리 libbluedroid.so 파일로 만든다.

이 라이브러리는 Java에서 사용 가능하도록 다음에서 라이브러리를 정의한다.

frameworks/base/core/jni/Android.mk

이를 보면 결론적으로 BlueTooth와 관련된 JNI 관련 파일은 다음 세 파일이다.

android_server_BlueToothA2dpService.cpp

android_server_BlueToothDeviceService.cpp

android_server_BlueToothEventLoop.cpp

그 외 파일들은

android_bluetooth_Database.cpp

android_bluetooth_HeadsetBase.cpp

android_bluetooth_common.cpp

dbus 관련 함수

android_bluetooth_BluetoothAudioGateway.cpp

* android_bluetooth_RfcommSocket.cpp

* android_bluetooth_BluetoothSocket.cpp

socket 통신 관련 (write, read, ...)

android_bluetooth_ScoSocket.cpp

Sco socket 통신 관련 (init, connect, accept, close ...)

당연한 얘기지만 BlueTooth의 A2DP, HSP, HFP 등을 사용하면 오디오 출력에 영향을 미치므로

framework/base/libs/audioflinger 쪽도 영향을 받는다.

BlueZ에 대한 소스는 external/bluez 에 있다.

참고할만한 기사

http://ko.broadcom.com/press/release.php?id=s363853

 

 

 

원본 위치 http://blog.daum.net/baramjin/16011028


** android 컴파일 후 마지막에 다음과 같은 메세지가 나오면 uboot-mkimage 를 설치하지 않아서 이다.

mkimage: 명령어를 찾을 수 없음


다음과 같이 설치 할 수 있다.
sudo apt-get install uboot-mkimage

[Guide] Building Android 2.3.4 on Ubuntu 11.04 (64 bit)

As promised my how-to for building Android 2.3.4 on Ubuntu 11.04 (64 bit). I found out that building Android changed a bit since Ubuntu 11.04 and the documentation on the Android source site isn't up to date. This is why i choose to write down the steps i did to build Android 2.3.4. So, go grab yourself a Red Bull and let's get ready to rumble!

What do you need?

Ubuntu 11.04 (64 bit), a internet connection & if your building for a phone.. The phone.

Preparing Ubuntu:

Fire up a terminal, and download the following packages to start with:

sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev libc6-dev g++-multilib lib32ncurses5-dev ia32-libs x11proto-core-dev libx11-dev lib32readline5-dev lib32z-dev libgl1-mesa-dev

Now make sure your using the right version of Java:

sudo add-apt-repository "deb http://archive.canonical.com/ maverick partner"
sudo add-apt-repository "deb-src http://archive.canonical.com/ubuntu maverick partner"
sudo apt-get update
sudo apt-get install sun-java6-jdk

You just downloaded all the software needed to build Android.

Make sure that your Ubuntu machine can use your USB devices by creating /etc/udev/rules.d/51-android.rules (as root user) paste the following inside that file:

# adb protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e12", MODE="0600", OWNER="<username>"
# fastboot protocol on passion (Nexus One)
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", ATTR{idProduct}=="0fff", MODE="0600", OWNER="<username>"
# adb protocol on crespo (Nexus S)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e22", MODE="0600", OWNER="<username>"
# fastboot protocol on crespo (Nexus S)
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", ATTR{idProduct}=="4e20", MODE="0600", OWNER="<username>"

Please make sure to switch "<username>" to the username of your Ubuntu user.

Now it's time to download the repo and stuff like that. In the same terminal type:

mkdir ~/bin
curl http://android.git.kernel.org/repo > ~/bin/rep

Now open up your bashrc (nano ~/.bashrc) and add the following to the end:

PATH=$PATH:$HOME/bin

Save the file and source it:

source ~/.bashrc

Getting the source:

Now, make a directory where you would like to build Android. I always keep my system clean so i made a Android/source/Gingerbread folder:

mkdir -p ~/Android/source/Gingerbread

Now go to that directory:

cd ~/Android/source/Gingerbread

Now let the repository initialize:

repo init -u git://android.git.kernel.org/platform/manifest.git -b gingerbread

android.git.kernel.org 가 막혀 있다면 아래 사이트를 이용하면 된다.
repo init -u https://android.googlesource.com/platform/manifest -b gingerbread

And next sync it. This will take a while :-) :

repo sync

You now have the source code of Gingerbread on your Ubuntu machine. Sweet! Of course, you still have to build it.

Building the source:

First i will explain how to build a normal generic build. This is a non phone specific build. In the Android source folder type:

. build/envsetup.sh

This will prepare your build environment. This is needed to have tools like lunch, mmm and other nifty Android specific tools. Now it's time to actually choose our version of 2.3.4:

lunch

You will be asked which Android version you want, choose "generic". Now! It's time for the real deal, building the source. It's time to fire up make:

make -j4

Do note that there are diffrent -j parameters of make to build faster. You could use make -j4 if you have 2 cores, and make -j8 if you have 4. This will speed up the building.

If the building ends with something like system.img that the build went ok. Congratulations you've just build Android 2.3.4. You can flash it to your phone with fastboot. But this is just a generic build missing device specific features.

Building the source for the Nexus One:

Connect your phone to your PC, and make sure that it's on debugging mode. From the root of your source, go to the Passion (code name for Nexus One) specific folder:

cd device/htc/passion

Import all the needed files:

./extract-files.sh

If this ends with no errors your done, you can now return to the root of your source tree. If you followed this how to go back to:

~/Android/source/Gingerbread

Now use lunch to choose the passion-full-userdebug build.

lunch

And! Now you can use make to build Android:

make -j4

If your build ends with something like this:

Install system fs image: out/target/product/passion/system.img

The build is complete. You can again use fastboot to flash it to your device. You now have the full open source version of Android running on your phone.

If you have any questions about this topic please don't hesitate to ask them in the comments i'll do my best to give answers when possible.

deb http://kr.archive.ubuntu.com/ubuntu 이 사이트는 오래 전에 막혔다.
따라서 /etc/apt/sources.list에서
deb http://kr.archive.ubuntu.com/ubuntu 등을  주석처리 하고 아래와 같이 다음 사이트로 변경한다.
한 네티즌의 댓글로 ftp.daum.net 에서 old-releases.ubuntu.com으로 변경

#################다음 저장소 #####################
#deb http://ftp.daum.net/ubuntu maverick main multiverse restricted universe
#deb-src http://ftp.daum.net/ubuntu maverick main multiverse restricted universe
#deb http://ftp.daum.net/ubuntu maverick-backports main multiverse restricted universe
#deb-src http://ftp.daum.net/ubuntu maverick-backports main multiverse restricted universe
#deb http://ftp.daum.net/ubuntu maverick-proposed main multiverse restricted universe
#deb-src http://ftp.daum.net/ubuntu maverick-proposed main multiverse restricted universe
#deb http://ftp.daum.net/ubuntu maverick-security main multiverse restricted universe
#deb-src http://ftp.daum.net/ubuntu maverick-security main multiverse restricted universe
#deb http://ftp.daum.net/ubuntu maverick-updates main multiverse restricted universe
#deb-src http://ftp.daum.net/ubuntu maverick-updates main multiverse restricted universe
##################################################


##################### old-releases ######################

deb http://old-releases.ubuntu.com/ubuntu/ intrepid main restricted
deb-src http://old-releases.ubuntu.com/ubuntu/ intrepid main restricted

#deb http://kr.archive.ubuntu.com/ubuntu/ intrepid main restricted
#deb-src http://kr.archive.ubuntu.com/ubuntu/ intrepid main restricted

## Major bug fix updates produced after the final release of the
## distribution.

deb http://old-releases.ubuntu.com/ubuntu/ intrepid-updates main restricted
deb-src http://old-releases.ubuntu.com/ubuntu/ intrepid-updates main restricted

#deb http://kr.archive.ubuntu.com/ubuntu/ intrepid-updates main restricted
#deb-src http://kr.archive.ubuntu.com/ubuntu/ intrepid-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.

deb http://old-releases.ubuntu.com/ubuntu/ intrepid universe
deb-src http://old-releases.ubuntu.com/ubuntu/ intrepid universe
deb http://old-releases.ubuntu.com/ubuntu/ intrepid-updates universe
deb-src http://old-releases.ubuntu.com/ubuntu/ intrepid-updates universe

#deb http://kr.archive.ubuntu.com/ubuntu/ intrepid universe
#deb-src http://kr.archive.ubuntu.com/ubuntu/ intrepid universe
#deb http://kr.archive.ubuntu.com/ubuntu/ intrepid-updates universe
#deb-src http://kr.archive.ubuntu.com/ubuntu/ intrepid-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.

deb http://old-releases.ubuntu.com/ubuntu/ intrepid multiverse
deb-src http://old-releases.ubuntu.com/ubuntu/ intrepid multiverse
deb http://old-releases.ubuntu.com/ubuntu/ intrepid-updates multiverse
deb-src http://old-releases.ubuntu.com/ubuntu/ intrepid-updates multiverse

#deb http://kr.archive.ubuntu.com/ubuntu/ intrepid multiverse
#deb-src http://kr.archive.ubuntu.com/ubuntu/ intrepid multiverse
#deb http://kr.archive.ubuntu.com/ubuntu/ intrepid-updates multiverse
#deb-src http://kr.archive.ubuntu.com/ubuntu/ intrepid-updates multiverse

## Uncomment the following two lines to add software from the 'backports'
## repository.
## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
# deb http://kr.archive.ubuntu.com/ubuntu/ intrepid-backports main restricted universe multiverse
# deb-src http://kr.archive.ubuntu.com/ubuntu/ intrepid-backports main restricted universe multiverse

## Uncomment the following two lines to add software from Canonical's
## 'partner' repository. This software is not part of Ubuntu, but is
## offered by Canonical and the respective vendors as a service to Ubuntu
## users.
# deb http://archive.canonical.com/ubuntu intrepid partner
# deb-src http://archive.canonical.com/ubuntu intrepid partner


deb http://old-releases.ubuntu.com/ubuntu intrepid-security main restricted
deb-src http://old-releases.ubuntu.com/ubuntu intrepid-security main restricted
deb http://old-releases.ubuntu.com/ubuntu intrepid-security universe
deb-src http://old-releases.ubuntu.com/ubuntu intrepid-security universe
deb http://old-releases.ubuntu.com/ubuntu intrepid-security multiverse
deb-src http://old-releases.ubuntu.com/ubuntu intrepid-security multiverse


#deb http://security.ubuntu.com/ubuntu intirepid-security main restricted
#deb-src http://security.ubuntu.com/ubuntu intrepid-security main restricted
#deb http://security.ubuntu.com/ubuntu intrepid-security universe
#deb-src http://security.ubuntu.com/ubuntu intrepid-security universe
#deb http://security.ubuntu.com/ubuntu intrepid-security multiverse
#deb-src http://security.ubuntu.com/ubuntu intrepid-security multiverse

########################################################


deb http://extras.ubuntu.com/ubuntu maverick main
deb-src http://extras.ubuntu.com/ubuntu maverick main

deb http://security.ubuntu.com/ubuntu maverick-security main restricted
deb-src http://security.ubuntu.com/ubuntu maverick-security main restricted
deb http://security.ubuntu.com/ubuntu maverick-security universe
deb-src http://security.ubuntu.com/ubuntu maverick-security universe
deb http://security.ubuntu.com/ubuntu maverick-security multiverse
deb-src http://security.ubuntu.com/ubuntu maverick-security multiverse

1. Android build 스크립 수정하기

.build/core/main.mk

파일을 여시면

75 ifeq ($(BUILD_OS),linux)
76 build_arch := $(shell uname -m)
77 ifneq (64,$(findstring 64,$(build_arch)))
78 $(warning ************************************************************)
79 $(warning You are attempting to build on a 32-bit system.)
80 $(warning Only 64-bit build environments are supported beyond froyo/2.2.)
81 $(warning ************************************************************)
82 $(error stop)
83 endif
84 endif

이 부분을 주석 처리 해주시고 저장 후 파일 닫으시면 됩니다.

    2. Android 스크립 수정하기

우선 Gingerbread 소스를 안드로이드 git에서 받으신 뒤에 

root 디렉토리 기준에서

./external/clearsilver/cgi/Android.mk
./external/clearsilver/java-jni/Android.mk
./external/clearsilver/util/Android.mk
./external/clearsilver/cs/Android.mk

위 파일을 여신 뒤

# LOCAL_CFLAGS += -m64
# LOCAL_LDFLAGS += -m64

부분에 있는 64를 32로 변경 하신 뒤 저장 하시면 됩니다.

저장이 끝나면 root 디렉토리에서 make -j3 를 하시면 됩니다.

에뮬레이터를 만들고 싶으신 경우엔 make -j3 로 빌드를 다 하고 난 뒤

make sdk 를 치시면 됩니다.
제 경우 32bits 머신에서 빌드하려다보니, 64bits 머신을 사용하라는 에러가 발생하네요..

32bits 머신에서 빌드하는 방법을 구글링해봤습니다. 덕분에 잘 빌드되네요.

1) /build/core/main.mk 수정
-ifneq (64,$(findstring 64,$(build_arch))) 
+ifneq (i686,$(findstring i686,$(build_arch)))

2) /external/clearsilver/ 내 Android.mk 수정
-LOCAL_CFLAGS += -m64 

참조URL: http://groups.google.com/group/android-platform/browse_thread/thread/b0bb991131589363


본 : http://www.kandroid.org/board/board.php?board=androidsource&command=body&no=72


일단 공식 홈페이지는 아래와 같다.

 

http://www.android-x86.org/

 

초기에 비하면 꽤 많은 진척이 있는 것 같다.

Virtual Box로도 동작 확인이 가능하며, Eclair, Froyo, Ginger-Bread 까지 빠르게 포팅 작업이 이루어 지고 있는 것 같다.

 

테스트 플랫폼도 EeePC, Samsung Q1U, Viliv S5, Lenovo ThinkPad x61 Tablet, ViewSonic ViewPad 10 등이 있다.

 

넷북에서의 사용을 목적으로 하기 때문에 기존 안드로이드와 다르게 추가된 내용은 다음과 같다.

 

- Wifi 와 Ethernet 지원

- Mouse cursor/wheel 지원

- native resolution 지원 (800x480 과 1024x600 지원)

- Proxy setting 지원

- Mplayer 포팅

- External storage auto mount support (Virtual Box로는 아무 변화가 없는 듯)

- External monitor support (해야하는 일로 되어 있어서 좀 더 확인해 봐야 할듯)

 

Virtual Box로는 OpenGL 지원이 제대로 되는지 모르겠다. Live Wallpaper 설정시, 일부는 정상 동작하고 일부는 동작이 조금 이상하게 나온다.

 

Atom 기반으로 되어 있기 때문에 최적화나 시스템 부하는 고려하지 않는 점이 있어서 ARM 기반으로 포팅시에는 주의가 필요하다.

 

코드 받으려면 다음과 같이 한다.

 

$repo init –u git://git.android-x86.org/manifest.git –b $branch
$repo sync

 

branch 명은 donut-x86, eclair-x86, froyo-x86, gingerbread-x86 이다.

오늘 해 볼 작업은 WebView 입니다. 웹기반 어플리케이션이라고 보면 되고 완성될 화면은 아래와 같습니다.

Daum의 모바일 웹페이지 프론트 페이지입니다. 맨 아래 하단에는 버튼을 두어서 원하는 곳으로 이동도 해 볼 겁니다.


 

Daum의 모바일용 웹페이지를 호출한 화면입니다.

웹브라우져 객체를 담기 위해 webview 를 아래 버튼을 만들기 위해 button 을 이용합니다.



1. 프로젝트 생성
 HelloWebView



2. Main.xml 코딩

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
 
 <LinearLayout
 android:orientation="vertical"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:layout_weight="1">
 
  <WebView
  android:id="@+id/webview"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"/>
 
 </LinearLayout>
 
 <LinearLayout
 android:orientation="horizontal"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent"
 android:layout_weight="8">
 
  <Button
  android:id="@+id/Button01"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Home"
  android:layout_weight="1"
  android:textSize="8pt"/>
 
   <Button
   android:id="@+id/Button02"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Portal"
  android:layout_weight="1"
  android:textSize="8pt"/>
 
   <Button
   android:id="@+id/Button03"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Close"
  android:layout_weight="1"
  android:textSize="8pt"/>
 
 </LinearLayout>
 
</LinearLayout>

위 처럼 코딩 하시면 화면 구성은 끝납니다. 화면에 구성에 필요한 부분은 별도로 공부 하시면 도움이 많이 될겁니다. 별도로 포스트 할 예정입니다.



3. HellowWebView.java 코딩

package com.sample.HelloWebView;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;

public class HelloWebView extends Activity {
 private static final String URL1="http://m.daum.net/mini";
 private static final String URL2="http://m.naver.com";
 WebView webview;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    
        webview = (WebView) findViewById(R.id.webview);
        webview.getSettings().setJavaScriptEnabled(true);
        webview.loadUrl(URL1);

       
        webview.setWebViewClient(new HelloWebViewClient());
       
        Button b1 = (Button)findViewById(R.id.Button01);
        Button b2 = (Button)findViewById(R.id.Button02);
        Button b3 = (Button)findViewById(R.id.Button03);
       
        b1.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
          webview = (WebView) findViewById(R.id.webview);
          webview.getSettings().setJavaScriptEnabled(true);
          webview.loadUrl(URL1);
          webview.setWebViewClient(new HelloWebViewClient());
   }
  });
       
        b2.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
          webview = (WebView) findViewById(R.id.webview);
          webview.getSettings().setJavaScriptEnabled(true);
          webview.loadUrl(URL2);
          webview.setWebViewClient(new HelloWebViewClient());
   }
  });
       
       
        b3.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    finish();
   }
  });
    }
       
   
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) {
            webview.goBack();
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
   
    private class HelloWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    }
}

다소 복잡해 보이지만 자동 완성 기능이 있으므로 어렵지 않습니다. 안드로이드는 자바와 XML로 구성되어 있다고 보면 됩니다. 특히 자바의 기초적인 부분을 잘 이해 하고 계시다면 개발은 어렵지 않을 거란 생각이 드네요.



4. 애플리케이션 훝어보기
 

 

Portal 버튼을 눌러 네이버로 이동한 화면입니다. 다시 Home 버튼을 누르면 다음으로 이동합니다. Close 는 화면을 종료하며 finish() 함수를 호출하여 간단하게 애플리케이션을 종료 할 수 있습니다.

안드로이드 JNI 에 대하여...


JNI JAVA에서 Native code를 사용할 수 있는 인터페이스이다. 좀 더 쉽게 말하면 CC++로 작성한 API JAVA에서 호출하게 해준다.

 

이를 위해서 framework의 안드로이드 소스 코드 중 service를 보자. (다른 쪽도 이와 유사하게 구현되어 있다.)

 

/framework/base/service/jni

/framework/base/service/java/com/android/server

 

jni 디렉토리의 Android.mk를 보면 libandroid_servers.so를 만들게 된다. 이는 java/com/android/server/SystemServer.java에서 다음과 같이 호출하게 된다.

 

 

    public static void main(String[] args) {

        if (SamplingProfilerIntegration.isEnabled()) {

            SamplingProfilerIntegration.start();

            timer = new Timer();

            timer.schedule(new TimerTask() {

                @Override

                public void run() {

                    SamplingProfilerIntegration.writeSnapshot("system_server");

                }

            }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);

        }

 

        // The system server has to run all of the time, so it needs to be

        // as efficient as possible with its memory usage.

        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

 

        System.loadLibrary("android_servers");

        init1(args);

    }

 

System.loadLibrary에 의해서 libandroid_servers.so가 로드되며 최초로 호출되는 것이 JNI_OnLoad() 이 다. JNI_OnLoad() onload.cpp에서 정의되어 있으며, JNI_OnLoad()가 호출되기 전에 JNI로 정의한 메소드가 호출되어서는 안된다. 이유는 JNI_OnLoad()에서 각각의 서비스가 사용할 수 있는 native code를 등록하기 때문이다. 등록 전에 호출되면 JAVA VM은 관련 함수를 찾을 수 없게 된다. (JNI_OnLoad() System.loadLibrary에 의하여 자동으로 호출되기 때문에 java 파일에서는 호출되는 곳을 찾을 수 없다)

 

 

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

    JNIEnv* env = NULL;

    jint result = -1;

 

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

        LOGE("GetEnv failed!");

        return result;

    }

    LOG_ASSERT(env, "Could not retrieve the env!");

 

    register_android_server_KeyInputQueue(env);

    register_android_server_HardwareService(env);

    register_android_server_AlarmManagerService(env);

    register_android_server_BatteryService(env);

    register_android_server_SensorService(env);

    register_android_server_FallbackCheckinService(env);

    register_android_server_SystemServer(env);

 

    return JNI_VERSION_1_4;

}

 

여기에서 호출한 register 함수를 살펴볼 필요가 있다. Register_android_server_HardwareService()를 본다. jniRegisterNativeMethod()에 의해서 method_table com/android/server/HardwareService에 등록한다는 의미이다. 실제로 com/android/server/를 보면 HardwareService.java 파일이 있다. 위의 의미가 HardwareService.java 파일에 등록한다는 의미는 아니다. HardwareService.java 파일에서 정의한 HardwareService 클래스에 등록하여 사용한다는 의미이다. 이렇게 등록되면 HardwareService 클래스에 서는 method_table에 등록된 native 함수를 호출하여 사용할 수 있다. 당연히 다른 클래스에서는 native 함수를 호출할 수 없다.

 

 

static JNINativeMethod method_table[] = {

    { "init_native", "()I", (void*)init_native },

    { "finalize_native", "(I)V", (void*)finalize_native },

    { "setLight_native", "(IIIIIII)V", (void*)setLight_native },

    { "vibratorOn", "(J)V", (void*)vibratorOn },

    { "vibratorOff", "()V", (void*)vibratorOff }

};

 

int register_android_server_HardwareService(JNIEnv *env)

{

    return jniRegisterNativeMethods(env, "com/android/server/HardwareService",

            method_table, NELEM(method_table));

}

 

한 예로 SystemServer.cpp를 보면 SystemServer, ServerThread, DemoThread가 있다. com_android_server_SystemService.cpp 에서 정의된 gMethods[]에 새로운 native 코드 set_mtd_data를 추가하고 이를 ServerThread에서 호출하려고 하면 컴파일에서는 에러가 나지 않지만 실행 시에 에러가 난다. 이 를 해결하기 위해서는 다음과 같이 호출하여야 한다.

 

SystemServer.set_mtd_data(outputsel, (int)0);

 

 

SystemServer 클래스의 메소드 형태로만 호출이 가능하다.

 

만약 동일한 native 코드를 두개 이상의 독립된 클래스에서 사용하려면 당연한 얘기지만 각각에 대하여 따로 등록해야만 한다.

 

다시 com_android_server_HardwareService.cpp 파일의 method_table[]을 보자. 여기에서는 5개의 native 함수가 등록되어 있다. 첫번째 인자가 실제 java에서 호출되면 함수면이고, 두번째 인자는 입출력 인스턴스의 타입을 정의한다. 세번째 인자는 com_android_server_HardwareService.cpp에서 정의한 JNI 인터페 이스 함수이다.

 

HardwareService.java HardwareService 클래스에서 이를 이용하기 위해서는 native 메소드임을 선언하는 과정이 필요하다.

 

public class HardwareService extends IHardwareService.Stub {

    ……

 

private static native int init_native();

    private static native void finalize_native(int ptr);

 

    private static native void setLight_native(int ptr, int light, int color, int mode,

            int onMS, int offMS, int brightnessMode);

 

    private final Context mContext;

    private final PowerManager.WakeLock mWakeLock;

 

    private final IBatteryStats mBatteryStats;

 

    volatile VibrateThread mThread;

 

    private int mNativePointer;

 

native static void vibratorOn(long milliseconds);

    native static void vibratorOff();

}

 

JNI에서 새로운 native 함 수를 추가했다면 java 코드의 클래스에도 반드시 메소드 정의를 추가한다.

안드로이드 애플리케이션 Life Cycle


♦ 안드로이드 애플리케이션 Life Cycle
대부분의 경우에 안드로이드 애플리케이션은 자신 고유의 리눅스 프로세스에 의해 실행된다. 이 프로세스는 애플리케이션이 특정 코드를 수행할 필요가 있을 때 생성되고, 시스템이 다른 애플리케이션에 사용할 메모리를 요청 또는 더 이상 필요없어질 때까지 실행 상태를 유지한다.
안드로이드의 중요한 특성은 애플리케이션의 프로세스 Life Cycle은 애플리케이션 자신에 의해 직접 컨트롤되지 않는다는 것이다. 그것은 시스템이 실행상태를 알고 있는 애플리케이션 부분들의 조합(얼마나 사용자에게 중요한 것인가, 시스템의 여유 메모리가 얼마나 더 남아있는가)으로 결정된다.
애플리케이션 개발자들이 알아야 할 중요한 사항은 어떻게 서로 다른 애플리케이션 컴포넌트(Activity, Service, IntentReceiver)들이 애플리케이션의 프로세스에 영향을 미치는가 하는 것이다. 이러한 컴포넌트들을 정확하게 사용하지 않을 경우, 시스템은 중요한 일을 하고 있는 애플리케이션의 프로세스를 종료시킬 수 있다.
프로세스 lifecycle 버그의 일반적인 예는 onReceiveIntent() 메소드 내에서 Intent를 받고 함수에서 리턴될 때, IntentReceiver가 스레드를 시작하는 것이다. 한번 리턴되고 나면 시스템은 IntentReceiver를 비활성 상태로 인식하게 되고, 그것을 실행하는 호스팅 프로세스는 다른 애플리케이션 컴포넌트가 그 안에서 활성화 되어 있지 않는 한 필요없어지는 것이다. 그러므로 메모리 요청에 의해 언제든지 프로세스가 종료될 수 있고, 생성되어 실행되던 스레드도 종료된다. 이 문제의 해결법은 IntentReceiver로부터 Service를 실행하는 것이다. 그래서 시스템이 그 프로세스를 종료하기전에 여전히 어떤 작업이 활성화 되어 있음을 인식하게 하는 것이다.
유휴 메모리가 부족할 때 어떤 프로세스가 종료되어야 하는지 결정하는 것은 중요한 것이다. 안드로이드는 이것을 “importance hierarchy”를 베이스로 하고, “Importance hierarchy”내에서 실행중인 컴토넌트와 그 컴포넌트들의 상태에 따라 결정한다. 중요도의 순서는 다음과 같다.

 

(1) foreground process : 사용자가 조작중인 최상위 화면의 Activity(onResume() 메소드가 호출된 경우) 또는 현재 실행중인 IntentReceiver(onReceiveIntent() 메소드가 실행중)를 잡고 있는 프로세스이다. 시스템에는 아주 적은 수의 이런 프로세스가 있고, 이러한 프로세스가 실행되기에 극히 부족한 메모리가 있을 경우에만 종료된다. 이러한 동작은 일반적으로 기기가 메모리 페이징 상태에 다다랐을 때이며, 사용자 인터페이스 응답을 유지하기 위해서 취해진다.


(2) visible process : 사용자 화면에는 보여지지만 foreground는 아닌(onPause() 메소드를 호출한 경우) Activity를 잡고 있는 프로세스이다. 예를 들면 foreground activity가 다이알로그를 보여주며 이전 activity는 그 아래에 위치하는 것과 같다. 이런 프로세스는 매우 중요하며, 모든 foreground 프로세스 실행이 종료되기 전까지는 종료되지 않는다.


(3) service process : startService()를 호출한 Service를 잡고 있는 프로세스이다. 이러한 프로세스는 사용자에게 직접적으로 보여지는 것은 아니지만 사용자와 관련된 일반적인 일(mp3를 배경음으로 연주한다던가, 네트워크 데이터를 업로드/다운로드 한다던가 하는등)들을 한다. 그래서 이러한 프로세스는 모든 foreground, visible 프로세스를 유지하기에 메모리가 충분하지 않을때까지 계속 유지된다.


(4) background process : 사용자에게 현재는 보여지지 않는 activity(onStop() 메소드를 호출한 경우)를 잡고 있는 프로세스이다. 이런 프로세스들은 사용자에게 어떠한 영향을 주지 않으며, activity lifecycle을 정확하게 구현하기 위해서 제공된다. 시스템은 메모리가 부족할 경우 언제든지 이런 프로세스 수행을 멈출 수 있다. 가끔식 이러한 프로세스들이 많이 수행되고 있을 때, 메모리 부족시 가장 최근에 사용자에게 보여진 것이 가장 마지막으로 종료되도록 LRU 목록에 유지된다.


(5) empty process : 어떠한 활성화된 애플리케이션 컴포넌트들도 잡고있지 않는 프로세스이다. 이러한 프로세스를 유지하고 있는 이유는 다음에 컴포넌트의 애플리케이션이 시작되어야 할 때 시작 시간을 개선하기 위한 캐시로 사용하기 위해서다. 시스템은 캐쉬된 빈 프로세스와 커널 캐쉬 사이의 시스템 전체 리소스의 균형을 맞추기 위해 이런 프로세스를 종료시킨다.

Activity Manager

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);

Alarm Manager

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);


Audio Manager 

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

Clipboard Manager 

ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);

Connectivity Manager

ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

Input Method Manager

InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);


Keyguard Manager

KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);


Layout Inflater Manager 

LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);


Location Manager 

LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);


Notification Manager 

NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);


Power Manager 

PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);


Search Manage

SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);


Sensor Manager 

SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);


Telephony Manager 

TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);


Vibrator

Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);


Wallpaper Service 

WallpaperService wallpaperService = (WallpaperService) getSystemService(Context.WALLPAPER_SERVICE);


Wi-Fi Manager 

WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);


Window Manager 

WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);

+ Recent posts