안녕하세요, 타이젠 개발자 윤진입니다.


지난 한 달간 온오프믹스를 통해 Tizen Talks의 참가자를 받아왔습니다.

참고 : [Tizen Talks 2016 in Seoul] 타이젠 개발자 행사 참가자 2차 추가모집

생각보다 많은 분들께서 참석 의사를 밝히셔서 굉장히 놀랐습니다.


타이젠에 관심있는 대학생들 뿐만 아니라,

공기업, 대기업, 벤쳐기업 등 다양한 곳에서 근무하시는 분들이 참가신청을 해주셨습니다.

서울 뿐만 아니라 대구, 부산 등 지방에서 올라오시는 분들도 계시더군요.

관심을 가져주셔서 다시 한 번 감사합니다.


애초에 행사는 20~30명을 위해 기획되었지만,

인원모집 단계에서 총원을 100여명까지 늘렸습니다.

마음 같아서는 참가신청을 원하는 모든 분들을 받아들이고 싶었지만,

장소가 협소하여 어쩔 수 없이 온오프믹스 참가신청을 마감하였습니다.

현재 대기인원 포함 200여분이 등록을 하셨기에 대기등록도 어렵습니다.

참석을 원하는 분은 따로 알려주세요.


애초의 세션 발표안이 약간 수정되었습니다.

참가자를 모집하며 듣고 싶은 내용에 대한 정보를 수집하였는데요,

좀 더 깊이있게 그리고 폭넓게 파고 들어야 하는 세션은 다음으로 미루기로 결정하였고,

플랫폼 전체를 훑으며, 서로 유기적으로 연결되는 세션을 남겨두었습니다.



박영주, Application, "타이젠을 말하다."

이세문, Application Framework, "Tizen Application Inside Out"

정우현, UI Framework, "타이젠 UI앱의 필수, EFL 파헤치기"

문관경, Window system, "더 빠르고 더 유연한 윈도우 시스템(Wayland on Tizen 3.0)"

우상정, Kernel / System Framework, "바닥부터 만들어보는 Tizen"

윤  진, Native App, "타이젠 오픈소스의 커미터가 되어보자! "

이승환, SDK Plugins, "Tizen SDK를 이용한 Tizen Platform 개발"


이번 행사를 위해 어디에서도 들을 수 없는 내용을 준비하고 있습니다.

발표자 분들께서 한창 리허설을 하고 계실 수도 있겠네요.



권오훈, Service Framework, "타이젠 서비스 개발 공통기능 파헤치기"

김기동, Security, "더 안전해진 개인정보 관리"

강석현, Web App, "Javascript Is Eating The World"


상기 세 개 세션은 다음 TT때 찾아뵙도록 하겠습니다.

개인적으로 꼭 듣고 싶은 세션들이어서 아쉬움은 크지만,

일회성 행사가 아니기에 다음 TT를 기다려보기로 합니다.



이 행사는 개발자들이 직접 주관하는 행사입니다.

현업에서 코드를 짜고 있는 개발자들이 만든 행사이기에,

여러가지로 부족한 점이 많이 있습니다.


원래의 취지는 개발자들끼리 한 번 모여서 '우리끼리' 넋두리를 늘어놓아보자 정도인데요,

행사 참석자가 많아져서 그냥 넋두리만 늘어놨다가는 안될 것 같더군요.


그래서 개발자들이 코딩하다 말고 장보고 준비하여 다과를 마련하였습니다.

대단한 것은 아니나 귀엽게 봐주셨으면 좋겠습니다.


주차는 기본적으로 불가하나,

먼 지역에서 오신 분들에게는 예외적으로 주차하실 수 있도록 하겠습니다.

이 부분은 참석자분께서 받은 메일로 답변주시면 됩니다.


며칠 안남았네요.

날도 추운데 감기 조심 하시고 행사날 뵙겠습니다.

끝_

  1. 코코콩 2016.01.20 11:06 신고

    흐어어어... 참석하고싶으나........ㅠㅠ

    혹시 발표자료 올려주실수 있으신가요?

    • 안녕하세요~ 코코콩님.
      제가 만든 자료는 Tizen Talks 그룹 및 본 블로그에 올릴 예정이고,
      다른 발표자 분들의 자료는 Tizen Talks에 올리려고 합니다. :)



