리눅스 & 안드로이드2011. 4. 22. 11:33
Android에서 파일을 쓰는데는, 경우에 따라 문제가 발생할 수 있을 것 같다. 그 이유는 바로 buffered I/O 때문!

보통 파일에 어떤 내용을 쓸 경우, 대부분의 경우에는 신경쓸 일이 거의 없다.
하지만 Service/Client 사이에서 파일을 공유해야 하는 경우에는 문제가 될 것 같다.
(물론 Service/Client 사이에 데이터 공유를 위해 File을 사용하는게 옳은지 그른지에 대한 문제는 접어둔다;;)

어떤 Service에서 데이터를 File에 저장하고, 해당 파일의 경로를 Client에게 제공하는 경우,
Client는 아무 생각 없이 전달받은 파일경로에서 파일을 열고, 데이터를 읽어오려고 한다.

하지만, Android file I/O 구현에서는 기본적으로 buffered I/O를 사용하도록 강제(?)하고 있다.
(내가 찾지 못 한것일 수도 있지만, 현재까지는 파일 생성 옵션을 지정할 수 없게 되어 있다)

그래서, Service에서 수행한 파일쓰기 작업에 의해 파일에 실제 데이터가 씌어지기 전에, Client에서의 파일읽기 작업이 먼저 일어난다. VM에서의 어떤 효율을 위해 이렇게 강제(?)하고 있는지는 잘 모르겠지만, 개인적인 입장에서 답답하다. -_-;

관련된 내용을 검색하다가 Linux 에서의 File I/O와 관련된 좋은 글을 발견하였다.

Linux Direct IO의 이해 (Synchronous IO와의 차이를 기반으로) [출처: 알티스토리 http://altistory.net/333]

DB에서는 데이터 쓰기의 신뢰성이 중요하므로 이런 문제를 고민하는게 당연해 보이지만,
임베디드 시스템에서 역시 전원 등의 다양한 문제로 데이터 손실이 일어날 수 있으므로 중요한 문제이다.
(JAVA API design 때문인지, Android 구현의 문제인지는 잘 모르겠지만 수정 바람-_-; 누가? 수정 해 주려나?)

결론은 Binder에 대한 제대로 된 이해가 필요하다!-0-

아직 갈길이 멀다-_-; 파일로의 출력은 그때 그때 다른듯. 바로 출력이 되기도 하는 거 같다.

(1) 우선 FileOutputStream 등으로 출력 후, FileInputStream 등으로 바로 읽으려고 하면 출력이 바로 되는 것 같데, 심증만 있고 물증이 없다;;
(2) RandomAccessFile 이란 class가 있다. 이 class는 object constructor에서 "r" "rw" "rws" "rwd" 등으로 mode를 지정할 수 있도록 되어 있다.

위와 같이 아직은 알아보고 확인해 봐야 할 것들이 너무 많다-0-


Posted by 세월의돌
리눅스 & 안드로이드2011. 4. 20. 14:13
2003년 말. 학교라는 테두리를 벗어나 회사라는 조직에 몸 담으면서 정말 환상적인 개발도구를 알게 되었다.
바로  Source Insight !
정말 "이런 도구가 있었다니...!" 라는 감탄을 금할 수 없었다.
(나중에 알게 된 사실이지만, vi 에도 유사한 기능을 적용할 수 있다^^; )

사설이 길었는데, 거의 완벽한 Source Insight이지만 불편한 점들 가운데 하나가,
리눅스 커널이나 Android framework 소스 등에 대한 프로젝트를 생성할 때,
모든 파일을 다 추가할 수 없기 때문에, 필요한 부분에 대한 파일들만 선별적으로 추가하게 된다.

그런데, 만약 프로젝트가 지워졌다거나 갑작스런 파일오류 등으로 프로젝트를 새로 생성해야 하는 경우, 필요한 파일들을 하나하나 다시 찾아서 추가 해 주어야 하는 번거로움이 있었다. (물론 대략적으로 디렉토리 덩어리들을 추가하고 "Remove Special..."을 이용해 필요없는 파일들을 제거할 수 있지만 이또한 번거롭다)

"Add and Remove Project Files" 윈도우에 보면 "Add from list..."라는 버튼이 존재하는 것으로 보아, 분명 파일 목록으로 추가할 수 있을 것 같았고, 반대로 파일 목록을 출력 해 주는 부분이 있으리라 생각 했으나 찾기 어려웠다;;

그러나 결국 찾아 내었다!!!

* 프로젝트 파일목록 생성
1. 메뉴 Project > Project Report... 선택
2. 모든 Checkbox를 선택해제하고 OK 버튼 클릭
3. 새로 생성된 윈도우에 Project report가 출력 되는데,
    여기에서 상단/하단의 불필요한 정보를 제거하고 파일 목록만 선택하여 파일로 저장

* 파일목록을 이용하여 프로젝트에 파일 추가

1. 메뉴 Project > Add and Remove Project Files... 선택
2. Add from list... 클릭
3. 위에서 저장한 파일 선택

위와 같이 하면 파일목록 생성 및 파일목록을 이용한 추가가 가능하다.
(스크린샷을 추가하면 좋겠지만, 그럴 수 없는 상황이므로 그냥 글로만 남김-0-)

Posted by 세월의돌
리눅스 & 안드로이드2011. 4. 12. 15:52
제목 그대로 find와 grep을 이용해 특정 문자열이 들어있는 파일을 찾는 방법이다.

find 와 grep을 pipeline을 이용해서 묶으면 될거라고 생각하고 있었는데, 찾아보니 전혀 다른 방법이었다. -_-;

$ find ./ -name filename | xargs grep -in find_string

* ./ - 파일을 찾고자 하는 directory. 하위 디렉토리까지 모두 검색한다.
* filename - 찾고자 하는 파일 이름에 대한 regular expression
* find_string - 각 파일 내에서 찾고자 하는 문자열


위와 같이 실행하면 찾고자 하는 문자열이 들어있는 줄(행)이 다음과 같은 형식으로 결과가 보여진다.

파일이름:줄번호: 해당 줄의 내용


Posted by 세월의돌
Android App. 개발 시 이미지들은 drawable이라고 불리며, res/drawable에 저장된다.
이러한 drawable resource들은 device들의 화면크기가 다양해 짐에따라, drawable, drawable-mdpi, drawable-hdpi, drawable-xdpi(Honeycomb에 추가) 등으로 구분된다.
그리고, 이러한 drawable resource 들은 device의 해상도에 따라 철저하게 구분하여 사용된다고 생각했었는데, 오늘 새로운(몰랐던?) 사실을 발견했다.

1. WVGA(hdpi) device라고 해서, drawable과 drawable-hdpi의 resource만 사용하는것은 아니었다.
WVGA device에서 작업중이라서, app. 아이콘을 아무 생각없이 drawable-hdpi 디렉토리의 것만 업데이트 했다. 그리고 Launcher에서 확인을 해 보니 정상적으로 적용이 되었길래 됐다고 생각 했다.

그런데 테스트의 편의를 위해 홈에 shortcut을 추가하는데 업데이트 이전의 아이콘이 보이는 것이었다.
그래서 어디에 이전 아이콘이 들어있나 찾아보니 drawable-mdpi에 남아 있었던것.
drawable-mdpi의 아이콘 까지 업데이트 해 줘야했다.
이게 Launcher(Home)의 bug인지 framework의 bug인지는 모르겠고, 확인하기도 귀찮지만 암튼 그렇다는 사실!

2. Home에 추가된 shortcut 등은 Bitmap을 caching 하므로 App.이 업데이트 되어도 바로 갱신되지 않는다.
Home에 shortcut을 추가한 후, 해당 app.의 아이콘을 업데이트하고 Eclipse 등을 이용해서 (기존것을 제거하지 않고) 재설치 하면, Home의 shortcut은 제거되지 않고 남아있게 된다. 이 때, caching 되었던 Bitmap 데이터(아이콘)은 업데이트 되지 않기 때문에 업데이트한 아이콘은 바로 적용되지 않는다.

물론 이런 현상을 해결한 Launcher가 market에 있을지도 모르겠다. :-)
Launcher 개발시 이러한 부분 까지도 신경을 써 주어야 할 텐데. 이것이 바로 detail의 힘?!

Posted by 세월의돌
리눅스 & 안드로이드2011. 3. 14. 16:16
Android framework 소스에서 LOG 출력방법

소스의 첫 줄에 다음을 추가