안녕하세요, 타이젠 개발자 윤진입니다.


얼마 전에 TT(Tizen Talks) 행사를 개최한다는 사실을 알려드렸는데요.

예상 외로 많은 분들이 관심을 가져주셔서 참가자 1차 모집을 마감하였습니다.

1차 모집 인원은 발표장 크기에 걸맞게 50명으로 책정했었지요.


비록 국내에 타이젠 모바일 제품이 출시되지 않았지만,

타이젠이 탑재된 기어시리즈가 널리 알려지고 있어서 10명만 와도 성공이라고 생각했었죠.


사실 발표자만 10명이 넘고,

행사운영으로도 그만한 숫자의 사람들이 투입이 되는데요,

행사를 준비하는 사람이 참가하는 사람보다 많아도 실망하지 말자고 다짐하고 있습니다.

(사실, 무명의 행사에 10명만 와도 성공이죠)


실제로는 얼마나 와주실지 아직도 걱정스럽기는 하지만,

그래도 참석의사를 밝히신 분이 50명이 넘었다는 사실에 감탄하고 있습니다.

그리고 대기자 명단에 올려서 참석의사를 적극적으로 피력하는 분도 계셨습니다.

타이젠 행사에 관심을 가져주는 모든 분께 진심으로 감사드립니다.


그래서 발표장을 좀 더 널직한 곳으로 변경하였습니다.

물론 현재까지 온오프믹스를 통해 신청의사를 밝히신 50분이 모두 오시진 못하겠지만,

백만분의 일의 확률로 모두 오실 수도 있을테니 참가자를 더 받으려면 공간을 넓혀야죠.


행사장소는 삼성전자 서초사옥 3층 그대로이지만,

3층에 있는 가장 넓은 대강의장에서 진행하려 합니다.

총 백여명이 들어갈 수 있는 공간입니다.




사진 촬영 : 박문경 연구원님


물론 공간이 넓어진 만큼 부담스러운 마음도 생기긴 합니다.

좁은 곳에서 10명은 왠지 가득차 보이지만,

넓은 곳에서 10명은 굉장히 휑해보일테니까요;

그래서 공간을 넓히는 것에 대한 상당한 부담감이 있지만,

장소가 모자라는 것보다는 남는게 차라리 나을테니,

공간이 휑해서 오는 심리적 압박은 준비하는 쪽에서 스스로 이겨내기로 했습니다.


온오프믹스에 추가로 참가신청을 받을 수 있도록 인원을 늘려놓았습니다.

애초에 계획했던 50명에서 100명으로 2배 늘렸는데요,

50명이 가득차서 헛걸음 하셨던 분들은 다시 신청해주세요.



2차 추가모집으로 등록된 사람은 '15. 12. 25 기준으로 78명입니다.

참석자 100명에 추가 대기자 50명으로 설정해두었습니다.

만약 참석예정자 100명이 꽉찬다면 대기자로 등록해주세요.

참석예정자분들께 전화/문자로 참석여부를 확인한 후 대기자 분들을 추가로 확정할 예정입니다.

그러니 연락가능한 전화번호를 꼭 남겨주세요 :)

참석신청은 여기에서 하실 수 있습니다.

그리고 각종 문의는 TT 공식사이트에서 하실 수 있습니다.

https://www.facebook.com/groups/tizentalks/


끝으로 TT 행사 댓글을 하나 언급하고 싶습니다.

황보진원님께서 "(생략)... 가능성을 보고서 울산에서 서울까지... 가려합니다. 기회가 주어진다면 직접 가능성을 보고 같은 가능성을 보는 이들과 교류하고 싶습니다. 기대하고 있습니다."라고 댓글을 남겨주셨습니다.

행사를 준비하는 입장에서 여러가지를 고민하게 만드는 댓글입니다.

먼길 오시는 만큼 헛된 걸음으로 돌아가시지 않도록 열심히 준비하겠습니다.


그럼 즐거운 하루 보내세요~

끝_



  1. 타이젠... 2015.12.27 15:14

    타이젠의 발전을 애타게 기다리는 분들도 많습니다. 저는 아니지만 타이젠폰 해외에서 직구했다가 램관리도 안되는 등 운영체제의 기본부터 개선해야 한다먀 다음 업데이트를 기다린다는 분도 있습니다.. 빨리 발전하길 바랍니다.

    • 안녕하세요? 의견 감사드립니다! 타이젠 모바일에 메모리 관련 정책은 매번 진화하고 있는 것으로 알고 있습니다. 그 사이에 불편을 느끼셨다니 여러가지로 송구스럽네요. 의견 주신 것을 소홀히 하지 않고 차기 버전에 반영할 수 있도록 하겠습니다. 감사합니다.



안녕하세요, 타이젠 개발자 윤진입니다.


드.디.어.

서울에서 타이젠 플랫폼 개발자들과 소통하는 자리를 마련하였습니다.

타이젠 플랫폼의 다양한 측면을 엿보실 수 있는 좋은 기회입니다.


박영주, Application, "타이젠을 말하다."

이세문, Application Framework, "Tizen Application Inside Out"

박춘언, UI Framework, "타이젠 UI앱의 필수, EFL 파헤치기"

우상정, Kernel / System Framework, "바닥부터 만들어보는 Tizen(Tizen from Scratch)"

문관경, Window system, "더 빠르고 더 유연한 윈도우 시스템(Wayland on Tizen 3.0)"

권오훈, Service Framework, "타이젠 서비스 개발 공통기능 파헤치기"

김기동, Security, "더 안전해진 개인정보 관리"

이승환, SDK Plugins, "Plugin을 추가하여 나만의 SDK를 만들기"

강석현, Web App, "Javascript Is Eating The World"

윤  진, Native App, "타이젠 오픈소스의 커미터가 되어보자! "


1회 TT(Tizen Talks)에서는 타이젠 플랫폼을 전체적으로 조망해보고,

2회, 3회... TT에서는 주요 Framework 별로 살펴볼 예정입니다.

타이젠 플랫폼에 관심있으신 분들의 많은 참여 부탁드립니다.


Tizen Talks 공식 그룹 : https://www.facebook.com/groups/tizentalks/

Tizen Talks 2016 in Seoul 등록하기 : http://onoffmix.com/event/59258


그럼 행사날 뵙겠습니다.

윤진 드림.

  1. YOhoho 2015.12.17 01:49

    우와아아아 기대됩니다 신청완료!

  2. 2015.12.19 08:17

    비밀댓글입니다


안녕하세요, 타이젠 개발자 윤진입니다.


Tizen 개발자 사이트에 방문해 보면 개발에 참고할만한 자료들이 많습니다.

말로만 좋다고 해봐야 입에 발린 소리를 하는 것으로 비춰질지도 모르니,

이번 포스팅은 철저히 Tizen 개발자 사이트의 자료를 이용하도록 하겠습니다.



여기에 들어가보시면 상기 그림과 같은 드럼앱 작성법이 나와 있습니다.

드럼을 치면 그에 맞는 소리가 플레이되는 간단한 앱입니다.

위의 그림만 봐도 드럼앱을 개발하고 싶은 욕구가 솟아나오시지요? :)


소리를 재생하려면 Player API를 사용합니다.

Player는 다수의 API로 구성되어 있는데,

그 중 라이프 사이클과 관련된 함수가 가장 중요합니다.

- player_create(), player_destroy()

- player_prepare(), player_unprepare()

- player_start(), player_stop(), player_pause()

위의 함수들로 Idle, Ready, Playing, Paused 상태를 관리합니다.


Player 상태 다이어그램


player_create()에서 재생을 위한 핸들을 생성해주면 Idle 상태로 진입합니다.

핸들을 이용하여 player_prepare()를 하면 비로소 재생할 준비를 합니다.

재생 준비가 되면 Ready 상태에 이르게 되는데요,

player_start()로 Playing 상태로 바뀌고,

player_pause()로는 Paused 상태로 바뀌며,

player_stop()을 실행하면 다시 ready 상태가 됩니다.


Player 상태 변이


위에서 언급한 상태 다이어그램을 함수 측면에서 살펴볼 수도 있습니다.