#define LOG_NDEBUG 1 <= LOGE, LOGW, LOGI, LOGD 출력. LOGV 제외

#define LOG_NDEBUG 0 <= LOGV를 포함한 모든 LOG 출력

참고로 LOG_NDEBUG에 의해 제어되는 소스코드는 system/core/include/cutils/log.h 이다.

Posted by 세월의돌
이클립스가 계속 먹통되는 현상으로 아무것도 할 수 없는 상태였다.
계속 업데이트를 해 보고, 이리저리 문제 해결법을 찾아봐도 잘 해결되지 않았다.

그리고 오늘! 답답한 마음에 이클립스 사이트에 다시 접속.
Indigi(3.7.0) 버전이 새로 올라왔길래, 속는셈 치고 다운로드하여 환경 설정.

우왕! 버벅댐 없이 정말 자연스러워졌다! 역시 Helios 버전의 버그였단 말인가?-_-;
Linux kernel release와 유사하게, 홀수 버전이 안정화 버전인지도 모르겠다.

Posted by 세월의돌
  1. (public) VideoView.setMediaController(MediaController controller) 호출
    1. 이미 MediaController가 설정되어 있는 경우 보이지 않도록 처리(hide() 호출)
    2. 내부적으로 사용하는 handler message를 제거
    3. MediaController를 포함하고 있는 decor view를 제거
    4. (private) VideoView.attachMediaController() 호출
      1. media controller와 media player가 상호 참조될 수 있도록 설정
      2. media controller가 추가될 view를 결정
      3. (public) MediaController.setAnchorView() 호출
        • (MediaController 자체는 FrameLayout 이므로) 자신에 포함된 모든 자식 views를 삭제
        • (protected) MediaController.makeControllerView() 호출
          • com.android.internal.R.layout.media_controller(.xml)를 이용해 view group을 inflate
          • (private) MediaController.initControllerView() 호출
            1. ImageButton(pause, fast forward, rewind, next and previous) 초기화
            2. ProgressBar(or SeekBar) 초기화
            3. TextView(end time and current time) 초기화
            4. StringBuilder and Formatter instance 생성
            5. (private) installPrevNextListeners() 호출
              1. Next와 Previous 버튼에 listener를 설정하고, listener가 null이 아닌경우에만 각 버튼을 활성화
          • inflate된 ViewGroup을 반환
        • makeControllerView()가 반환한 ViewGroup instance를 LayoutParams(MATCH_PARENT, MATCH_PARENT)와 함께, 자신(MediaController, FrameLayout)의 child로 추가
      4. VideoView의 상태가 ERROR, IDLE, or PREPARING이 아닌경우 MediaController를 활성화

Posted by 세월의돌
리눅스 & 안드로이드2011. 2. 26. 20:13
제목이 좀 모호하다. 그치?ㅋ 어제 오늘 이놈 땜에 삽질을 좀 했다.
Daum 비디오 플레이어를 따라 만들어 보려고 마음먹고, 산후조리원에서 맥북으로 관련 자료들을 좀 찾아 보았다.

우선 가장 필요한 것이, 비디오에서 특정 시간의 frame을 bitmap으로 꺼내 오는것!
와이프의 도움으로 MediaMetadataRetriever class를 이용하면 된다는 것을 알게 되었고,
Android Developer 사이트에서 위의 class를 찾아 보니 과연 getFrameAtTime method가 있었다!(얏호!)

"이 method를 가지고 작업을 시작하면 되겠네~"라고 생각하고 즐겁게 출근하여,
실제 sample code를 만들어보던 중에 1차 벽에 부딛치게 된다.

MediaMetadataRetriever가 @hide 속성이 있어서 SDK로 publishing 되지 않았던 것!
하지만 이때 까지만 해도 "왜 Android Developer 사이트에 보이는 API가 @hide로 되어 있을까? API Level이 다른가?"라는 의심은 하지도 못했고, 당연히 다음에 부딛칠 벽도 예상할 수 없었다.