표에서는 각각의 함수를 실행하기 전에 수행해야할 pre-state를 확인할 수 있습니다.

대부분의 함수가 sync로 동작하기 때문에 절차적 프로그래밍을 하면 됩니다.

player_prepare_async()만이 async인데요, 드럼앱에서는 따로 사용하지 않았습니다.


우선, player 핸들을 생성하여 준비하는 단계를 살펴보겠습니다.

총 9개의 드럼이 있기 때문에 각각의 소리를 재생하기 위해서 9개의 player 핸들을 생성해야합니다.


static void init_base_player(app_data *ad)
{
player_create(&ad->player1);
player_set_uri(ad->player1, "/opt/usr/apps/org.tizen.drums/res/sounds/ride.wav");
player_prepare(ad->player1);

player_create(&ad->player2);
player_set_uri(ad->player2, "/opt/usr/apps/org.tizen.drums/res/sounds/crash.wav");
player_prepare(ad->player2);

player_create(&ad->player3);
player_set_uri(ad->player3, "/opt/usr/apps/org.tizen.drums/res/sounds/tom2.wav");
player_prepare(ad->player3);

player_create(&ad->player4);
player_set_uri(ad->player4, "/opt/usr/apps/org.tizen.drums/res/sounds/hihat2.wav");
player_prepare(ad->player4);

player_create(&ad->player5);
player_set_uri(ad->player5, "/opt/usr/apps/org.tizen.drums/res/sounds/hihat1.wav");
player_prepare(ad->player5);

player_create(&ad->player6);
player_set_uri(ad->player6, "/opt/usr/apps/org.tizen.drums/res/sounds/tom1.wav");
player_prepare(ad->player6);

player_create(&ad->player7);
player_set_uri(ad->player7, "/opt/usr/apps/org.tizen.drums/res/sounds/floor.wav");
player_prepare(ad->player7);

player_create(&ad->player8);
player_set_uri(ad->player8, "/opt/usr/apps/org.tizen.drums/res/sounds/snare.wav");
player_prepare(ad->player8);

player_create(&ad->player9);
player_set_uri(ad->player9, "/opt/usr/apps/org.tizen.drums/res/sounds/bass.wav");
player_prepare(ad->player9);
}


위의 함수를 보시면, player_create()를 9번 수행한 것을 확인할 수 있습니다.

그리고 획득한 핸들로 player_set_uri()를 사용하여 재생할 파일 경로를 입력하였습니다.

"file://"와 같은 prefix를 넣지 않고 바로 절대경로를 입력하여도 동작합니다.

파일 경로까지 입력하였으니 이제 재생을 위한 준비를 할 차례입니다.

player_prepare()함수를 사용하여 sync로 재생 준비를 마칩니다.


void play_audio(player_h player)
{
player_state_e player_state;
player_get_state(player, &player_state);
if (player_state == PLAYER_STATE_PLAYING) {
player_stop(player);
}
player_start(player);
}


이제 드럼을 터치하면 재생을 할 차례입니다.

재생을 하기에 앞서 현재 재생 중인지 여부를 확인합니다.

player_get_state() 함수를 사용하여 현재 상태를 확인할 수 있습니다.



함수를 통해 총 5가지 상태 중 하나의 값을 얻어옵니다.

만약 이미 플레이 중이라면,

player_get_stop()으로 플레이를 멈춥니다.

그리고 다시 player_start()로 재실행을 합니다.


드럼마다 이벤트 영역을 설정하여 play_audio() 함수를 실행하도록 합니다.

총 9개의 드럼이 제각각의 소리를 내는 것을 확인할 수 있습니다.

9개의 이벤트 영역을 설정하는 방법도 흥미로우니,

시간이 허락한다면 한 번 소스를 살펴보는 것도 좋습니다.


player를 위해 할당받은 자원을 정리할 차례입니다.

9개의 핸들에 대해 아래 두 함수를 이용하여 정리작업을 합니다.


    player_unprepare(app->player1);
    player_destroy(app->player1);


이상 아주 간단한 player 사용법이었습니다.

player에는 이외에도 굉장히 다양한 기능이 있습니다.

시간이 허락한다면 좀 더 복잡한 앱의 소스를 분석해보는 시간을 가져보겠습니다.


그럼 좋은 하루 보내세요~

끝_



* References

https://developer.tizen.org/

https://developer.tizen.org/community/tip-tech/drums-tizen

https://developer.tizen.org/dev-guide/2.4.0/org.tizen.native.mobile.apireference/group__CAPI__MEDIA__PLAYER__MODULE.html


안녕하세요, 타이젠 개발자 윤진입니다.


타이젠 앱개발과 관련하여 자주 접하는 질문들을 하나씩 포스팅하기로 마음 먹었었는데요,

(마음만 먹었습니다;)

근데 워낙 많은 질문이 들어와서...

내년이 되어도 모든 답변을 포스팅할 수 있을지 모르겠습니다.


일단 이번 포스팅에서는,

화면이 꺼지면 안되는 앱이 필수로 사용하는 전원 API를 살펴보도록 하겠습니다.


전원 관련 API는 총 4개가 있습니다.

여기서 CPU와 Display의 전원은 request & release 함수를 이용하여 제어하지요.

하지만, 2.4부터는 보다 강력하면서 사용하기도 쉬운 API가 추가되었습니다.

그에 따라 request & release API는 deprecated 수순을 밟고 있습니다.


그 대신 efl_util에서 window screen mode를 설정할 수 있도록 API를 제공합니다.

함수 이름에 직접적으로 언급되어 있듯,

이 함수는 윈도우의 상태를 기준으로 파워를 제어하게 됩니다.

윈도우가 화면에 보이는 상태에서만 위의 함수로 지정한 상태로 진입하고,

화면에서 완전히 사라지면 n초 후 화면은 꺼지게 됩니다.


EFL_UTIL_SCREEN_MODE_DEFAULT는 시간이 경과하면 화면을 끄고,

EFL_UTIL_SCREEN_MODE_ALWAYS_ON은 화면이 켜져있는 상태를 유지합니다.


기존에는 앱의 라이프사이클인 pause / resume 콜백에서 device power 함수를 사용하여,

- 앱이 pause가 되면 상시 전원 on에서 사용시만 on으로 변경하고,

- 앱이 resume이 되면 상시 전원 on 상태로 유지하였었는데요,


이제는 윈도우의 상태에 따라,

- 윈도우가 사라지면(곧, 앱이 pause가 되면), ALWAYS_ON 상태가 자동으로 해제되어 화면이 꺼지도록 제어가 됩니다.

- 반대로 윈도우가 나타나면(곧, 앱이 resume이 되면), ALWAYS_ON이 다시 설정되게 됩니다.

그렇기에 앱의 라이프 사이클 대신 기능의 라이프 사이클에 맞춰 함수를 사용하면 됩니다.

간단하지요? :)


그럼 오늘도 좋은 하루 보내세요~

끝_


* References

https://developer.tizen.org/community/tip-tech/keeping-screen-awake-until-pressing-hold-button

https://developer.tizen.org/dev-guide/2.4.0/org.tizen.native.mobile.apireference/group__CAPI__SYSTEM__DEVICE__POWER__MODULE.html

https://developer.tizen.org/dev-guide/2.4.0/org.tizen.native.mobile.apireference/group__CAPI__EFL__UTIL__MODULE.html

  1. 2015.12.11 23:00

    비밀댓글입니다


안녕하세요, 타이젠 개발자 윤진입니다.


타이젠 데브랩을 진행할 때 빠지지 않고 언급했던 부분은,

애플리케이션의 기본 골격이라 여겨지는 라이프사이클입니다.

라이프사이클이 앱을 구성하는 필수적인 요소라는 것에는 재론의 여지가 없습니다.

중급개발자로 나아가기 위해서는 라이프사이클을 제대로 활용해야합니다.


하지만, 타이젠 스타터를 위한 데브랩에서 라이프사이클에 대한 설명이 필요할지 회의가 드네요.

애플리케이션을 작성할 때에는 분명히 유효한 개념일지는 모르지만,

처음 개발을 하는 사람들에게는 진입장벽만 높이고 있겠지요.

그래서 향후 데브랩에서는 따분한 라이프사이클, 이벤트핸들링, edc 따위는 날려버리려 합니다.