하지만 바로 다음 문제에 봉착!
내가 작업하는 환경은 API Level 8. getFrameAtTime의 API Level 10! API Level 10!! API Level 10!!!
정말 난감한 상황이었다. -_-;
부랴부랴 API Level 10에 대해 찾아보니, Android 2.3.3에 해당했다.
2.3 Gingerbread에 대해서만 알고 있었는데 2.3.3은 도대체 뭐냐고!!!!
Android GitWeb에서 2.3.3을 입수하고 나서야 소스에서 확인할 수 있었다.(@hide도 제거되어 publishing SDK가 됨)
여기서부터 다시 삽질이 시작되었던 것이었던 것이었다;;
어디서도 Android 2.3.3이 올라간 device를 구할 수 없었고, emulator는 너무 느렸다.
그래서 오기로 2.3.3에 있는 MediaMetadataRetriever 관련 코드들을 포팅 해 보겠다고 마음 먹어버렸다.(왜! -_-;)
그러나 역시나 포팅은 힘들었다. 제대로 알고 하는게 아니었기 때문.
에러 하나를 수정하면 또 몇 개가 나오고. 이것의 무한 반복. 하고 나서도 제대로 된다는 보장도 없었다.
결국 빌드까지는 완료 하였지만, HAL(Hardware Abstraction Layer)관련 코드 간과하고 있었고, 잘 되지 않았다;;

여기서 접기에는 좀 아쉬운 감이 있었다.(무려 하루를 투자 하였으니...-0-)
그래서 코드를 조금 더 살펴보던 중, HAL 코드에서 특정 frame을 꺼내오는 함수를 발견!
"좋아! 그럼 이 함수를 가지고 내가 한번 만들어 보지 뭐!" 라고 생각하고 토요일 특근을 결심!!!

수빈이 B.C.G. 접종을 위해 소아과를 다녀오느라 늦으막히(오전 10시 53분) 특근을 찍고 작업을 시작했다.
JAVA, JNI, 각종 C++ 소스파일들, 그리고 HAL 관련 소스파일들에 모조리 코딩을 했고 빌드에 성공!
두근두근 마음을 졸이며 실행을 해 보았으나 잘 되지 않았고, 문제는 점점 미궁으로 빠져들어갔다.
처음에는 captureFrame과 같은 결과를 뱉어 내더니, 나중에는 아무런 Bitmap도 뱉어내지 않았던 것이다.

도대체 무엇이 문제일까 찾고 또 찾아보았지만 전혀 알 수 없었고, 무식한 방법(디버그 메시지를 추가하고 빌드하여 다운로드후 실행-이것의 무한반복)으로 특정 method가 무조건 NULL을 뱉어내는 느낌을 받고 확인해본 결과, abstract class를 구현 해 놓은 class(실은 껍데기. 모두 NULL을 반환하도록 되어 있음) method argument type과 이를 상속한 실제 구현(HAL)부의 method의 argument type이 서로 다르게 해석되어 계속해서 껍데기 class의 method를 호출한다는걸 발견하고 너무 허탈했다.

요는 Android 2.3.3의 코드를 참조하다가 long을 int64_t로 선언되어 있는것을 발견하고 모두 바꿔주었는데, 이것이 화근이었다. long은 C/C++ native type이므로 어디서든 동일하게 해석되지만, int64_t는 framework과 HAL에서 서로 다르게 해석되었던것. 같이 빌드되는 소스인데도 이렇게 달라서야-_-;

그래서 모두 long으로 바꿔주니 호출은 제대로 이루어 졌으나, 꺼내오는 프레임은 항상 7초 언저리.
분명 시간을 입력으로 전달하는데도 그래서 이상하다는 생각이 들었고, HAL 관련 코드를 좀더 살펴보니 우습게도(왜 이렇게 코드를 작성 해 놨는지 정말 궁금!) 입력되는 시간은 무시하고, thumbnail seek time(아마도 미리 정의 되어 있는 듯)을 가져와서 해당 시간 위치에서 frame을 꺼내 오도록 코드가 작성되어 있었다.

이 부분을 제거하고 다시 빌드! 다운로드! 그리고 실행...
푸하하하하하하하~!!!!! 드디어 원하는 시간에서 frame을 꺼내올 수 있게 되었다!

이제 퇴근해야겠다. 마트에 들러 젖병세정제와 젖병솔을 사고 수빈이를 보러가야겠다~
아 행복해~~~