대신 네이티브 앱 작성이 얼마나 쉬운지 위주로 알려드릴 생각입니다. :)

(EFL 창시자 하이츨러 마스터와 함께 나눈 생각임을 알려드립니다.)


그 대신 블로그에서 마음껏 하고 싶은 얘기를 떠들 생각입니다.

네이티브 애플리케이션을 개발할 때 필수적인 개념들을,

하나씩 최대한 자세하게 짚으면서 풀어낼 예정입니다.

타이젠이 오픈소스인 이상,

소스단까지 파고들어가 동작원리와 코드리뷰를 하는 것도 좋겠네요.

그리고 소박하게나마 아키텍쳐 설계원칙도 제가 아는 선에서 언급하도록 하겠습니다.


어쨌든,

이번에는 이벤트 핸들링에 대해서 언급해볼까 합니다.


https://developer.tizen.org/community/tip-tech/application-fundamentals-developer-guide


이벤트 핸들링과 관련하여 개략적인 블록다이어그램입니다.

다이어그램에는 여러 낯선 용어들이 등장합니다.

AUL, AUL daemon, Application Information DB.


첫번째로 등장하는 AUL은 Application Utility Libray를 의미합니다.

한 앱에서 다른 앱을 런칭 혹은 리쥼 혹은 종료시킬 때 사용하는 API를 제공합니다.

AUL에서 제공하는 API는 "aul_" prefix를 가지고 있습니다.

타이젠 SDK에서 "aul_"로 시작하는 API를 발견하셨나요?