Posted by 세월의돌
리눅스 & 안드로이드2011. 2. 24. 17:04
 Android framework source에 보면 분명 public으로 지정된 class, method, variable인데 @hide attribute가 붙어있어 SDK로는 접근이 불가능한 요소들이 존재한다. 분명 뭔가 이유가 있기 때문에 Google에서 그렇게 막아 놓았을 수도있다.(본인들만 편리하게 사용하려고 그랬을 수도 있음-_-;)

 그러나 이클립스Eclipse에서 응용프로그램을 개발하다 보면, 때로는 필요한 상황이 발생할 수 있다. 그럴때 발생하는 어려움을 해결할 수 있는 방법이 있었던 것 같다. (내가 모르고 있었으므로...^^;)

 방법은 아주 간단(?)했다. 필요한 프레임웍 JAVA 소스의 패키지 디렉토리 구조를 그대로 본인의 프로젝트 디렉토리에 생성 후 복사 해 주면 된다. 즉,

MediaPlayer.java가 필요하다면, MediaPlayer.java의 패키지가 android.media이므로, 본인의 (project directory)/src/android/media/MediaPlayer.java 처럼 복사하면 된다.

'리눅스 & 안드로이드' 카테고리의 다른 글

MediaController 초기화 과정  (0) 2011.03.07
getFrameAtTime을 위한 삽질  (2) 2011.02.26
안드로이드 SD card 마운트(vold)  (1) 2011.02.17
Kernel Command Line  (0) 2011.02.15
GNU Compiler __attribute__  (2) 2011.02.11
Posted by 세월의돌
리눅스 & 안드로이드2011. 2. 17. 14:16
SD card는 vold(아마도 volume daemon의 약자인듯)가 mount를 하도록 되어있다.

vold는 init.rc에 정의되어 있으며, kernel booting 시 시작되는 서비스 이다.

vold는 /system/etc/vold.fstab의 내용을 참고하여 본인이 mount 해야 할 device를 list로 만들어 두고 event(SDcard 탈/부착?)에 의해 mount를 시도하도록 되어 있는 것 같다.

아래는 foroyo에 포함된 vold.fstab의 내용이다.
## Vold 2.0 Generic fstab
## - San Mehat (san@android.com)
##

#######################
## Regular device mount
##
## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...> 
## label - Label for the volume
## mount_point - Where the volume will be mounted
## part - Partition # (1 based), or 'auto' for first usable partition.
## <sysfs_path> - List of sysfs paths to source devices
######################

## Example of a standard sdcard mount for the emulator / Dream
# Mounts the first usable partition of the specified device
dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1

## Example of a dual card setup
# dev_mount left_sdcard /sdcard1 auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1
# dev_mount right_sdcard /sdcard2 auto /devices/platform/goldfish_mmc.1 /devices/platform/msm_sdcc.3/mmc_host/mmc1

## Example of specifying a specific partition for mounts
# dev_mount sdcard /sdcard 2 /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1
SD card를 직접 해당 디렉토리에 마운트 시키기 위해서는 다음과 같은 명령어를 사용하면 된다.

cmd> adb remount
cmd> adb shell
# su (필요 없을수도 있음)
# mount -o rw -t vfat /dev/block/<partition> /mnt/sdcard

* 여기서 <partition>은 예를들어 mmcblk0p1이 될 수 있다
* SD card는 filesystem type(-t)을 vfat으로 지정해야 한다
* rw 옵션(-o)은 default이므로 생략해도 된다
* 당연한 이야기 이겠지만, /mnt/sdcard 디렉토리는 미리 생성되어 있어야 한다
  (init.rc에 정의되어 부팅시 자동으로 생성된다)


P.S 어떤 device를 보면 대용량 플래시 메모리를 내장하면서 /mnt/sdcard를 내장 플래시 메모리를 마운트하는 포인트로 사용하고, 실제 외장 SD card는 /mnt/sdcard/ 내부에 디렉토리를 생성하고 그 디렉토리를 마운트 포인트로 사용한다. 의도적이었는지 잘 몰라서 이렇게 했는지 이유는 잘 모르겠지만, 일반적으로 SD card라 함은 탈착이 가능한 플래시메모리라고 생각하는데, 왜 이런 이상한 짓을 했는지 잘 모르겠다.-_-; 이런식으로 상식에 벗어나는 행동들을 하게되면 욕을 먹게 되는것이다;;

Posted by 세월의돌