물론 발견하실 수 없을 겁니다. :(

왜냐하면 AUL API들은 플랫폼 내부에서 사용하는 함수군이기 때문입니다.


대신 외부에 오픈되어 있는 API로 app_control API가 있습니다.

app_control API 내에서 AUL을 사용하여 다른 앱을 컨트롤하게 됩니다.

app_control은 사용하기 쉽게 재가공한 API로 외부개발자들에게 노출되어 있습니다.

반면 AUL은 플랫폼 내부 피쳐로 외부에 노출할 필요가 없는 API도 관리하고 있습니다.

app_control repo. : platform/core/api/application


int app_request_to_launchpad_with_fd(int cmd, const char *appid, bundle *kb, int *fd, int uid)
{
	int must_free = 0;
	int ret = 0;

	SECURE_LOGD("launch request : %s", appid);
	if (kb == NULL) {
		kb = bundle_create();
		must_free = 1;
	} else
		__clear_internal_key(kb);

	ret = __app_send_cmd_with_fd(AUL_UTIL_PID, uid, cmd, kb, fd);

	_D("launch request result : %d", ret);
	if (ret == AUL_R_LOCAL) {
		_E("app_request_to_launchpad : Same Process Send Local");
		bundle *b;

		switch (cmd) {
			case APP_START:
			case APP_START_RES:
				b = bundle_dup(kb);
				ret = __app_launch_local(b);
				break;
			case APP_OPEN:
			case APP_RESUME:
			case APP_RESUME_BY_PID:
				ret = __app_resume_local();
				break;
			default:
				_E("no support packet");
		}

	}

	/*   cleanup */
	if (must_free)
		bundle_free(kb);

	return ret;
}


앱을 런칭하면 app_control에서 AUL로 런칭요청이 넘어오고,

결국 위의 API가 실행되게 됩니다.


위의 API 이름을 보면 여러가지 정보를 얻을 수 있지요.

app(앱)이 request(요청)를 하고 있는데,

launchpad(런치패드)라는 데몬에게 fd(파일 디스크립터)를 실어서 보내고 있군요.

여기서 launchpad가 바로 위의 블록다이어그램에 언급된 AUL daemon입니다.

Caller 앱은 미리 열어둔 유닉스 소켓을 사용하여 launchpad에게 요청을 전달합니다.

(socket과 관련된 내용은 aul-1/src/app_sock.c에서 살펴보실 수 있습니다.)


요청을 전달받은 launchpad는 caller 앱의 요청을 수행하기 전에,

caller앱에게 합당한 권한이 있는지 살펴봅니다.

합당한 권한이 있다면, caller 앱의 요청사항에 따라 callee 앱을 런칭/리쥼/종료하게 되고,

합당한 권한이 없다면, 아무 것도 수행하지 않습니다.


caller 앱의 요청이 callee 앱을 런칭시키는 것이라면,

런치패드의 한 모듈인 런치패드 로더에서,

사전에 fork/exec으로 만들어 놓은 프로세스를 활용하여 callee 앱을 띄웁니다.

fork/exec 자체가 상당한 시간을 소요하기 때문에,

앱 런칭 성능 향상을 위해 사전에 프로세스를 만들어놓지요.


static void __init_window(void)
{
	Evas_Object *win = elm_win_add(NULL, "package_name", ELM_WIN_BASIC);
	if (win) {
		aul_set_preinit_window(win);

		Evas_Object *bg = elm_bg_add(win);
		if (bg) {
			evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
			elm_win_resize_object_add(win, bg);
			aul_set_preinit_background(bg);
		} else {
			_E("[candidate] elm_bg_add() failed");
		}

		Evas_Object *conform = elm_conformant_add(win);
		if (conform) {
			evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
			elm_win_resize_object_add(win, conform);
			aul_set_preinit_conformant(conform);
		} else {
			_E("elm_conformant_add() failed");
		}
	} else {
		_E("[candidate] elm_win_add() failed");
	}
}

fork/exec 뿐만 아니라 위의 코드에서 볼 수 있듯,

- 윈도우 elm_win_add()

- 백그라운드 elm_bg_add()

- 컨포먼트 elm_conformant_add()

앱을 구성하는 필수적인 요소들을 사전에 만들어놓습니다.


static void __adapter_add_fd(void *user_data, int fd,
                             loader_receiver_cb receiver)
{
	__fd_handler = ecore_main_fd_handler_add(fd,
			(Ecore_Fd_Handler_Flags)(ECORE_FD_READ | ECORE_FD_ERROR),
			__process_fd_handler, NULL, NULL, NULL);
	if (__fd_handler == NULL) {
		_D("fd_handler is NULL");
		close(fd);
		exit(-1);
	}

	__receiver = receiver;
}

그리고 위에서 볼 수 있듯,

mainloop에 진입하기 전에 file descriptor도 등록하게 됩니다.

file descriptor를 통해 mainloop에 진입한 후에도,

fd로 넘어오는 이벤트를 처리할 수 있게 됩니다.

ecore_main_fd_handler_add()의 역할이 mainloop에서도 fd 이벤트를 처리해주는 것이지요.


자, 이제 앱을 런칭시킬 모든 준비가 끝났습니다.

윈도우 등을 비롯한 UI 컴포넌트도 만들어두고,

이벤트 전달을 위한 fd handler도 생성해두었습니다.

그렇다면 이제는 실제 callee 앱을 얹힐 차례입니다.


static int __loader_terminate_cb(int argc, char **argv, void *user_data)
{
	void *handle = NULL;
	int res;
	int (*dl_main)(int, char **);

	SECURE_LOGD("[candidate] Launch real application (%s)", argv[0]);
	handle = dlopen(argv[0], RTLD_LAZY | RTLD_GLOBAL);
	if (handle == NULL) {
		_E("dlopen failed(%s). Please complile with -fPIE and link with -pie flag",
			dlerror());
		goto do_exec;
	}

	dlerror();

	dl_main = dlsym(handle, "main");
	if (dl_main != NULL)
		res = dl_main(argc, argv);
	else {
		_E("dlsym not founded(%s). Please export 'main' function", dlerror());
		dlclose(handle);
		goto do_exec;
	}

	dlclose(handle);
	return res;

do_exec:
	if (access(argv[0], F_OK | R_OK)) {
		char err_str[MAX_LOCAL_BUFSZ] = { 0, };

		SECURE_LOGE("access() failed for file: \"%s\", error: %d (%s)",
			argv[0], errno, strerror_r(errno, err_str, sizeof(err_str)));
	} else {
		SECURE_LOGD("[candidate] Exec application (%s)", g_argv[0]);
		if (execv(argv[0], argv) < 0) {
			char err_str[MAX_LOCAL_BUFSZ] = { 0, };

			SECURE_LOGE("execv() failed for file: \"%s\", error: %d (%s)",
				argv[0], errno, strerror_r(errno, err_str, sizeof(err_str)));
		}
	}

	return -1;

}

위의 코드 상단부에 보면 dlsym으로 main 함수를 여는 부분이 있습니다.

바로 저기에서 런치패드 로더는 비로소 앱의 컨택스트를 프로세스에 탑재하게 됩니다.


앱의 컨텍스트는 application API를 사용하여 등록한 앱 라이프사이클을 의미합니다.

앱 개발자가 앱 라이프사이클을 등록할 때에는 application API를 사용하는데요,

application API는 내부적으로 app-core를 사용하지요.


EXPORT_API int appcore_efl_main(const char *name, int *argc, char ***argv,
				struct appcore_ops *ops)
{
	int r;

	r = appcore_efl_init(name, argc, argv, ops);
	_retv_if(r == -1, -1);

	elm_run();

	appcore_efl_fini();

	return 0;
}

위처럼 callee앱이 Application API를 사용하여 채워넣은 라이프사이클 정보-

create, terminate, resume, pause, control-는 appcore_ops라는 구조체로 app-core 쪽에 전달하게 됩니다.


static void __add_climsg_cb(struct ui_priv *ui)
{
	_ret_if(ui == NULL);
#if defined(WAYLAND)
	ui->hshow =
		ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_SHOW, __show_cb, ui);
	ui->hhide =
		ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_HIDE, __hide_cb, ui);
	ui->hvchange =
		ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_VISIBILITY_CHANGE,
				__visibility_cb, ui);
	ui->hlower =
		ecore_event_handler_add(ECORE_WL_EVENT_WINDOW_LOWER,
				__lower_cb, ui);
#elif defined(X11)
	ui->hshow =
		ecore_event_handler_add(ECORE_X_EVENT_WINDOW_SHOW, __show_cb, ui);
	ui->hhide =
		ecore_event_handler_add(ECORE_X_EVENT_WINDOW_HIDE, __hide_cb, ui);
	ui->hvchange =
		ecore_event_handler_add(ECORE_X_EVENT_WINDOW_VISIBILITY_CHANGE,
				__visibility_cb, ui);

	/* Add client message callback for WM_ROTATE */
	if (!__check_wm_rotation_support()) {
		ui->hcmsg = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE,
				__cmsg_cb, ui);
		ui->wm_rot_supported = 1;
		appcore_set_wm_rotation(&wm_rotate);
	}
#endif
}

그리고 각각의 라이프사이클 콜백 함수들을,

각각의 동작원리에 따라 App-core에서 관리하게 됩니다.

위의 코드에는 라이프사이클 중 resume/pause 이벤트가 나와있네요.

윈도우에 show/hide 콜백을 걸어놓고 resume/pause을 매칭시키죠.


이런 식으로 라이프사이클까지 등록까지 완료되면,

앱런칭을 위해 create 콜백, control 콜백, resume 콜백이 차례대로 불러줍니다.

그러면 최종적으로 UI를 갖춘 앱이 런칭이 되겠지요. :)


자, 여기까지-

- Application

- AUL

- App-core

- Launchpad

위의 네가지가 합작하여 앱을 런칭시키는 과정을 살펴보았습니다.


간단하게 보자면,

1. Application API의 app_control을 사용하여 callee 앱을 런칭하고자 시도

2. app_control API는 내부적으로 AUL을 이용하여 앱런칭 요청을 launchpad로 전달

3. launchpad는 사전에 process를 만들어 필요한 이벤트를 달아놓기

4. launchpad에서 미리 만든 process에 callee 앱의 main 함수를 dlsym으로 로드하기

5. callee main에서 Application API(내부적으로 App-core)를 사용하여 앱 라이프사이클 등록하기


위와 같이 요약할 수 있겠네요.

오래된 기억을 더듬어가며 썼기 때문에 최신의 구조에서는 변경된 항목이 있을 수도 있습니다.

자세한 내용보다는 전체적인 그림을 그리는데 이용하시면 좋겠습니다.


그럼 좋은 하루 보내세요~

끝_



+ Recent posts