[펌] http://www.androidpub.com/19665

프로그램이 죽는 경우 기본적인 디버깅 방법조차 모르는 경우가 많은 것 같아서 정리를 합니다. 프로그램이 죽어서 Q&A 게시판에 글을 남기실때 이 내용을 반드시 확인하시고 질문을 올려주시기 바랍니다.

stoppederror.png 

프로그램이 죽는 경우라 하면 먼저 위와 같은 에러 메시지(Sorry! The application XXXX (process com.xxx.xxx.xxx) has stopped unexpectedly. Please try again. Force close)가 화면에 나타나는 경우를 말합니다.

이 경우 디버깅 화면의 LogCat 메시지를 살펴보면 다음과 같습니다. (로그캣이 뭔지 모르신다면 먼저 프로젝트 실행과 디버깅 그리고 단말 세팅 이 글을 읽어보세요)
stoppederror02.jpg

가장 가까운 마지막 부분 근처에 E 로 찍히고 빨간색으로 표시되는 메시지가 주욱 찍힙니다. 소스 어디에서 어떤 이유로 에러가 발생했는지를 표시해주는 로그로 에러의 해결을 위해 가장 중요한 부분입니다.

08-05 00:02:14.564: ERROR/AndroidRuntime(12848): Uncaught handler: thread main exiting due to uncaught exception
08-05 00:02:14.774: ERROR/AndroidRuntime(12848): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android.apis/com.example.android.apis.view.Gallery1}: java.lang.NullPointerException
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2268)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.app.ActivityThread.access$1800(ActivityThread.java:112)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.os.Handler.dispatchMessage(Handler.java:99)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.os.Looper.loop(Looper.java:123)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.app.ActivityThread.main(ActivityThread.java:3948)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at java.lang.reflect.Method.invokeNative(Native Method)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at java.lang.reflect.Method.invoke(Method.java:521)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at dalvik.system.NativeStart.main(Native Method)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848): Caused by: java.lang.NullPointerException
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at com.example.android.apis.view.Gallery1.onCreate(Gallery1.java:48)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
08-05 00:02:14.774: ERROR/AndroidRuntime(12848):     ... 11 more


주루룩 선택하고 에러 메시지를 카피&페이스트할 수 있습니다. 여기서 중요한 부분은 굵은 글씨로 표시해보았습니다. 널포인트 익셉션이 발생하고 소스의 어느 어느 위치에서 발생하는지를 표시합니다.

01.super.onCreate(savedInstanceState);
02.setContentView(R.layout.gallery_1);
03. 
04.// Reference the Gallery view
05.Gallery g = (Gallery) findViewById(R.id.add);
06.// Set the adapter to our custom adapter (below)
07.g.setAdapter(new ImageAdapter(this));
08. 
09.// Set a item click listener, and just Toast the clicked position
10.g.setOnItemClickListener(new OnItemClickListener() {
11.public void onItemClick(AdapterView parent, View v, int position, long id) {
12.Toast.makeText(Gallery1.this, "" + position, Toast.LENGTH_SHORT).show();
13.}
14.});
15. 
16.// We also want to show context menu for longpressed items in the gallery
17.registerForContextMenu(g);

해당 소스의 관련 부분을 보고 어디에서 문제가 발생했는지를 확인합니다.

Q&A 게시판에 에러 발생과 관련하여 질문을 하실때에는 먼저 Stopped Unexpectedly로 죽는 경우인지를 밝하시고, LogCat에서 붉은 메시지를 카피해서 붙여주신 이후에, 관련 소스 부분까지 정확히 찾아서 질문에 붙여주시기 바랍니다. 소스 전체를 압축해서 첨부해서 디버깅을 해달라는 경우가 종종 있는데 해당 소스를 일일이 다운받아서 문제점을 찾아서 보는 경우도 없고, 나중에 같은 문제를 접하는 다른 개발자분들에게도 도움이 되지 않습니다. 화면을 그냥 카피하지 마시고 반드시 위와 같이 에러메시지와 소스부분을 텍스트로 질문에 넣어주세요.
[펌] http://icess.egloos.com/3279459

안드로이드
SDK에서 단말기의 모뎀에서 제공하는 전화기능에 관련된 내용은 
android.telephony 패키지의 TelephonyManager클래스에서 담당한다.

단말기의 모뎀상태에 대한 정보를 얻기 위해서는 READ_PHONE_STATE권한이 필요하다.
AndroidManifest.xml파일에 아래 내용을 추가한다.
<uses-permission 
android:name="android.permission.READ_PHONE_STATE">
</uses-permission>

◆ 단말기의 모뎀상태 조회
TelephonyManager 객체를 얻기 위해서는 Context 객체에서 제공하는 getSystemService() 메서드를 이용한다.
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

음성통화 상태 조회
CALL_STATE_IDLE/CALL_STATE_OFFHOOK/CALL_STATE_RINGING 등의 값을 반환
Log.d("PHONE", "getCallState :" + tm.getCallState());
데이터통신 상태 조회
DATA_DISCONNECTED/DATA_CONNECTING/DATA_CONNECTED/DATA_SUSPENDED 등의 값을 반환
Log.d("PHONE", "getDataState :" + tm.getDataState());
단말기 ID 조회
GSM방식 IMEI 또는 CDMA방식의 MEID 값을 반환
Log.d("PHONE", "getDeviceId :" + tm.getDeviceId());
SW버전 조회
GSM방식의 IMEI/SV와 같은 SW버전을 반환
Log.d("PHONE", "getDeviceSoftwareVersion :" + tm.getDeviceSoftwareVersion());
전화번호 조회
GSM방식의 MSISDN과 같은 전화번호 반환
Log.d("PHONE", "getLine1Number :" + tm.getLine1Number());
국가코드 조회
현재 등록된 망 사업자의 MCC(Mobile Country Code)에 대한 ISO 국가코드 반환
Log.d("PHONE", "getNETWORKCountryIso :" + tm.getNetworkCountryIso());
Log.d("PHONE", "getSimCountryIso :" + tm.getSimCountryIso());
망 사업자코드 조회
현재 등록된 망 사업자의 MCC+MNC(Mobile Network Code) 반환
Log.d("PHONE", "getNetworkOperator :" + tm.getNetworkOperator());
Log.d("PHONE", "getSimOperator :" + tm.getSimOperator());
망 사업자명 조회
현재 등록된 망 사업자명 반환
Log.d("PHONE", "getNetworkOperatorName :" + tm.getNetworkOperatorName());
Log.d("PHONE", "getSimOperatorName :" + tm.getSimOperatorName());
망 시스템 방식 조회
현재 단말기에서 사용중인 망 시스템 방식을 반환
NETWORK_TYPE_UNKNOWN/
GSM방식 :  NETWORK_TYPE_GPRS/NETWORK_TYPE_EDGE/NETWORK_TYPE_UMTS/
NETWORK_TYPE_HSDPA/NETWORK_TYPE_HSUPA/NETWORK_TYPE_HSPA
CDMA방식 : NETWORK_TYPE_CDMA/NETWORK_TYPE_EVDO_0/NETWORK_TYPE_EVDO_A/NETWORK_TYPE_1xRTT
Log.d("PHONE", "getNetworkType :" + tm.getNetworkType());
단말기 종류 조회
단말기에서 지원하는 망의 종류를 반환
PHONE_TYPE_NONE/PHONE_TYPE_GSM/PHONE_TYPE_CDMA 등의 값을 반환
Log.d("PHONE", "getPhoneType :" + tm.getPhoneType());
SIM카드 Serial Number 조회
Log.d("PHONE", "getSimSerialNumber :" + tm.getSimSerialNumber());
SIM카드 상태 조회
SIM_STATE_UNKNOWN/SIM_STATE_ABSENT/SIM_STATE_PIN_REQUIRED/SIM_STATE_PUK_REQUIRED/
SIM_STATE_NETWORK_LOCKED/SIM_STATE_READY 등의 값을 반환
Log.d("PHONE", "getSimState :" + tm.getSimState());
가입자 ID 조회
GSM방식의 IMSI와 같은 가입자 ID 반환
Log.d("PHONE", "getSubscriberId :" + tm.getSubscriberId());

◆ 조회결과
getCallState :0(CALL_STATE_IDLE)
getDataState :2(DATA_ACTIVITY_OUT)
getDeviceId :000000000000000
getDeviceSoftwareVersion :null
getLine1Number :15555218135
getNetworkCountryIso :us
getNetworkOperator :310260
getNetworkOperatorName :Android
getNetworkType :3(NETWORK_TYPE_UMTS)
getPhoneType :1(PHONE_TYPE_GSM)
getSimCountryIso :us
getSimOperator :310260
getSimOperatorName :Android
getSimSerialNumber :89014103211118510720
getSimState :5(SIM_STATE_READY)
getSubscriberId :310260000000000

실제상황에서는 이와같이 현재 단말기의 상태를 직접 조회하는것이 아니라 
상태정보가 변경될 때 자동으로 인식해야하는 상황이 훨씬 많을것이다.
이럴때는 TelephonyManager의 listen()를 이용하여 콜백메서드를 등록하면 가능하다.
        tm.listen(new PhoneStateListener(){
         public void onCallStateChanged(int state, String incomingNumber){
         if (state == TelephonyManager.CALL_STATE_RINGING){
         Log.d("Telephony", "state = " + state + ", number = " + incomingNumber);
         }else{
         Log.d("Telephony", "state = " + state);
         }        
         }
        }, PhoneStateListener.LISTEN_CALL_STATE);

onCallStateChanged() 이외에도 아래와 같은 상태변화를 감지할 수 있다.
- onCallForwardingIndicatorChanged() : 호전환(Call Forwarding) 상태 변화
- onCellLocationChanged() : 단말기의 Cell위치 변화
- onDataActivity() : Data 활성화 상태 변화
- onDataConnectionStateChanged() : Data 연결상태 변화
- onMessageWaitingIndicatorChanged() : 메시지 대기상태 변화
- onServiceStateChanged() : 단말기의 서비스 상태 변화
- onSignalStrengthsChanged() : 망의 신호강도 변화

◆ 전화번호 처리
각 국가별로 전화번호의 형식이 다르다. 
한국은 01x-xxxx-xxxx 이 일반적이고,
북미는 xxx-xxx-xxxx가 된다.
PhoneNumberUtils.formatNumber() 메서드를 사용하면 설정된 Locale에 맞게 형식화 된다.
String formattedTelNumber = PhoneNumberUtils.formatNumber("01098761234");
        Log.d("Telephony", "formattedTelNumber :" + formattedTelNumber);
Locale을 English(United States)로 할경우 010-987-61234로 출력된다.
한국어로 할 경우는 01098761234가 그대로 출력된다.
formatNumber() 메서드의 구현내용을 살펴봐야 할듯 하다.

EditText에서 전화번호를 입력받을 경우에도 자동으로 형식화가 가능하다.
EditText객체의 addTextChangedListener에 PhoneNumberFormattingTextWatcher()를 등록하기만 하면 된다.
        EditText tn = (EditText) findViewById(R.id.edtTelNumber);
        tn.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
그러나 역시 한국어로는 동작하지 않았다.

출처:Telephony 기능


[펌] http://polomin.tistory.com

Permission 종류
ACCESS_CHECKIN_PROPERTIES      체크인데이터베이스의_속성테이블로_액세스                       
ACCESS_COARSE_LOCATION         코스_로케이션_액세스_(Cell-ID/WiFi)                            
ACCESS_FINE_LOCATION           파인로케이션_액세스(GPS)                                       
ACCESS_LOCATION_EXTRA_COMMANDS 로케이션_옵션_커맨드_액세스                                    
ACCESS_MOCK_LOCATION           목_로케이션_프로바이더_생성_(테스트용)                         
ACCESS_NETWORK_STATE           네트워크_상태_접근                                             
ACCESS_SURFACE_FLINGER         서피스_플링거_접근                                             
ACCESS_WIFI_STATE              WiFi상태_접근                                                  
ADD_SYSTEM_SERVICE             시스템서비스_추가                                              
BATTERY_STATS                  배터리_상태                                                    
BLUETOOTH                      블루투스                                                       
BLUETOOTH_ADMIN                블루투스_어드민                                                
BRICK                          디바이스_실효성_지정                                           
BROADCAST_PACKAGE_REMOVED      제거된_패키지에_대한_notification_브로드캐스트                 
BROADCAST_SMS                  SMS에_대한_브로드캐스트                                        
BROADCAST_STICKY               인텐트_브로드캐스트                                            
CALL_PHONE                     통화                                                           
CALL_PRIVILEGED                통화(긴급전화_포함)                                            
CAMERA                         카메라                                                         
CHANGE_COMPONENT_ENABLED_STATE 컴포넌트의_실효성_변경                                         
CHANGE_CONFIGURATION           컨피그_변경                                                    
CHANGE_NETWORK_STATE           통신상태_변경                                                  
CHANGE_WIFI_STATE              WiFi상태_변경                                                  
CLEAR_APP_CACHE                어플리케이션_캐시_클리어                                       
CLEAR_APP_USER_DATA            어플리케이션의_유저데이터_클리어                               
CONTROL_LOCATION_UPDATES       위치정보_갱신                                                  
DELETE_CACHE_FILES             캐시파일_제거                                                  
DELETE_PACKAGES                패키지_제거                                                    
DEVICE_POWER                   전원상태에_대한_로우레벨_접근                                  
DIAGNOSTIC                     진단리소스_읽고쓰기                                            
DISABLE_KEYGUARD               키_가드_끄기_DUMP_덤?                                         
EXPAND_STATUS_BAR              상태표시줄_확장                                                
FACTORY_TEST                   팩토리_테스트                                                  
FLASHLIGHT                     플래시라이트                                                   
FORCE_BACK                     포스백                                                         
GET_ACCOUNTS                   어카운트_획득                                                  
GET_PACKAGE_SIZE               패키지_획득                                                    
GET_TASKS                      태스크_획득                                                    
HARDWARE_TEST                  하드웨어테스트                                                 
INJECT_EVENTS                  유저이벤트_키/트랙볼                                           
INSTALL_PACKAGES               패키지_인스톨                                                  
INTERNAL_SYSTEM_WINDOW         내부_시스템윈도_활용                                           
INTERNET                       인터넷                                                         
MANAGE_APP_TOKENS              어플리케이션_토큰관리                                          
MASTER_CLEAR                   마스터_클리어                                                  
MODIFY_AUDIO_SETTINGS          오디오설정_편집                                                
MODIFY_PHONE_STATE             전화상태_편집                                                  
MOUNT_UNMOUNT_FILESYSTEMS      파일시스템_편집                                                
PERSISTENT_ACTIVITY            액티비티_지속                                                  
PROCESS_OUTGOING_CALLS         전화_발신처리_접근                                             
READ_CALENDAR                  캘린더_읽어오기                                                
READ_CONTACTS                  주소록_읽어오기                                                
READ_FRAME_BUFFER              프레임버퍼_읽어오기                                            
READ_INPUT_STATE               입력상태_읽어오기                                              
READ_LOGS                      로그_읽어오기                                                  
READ_OWNER_DATA                owner_data읽어오기                                             
READ_PHONE_STATE               통화상태_읽어오기_READ_SMS_SMS읽어오기                         
READ_SYNC_SETTINGS             동기설정_읽어오기                                              
READ_SYNC_STATS                동기상태_읽어오기                                              
REBOOT                         reboot                                                         
RECEIVE_BOOT_COMPLETED         boot완료                                                       
RECEIVE_MMS                    MMS수신                                                        
RECEIVE_SMS                    SMS수신                                                        
RECEIVE_WAP_PUSH               WAP수신                                                        
RECORD_AUDIO                   오디오_수신                                                    
REORDER_TASKS                  태스크_Z오더                                                   
RESTART_PACKAGES               패키지_리스타트                                                
SEND_SMS                       SMS송신                                                        
SET_ACTIVITY_WATCHER           액티비티_왓쳐지정                                              
SET_ALWAYS_FINISH              액티비티_전체_종료                                             
SET_ANIMATION_SCALE            스케일_애니메이션_지정                                         
SET_DEBUG_APP                  디버그어플리케이션_지정                                        
SET_ORIENTATION                스크린_로테이션지정                                            
SET_PREFERRED_APPLICATIONS     자주_사용하는_어플리케이션_지정                                
SET_PROCESS_FOREGROUND         포어그라운드_처리지정                                          
SET_PROCESS_LIMIT              제한처리_지정                                                  
SET_TIME_ZONE                  타임존_지정                                                    
SET_WALLPAPER                  배경화면_지정                                                  
SET_WALLPAPER_HINTS            배경화면_힌트_지정                                             
SIGNAL_PERSISTENT_PROCESSES    지속처리_시그널_지정                                           
STATUS_BAR                     상태표시줄_지정                                                
SUBSCRIBED_FEEDS_READ          서브스트립드_피즈_읽어오기                                     
SUBSCRIBED_FEEDS_WRITE         서브스트립드_피즈_쓰기                                         
SYSTEM_ALERT_WINDOW            알림_윈도우                                                    
VIBRATE                        진동                                                           
WAKE_LOCK                      알람                                                           
WRITE_APN_SETTINGS             APN설정_쓰기                                                   
WRITE_CALENDAR                 캘린더_쓰기                                                    
WRITE_CONTACTS                 주소록_쓰기                                                    
WRITE_GSERVICES                G서비스_쓰기                                                   
WRITE_OWNER_DATA               owner_data쓰기                                                 
WRITE_SETTINGS                 설정_쓰기                                                      
WRITE_SMS                      SMS쓰기                                                        
WRITE_SYNC_SETTINGS            동기설정_쓰기      


<uses-permission android:name="android.permission.xxxxxx"/>

(출저: http://polomin.tistory.com)

1. source build/envsetup.sh

2. lunch
    ==> 해당 deivce 선택

3. mmm package/apps/Phone

4. make snod ( image 생성)

[펌] http://yms2047.tistory.com/277

C와 JAVA 구조체 비교


 C언어 JAVA 
 struct Doggy {

  int eye;
  int leg;
  char[12] name;
}

void run(){
  //뽀삐 달리다.
}

int main()
{
  struct Doggy bbobbi;
  struct kitty marry;

  bbobbi.eye = 2;
  bbobbi.eye = strcpy(name, "뽀삐");
  run();
}
 
class Doggy {
  
  //멤버변수
  int eye;
  int leg;
  String name;
  
  //생성자
  Doggy(){  
  }

  //멤버메소드
  void run(){
    //뽀삐 달리다.
  }
}

public class DoggyTest{

  public static void main(String args[]) {

    Doggy bbobbi = new Doggy();

    bbobbi.eye = 2;
    bbobbi.name = "뽀삐";
    bbobbi.run();
}

[펌] http://lunatine.springnote.com/pages/7638839


Write Barrier

본 문서는 Linux 파일시스템의 오류 상황과 파일시스템에서 지원하는 Write Barrier 기능에 대해 기술하고 있습니다.

 

파일시스템 에러


 Linux 파일시스템은 Unix 시스템과 마찬가지로 마운트 작업을 거친 후에 접근이 가능한 형태로 이루어져있다. 마운트 작업을 거쳐 OS에 인식이 되면 파일시스템 드라이버를 통해서 물리적인 디스크에 매핑되는 논리적 구조로 사용이 가능하게 된다.


 파일시스템은 일반적인 경우에는 별 다른 문제 없이 정해진 파일시스템 구조에 맞추어 데이터를 저장하게 되는데 이러한 파일시스템에 문제가 발생하는 경우가 몇 가지 존재 하지만 종합해보면 궁극적인 원인은 실제 물리적인 디스크의 장애로 인한 경우로 결론 지을 수 있다.


 먼저, 물리적인 디스크의 배드섹터(Bad Sector)에 대한 부분을 생각할 수 있다. 물리적인 디스크의 플래터에 배드섹터가 발생하였고 이 영역에 파일시스템이 매핑하여 데이터를 기록하려고 하면 오류가 나게 된다. 하지만, 최근 디스크 들은 이러한 배드 섹터를 자동으로 처리하기 위해서 디스크가 제공하는 가용공간 이외에도 추가적인 영역을 가지고 있어 배드섹터가 발생하면 해당 영역을 미리 준비된 추가 영역으로 대체해서 I/O를 처리하게 된다.


 그리고, 물리적인 디스크가 인식불가 또는 전원 공급이 끊긴 상태를 생각해 볼 수 있다. 물리적인 디스크가 죽은 장치(Dead Device)로 인식이 되면 I/O를 처리할 수 없는 상황이 발생하게 되는데 이 경우에 파일시스템의 결함(Corruption)이 발생할 수 있다. 이는 저널링 파일시스템의 특성하고도 관련성이 있다. 저널링 파일시스템은 일반적으로 세 가지 방식으로 동작하는데 쓰기저장(WriteBack), 순서(Ordered), 데이터(Data) 방식으로 나눌 수 있다.


 간단히 살펴보면

  • 쓰기저장 모드에서는 메타데이터만을 저널에 기록하고 실제 데이터 블록은 디스크의 해당 위치에 직접 기록하는 방식
  • 순서 모드에서는 실제 데이터 블록을 기록하고 나서야 메타데이터를 저널에 기록한다.
  • 데이터 방식의 경우는 메타데이터와 데이터블록을 저널에 모두 기록하고 그 후에 디스크에 다시 기록하는 방식


 일반적으로 많이 사용되는 ext3 파일시스템의 경우 순서 방식이 기본으로 되어있으며 앞서 물리적디스크가 인식이 되지 않게 되면 데이터블록은 기록하였으나 저널에 메타데이터가 제대로 기록되지 않아 파일시스템의 불일치(inconsistency) 또는 결함이 생기게 된다. 참고로, 통상적인 쓰기저장 방식이라면 메타데이터만 남고 실제 데이터블록은 유실되게 된다. (저널링 관련된 부분은 인터넷에 많이 있는 저널링 관련 문서를 참고하면 된다)


 또 하나 생각해 볼 수 있는 부분이 대규모의 I/O 요청이 발생하였고 이 요청이 물리적인 디스크가 (심지어 캐시를 가지고 있음에도 불구하고) 감당하지 못할 정도로 많을 경우이다. 이 경우에는 오랜 시간이 걸리더라도 I/O 요청을 다 처리했다면 파일시스템이 조각현상(fragmentation)이 심할지언정 불일치나 결함까지 발생하지는 않는다. 다만, 이러한 I/O 요청을 견디다 못해 디스크 컨트롤러에서 취소(Abort)를 발생 시키거나 디스크 자체가 행업(Hang-up)되면 앞서 살펴보았던 디스크 인식불가 상태와 마찬가지로 파일시스템에 문제가 발생할 수 있다.


 그 외에 전원차단 등의 문제를 생각해 볼 수 있는데 전원이 차단되는 것은 디스크 인식불가 상태와 마찬가지로 생각해도 큰 문제가 없으며 예외적인 요소에 대해서는 후에 Write Barrier를 살펴볼 때 설명하도록 하겠다. 그리고, 드문 경우이긴 하지만 커널 자체의 버그(또는 파일시스템 드라이버 모듈의 버그)로 인해서 발생하는 경우가 있다. 이러한 버그의 예로 다량의 I/O 처리에 대해서 제대로 처리하지 못하고 Zero-length 파일을 양산해서 발생하는 문제도 있다.


 앞서 살펴본 파일시스템에 결함(Corruption)에 영향을 줄 만한 상황에 대해서 종합해보면 궁극적인 요인은 물리적인 디스크 자체의 문제로 볼 수 있으며 운영중인 파일시스템의 불일치(inconsistency) 부분은 파일시스템의 조각화 현상에 능동적으로 대처하지 못하는 파일시스템에서도 종종 볼 수 있다. (예, ext2/3)



Write Barrier


 Write Barrier는 파일시스템의 메타데이터가 올바르게 기록되고 디스크에 제대로(심지어 디스크 전원이 나갈지라도) 반영되게 하기위한 커널 매커니즘이다. 이 매커니즘은 전원에 문제가 생겨도 fsync()를 통해서 전송된 데이터가 올바르게 지속되록 해주지만 특정 프로그램에 대해서는 성능 저하를 가져오는 영향을 줄 수 있다. 특히, fsync() 시스템콜을 많이 사용하거나 작은 파일의 생성과 삭제를 빈번하게 하는 어플리케이션에 성능적인 저하를 많이 일으키게 된다.


 앞서 언급했던 파일시스템과 관련된 부분을 다시 짚어보자. 현재 대부분의 디스크 장치는 내부적으로 캐시를 가지고 있으며 RAID 컨트롤러에도 캐시가 존재한다. 이러한 Write Cache가 존재하는 저장장치들은 데이터가 캐시에 전달이 되면 물리적인 디스크에서 I/O가 완료되었다고 응답한다. 만약 이 상황에서 전원이 유실되면 캐시에 존재하는 데이터도 사라지게 되는데 하나의 데이터 저장 트랜젝션이 일부만 수행된 경우라면 상황은 더 복잡하게 된다. 제대로 완료되지 않은 데이터블록들만 디스크에 존재하게 될 것이고 전원이 복구되면 저널은 초기화 되지 않은 트랜젝션 블록들을 파일시스템에 다시 반영하려고 시도하며 결과적으로 데이터의 일관성과 무결성에 영향을 미치게 된다.


Write Barrier의 동작


 Write Barrier는 I/O 처리의 전과 후에 저장장치(디스크)의 캐시를 비우는 동작을 통해서 Linux 커널에 구현되어있다. 데이터를 저장하기 위해서 트랜젝션이 기록되면 저장장치의 캐시를 비우고(flush) 데이터블록이 기록되면 다시한번 저장장치의 캐시를 비우게 된다. 여기에서 캐시를 비운다는 것은 디스크 캐시에 존재하는 데이터를 실제 물리적인 저장장치에 기록한다는 것을 의미한다. 이러한 동작은 디스크에 모든 데이터를 보유하게 되므로 메타데이터의 순서를 다시 맞출 필요가 없어지게 된다.


 하지만, 앞서 언급했던 것 처럼 Write Barrier를 사용하게 되면 디스크 성능 향상을 위해 장착된 디스크 캐시에 대해서 2번에 걸쳐 비우는 작업을 진행하므로 성능에 단점으로 작용할 수 밖에 없다.



Write Barrier for ext3/ext4


 당연한 이야기일지 모르지만 저널링 파일시스템인 ext3에도 Write Barrier 기능의 사용이 가능하다. 하지만, ext3는 ext2에 저널링 기능을 추가해서 나온 파일시스템으로 태생적인 한계로 인해 Write Barrier를 활성화하게 되면 성능저하가 매우 심한 편이다. ext3도 계속 개선되고 있기 때문에 어느 정도 좋아졌는지는 모르겠지만 일전에 테스트 했던 경험으로는 약 1/10 수준의 I/O 성능밖에 내지 못하는 문제가 있었다.


 비교적 최근 등장한 ext4 파일시스템도 Write Barrier를 지원하며 ext3와는 다르게 Write Barrier 기능이 기본적으로 활성화 되어있다. 즉, /etc/fstab에 barrier=1로 설정하여 마운트 하지 않아도 Write Barrier 기능이 동작한다. 따라서, ext4의 안정성은 ext3 기본(Write Barrier 비활성)보다 낫다고 보아도 무방하다. ext4 외에도 대용량 스토리지 시스템에 널리 사용되어왔던 XFS 파일시스템도 Write Barrier가 기본적으로 활성화 되어있다. 


 이러한 ext4 파일시스템의 Write Barrier의 활성화는 해당 기능을 활성화해도 충분한 성능을 얻을 수 있기 때문인데 이에 대한 벤치마크 자료를 확인해 보자.


bonnie_seq_block_inout.png bonnie_random_seek.png
 

위 자료는 Bonnie++로 테스트한 순차적(sequential)인 I/O 대역폭과 랜덤한 데이터 접근에 대한 결과 값이다. ext4, XFS 파일시스템의 경우 Write Barrier가 활성화 되어있음에도 좋은 성능을 보이고 있다.


linux_kernel_untar_frag.png

 

이 그래프는 Write Barrier와 직접적인 관련이 없는 번외적인 것으로 커널소스를 풀었을 때의 조각화 정도를 비교한 그래프이다. 이는, 지연할당(Delayed Allocation) 기능이 없는 ext3가 가장 조각화가 심하게 되는 것을 보여주고 있다.



Write Barrier의 유효성


 Write Barrier는 파일시스템의 일관성/무결성을 위해서 존재하는 기능이지만 BBC(Battery-backend Cache)가 존재하는 RAID 컨트롤러에서는 없어도 되는 기능이다. BBC가 존재하는 경우는 파워가 유실되어도 Write Cache 데이터가 날아가지 않고 그대로 보존되며 다시 정상적으로 시스템에 전원이 공급되면 전원 복구 후 작업(Post-power-loss recovery)의 일환으로 Write Cache가 가지고 있는 데이터를 물리적인 디스크에 반영시켜주기 때문이다.


 Write Barrier가 기본적으로 활성화 된 파일시스템이더라도 위와 같이 물리적인 안정성을 가지고 있는 경우에는 Write Barrier를 끄고 성능 향상을 꾀하는게 더 나을 수 있다. 단, 전원 문제가 아닌 디스크 컨트롤러 자체의 장애에 대해서도 안정성을 확보하고자 한다면 Write Barrier를 활성화 할 필요가 있다.

[펌] http://blog.naver.com/wassupnari/100105102485


linux kernel과 userspace간의 데이터 교환은 언제나 큰 이슈인데, 대부분 read/write system call로 데이터를 넘겨주고 받거나, 혹은 ioctl을 이용해 단순한 값등을 넘기고 device만의 특정 커맨드를 넘겨줄 수 있다. 더불어 procfs가 있는데 이것은 kernel에 보다 직접적으로 접근할 수 있는 방법으로써, kernel 혹은 driver단에서 직접 /proc 에 특정 node를 생성해서 userspace와 직접적으로 data 교환이 가능하다. 현재는, 이것이 여기에서 말하려 하는 sysfs로 발전되어 가는 과정이라고 하는데, 솔직히 그 히스토리는 관심이 없고. 워낙 역사공부를 좋아라 하는 편이 아니라. :)

2가지 방법이 있는데, 사용법만 간추려 정리해보면 다음과 같다.

1. device 구조체를 직접 이용해 생성하는 방법

주로 shell상에서 echo등을 이용해 간단한 값을 넣거나, 혹은 cat등으로 간단한 값을 읽어올때 사용하기 편하다.

  1. device_create_file(struct device *, struct device_attribute *)  
  2. device_remove_file(struct device *, struct device_attribute *)  

  1. static DEVICE_ATTR(_name, _mode, _show, _store)  
- _name : device 이름. 접두어로 dev_attr_ 이 붙는다.
- _mode : 권한. linux나 unix등에서 사용하는 권한설정 숫자값을 그대로 사용.
        4, 2, 1의 조합으로 이루어지는 그 숫자 말이다. 궁금한 분은 chmod를 뒤져볼것.
- _show : kernel에 userspace에게 값을 보여주는(넘겨주는) func 포인터
- _store : userspace에서 kernel로 값을 보여주는(넘겨주는) func 포인터

위 세가지로, struct device에 지정된 /sys 아래의 특정 device 디렉토리 아래에 sysfs node를 생성할 수 있다.

다음은 _show와 _store에 선언된 특정 func의 prototype 및 pseude code이다.
  1. static ssize_t xxxxx_store(struct device *, struct device_attribute *,  
  2.                         const char *buf, size_t count)  
  3. {  
  4.     u8 data;  
  5.   
  6.     scanf(buf, fmt, &data);  
  7.   
  8.     return count;  
  9. }  
  10.   
  11. static ssize_t xxxxx_show(struct device *, struct device_attribute *,  
  12.                         char *buf)  
  13. {  
  14.     int count;  
  15.     u8 data;  
  16.   
  17.     count += sprintf(buf, fmt, data);  
  18.   
  19.     return count;  
  20. }  
return 값으로 둘다 count를 넘겨주는데, xxxx_store는 kernel주체로 동작되기 때문에, userspace쪽에서 넘겨주는 값의 길이를 알 수 없으므로 count인자를 받아야 한다. 대신, _store는 값을 받아오는 쪽이라, 굳이 userspace쪽으로 넘겨줄 값을 생각해 줄 필요는 없다.

반대로, xxxx_show는 kernel주체로 동작되더라도, userspace쪽에서 보여주는 함수이니 count함수는 userspace쪽에서나 필요하다. 대신, 꼭 code 내부에서 buf에 write한 count값을 고려해서 return으로 넘겨주어야 한다.

2. 간접적으로 kobj 구조체를 이용해 생성하는 방법

kobj 를 이용하면, binary file등의 덩치큰 파일들을 직접 쓰고 읽을 수 있다. (솔직히 읽는 것은 문제가 있을 법도 한데, 테스트를 못해봐서 -.-) 따라서, device_attribute 구조체 대신, bin_attribute 구조체를 사용한다. 기본적 node 생성방법은 다음과 같다.

  1. sysfs_create_bin_file(struct kobject *, struct bin_attribute *)  
  2. sysfs_remove_bin_file(struct kobject *, struct bin_attribute *)  
  3.   
  4. static struct bin_attribute xxxx_attr = {  
  5.     .attr = {  
  6.         .name = "xxxx",  
  7.         .mode = S_IRWXUGO,  
  8.     },  
  9.     .size = MAX_BUF,  
  10.     .read = xxx_sysfs_read,  
  11.     .write = xxx_sysfs_write,  
  12.     .mmap = xxx_sysfs_mmap,  
  13. }  

device_attribute 와 마찬가지로, 권한 mode, read/write/mmap 함수의 func 포인터를 지정해준다. name은 그냥 지정해줄 수 있고(device_attribute에도 있는지는 모르겠음. 찾아봐야함.) 가장 크게 다른점은, buffring을 위해 한번에 가능한 MAX size를 지정해줘야 한다는 것이다. binary data이므로 용량이 큰 파일들을 주로 쓰기 편하게(device에 올릴 firmware 같은 것들) 만들어놓은 것인듯.

read와 write함수의 prototype은 다음과 같다.

  1. static ssize_t xxxx_sysfs_read(struct kobject *, struct bin_attribute *,  
  2.            char *buf, loff_t off, size_t size)  
  3. {  
  4.     int count;  
  5.     u8 data;  
  6.   
  7.     if (off >= MAX_BUF)  
  8.         return 0;  
  9.   
  10.     if (off + size > PAGE_SIZE)  
  11.         return 0;  
  12.   
  13.     count += sprintf(buf, fmt, data);  
  14.   
  15.     return count;      
  16. }  
  17.   
  18. static ssize_t xxxx_sysfs_write(struct kobject *, struct bin_attribute *,  
  19.            char *buf, loff_t off, size_t size)  
  20. {  
  21.     if (off == 0) {  
  22.         /* set the values, for the first time */  
  23.     }  
  24.   
  25.    return size;  
  26. }  
  27.   
  28. static ssize_t xxxx_sysfs_mmap(struct kobject *, struct bin_attribute *,  
  29.            struct vm_area_struct *vma)  
  30. {  
  31.     /* ? */  
  32. }  

여 기서 중요한 것은, buffering되는 MAX 값에 따라 여러번 위 함수들이 호출된다는 것인데, 특히 write에서 쓰고자 하는 file이나 data가 MAX_BUF보다 크게 되면 그 배수만큼 여러번 call된다. 따라서 그에 맞는 처리를 해주어야 한다. 그 부분은 알아서들 하시길 바라며 ... :-)


3. data 교환을 위한 내부의 local 변수 선언

device_create_file() 을 이용하든 sysfs_create_bin_file()을 이용하든, 두 경우 모두 device의 struct device * 구조체 포인터만 알고 있으면 쉽게 적용 가능하다. device_create_file()의 경우 인자로 직접 struct device * 를 받으니, device_create_file()을 call할때 직접 그 포인터를 넘겨주면 된다, sysfs_create_bin_file()의 경우는 인자로 struct kobject *를 받는데, 이것은 &(struct device).kobj 값을 넘겨주면 된다.

또 하나, device 구조체를 이용하는 방법에서는 read/write 함수에서 struct device * 를 인자로 받기 때문에, 그 device 구조체를 보유하고 있는 상위 buf구조체나 platformdata등을 구하면 된다. 일례로, i2c client framework의 경우, 다음과 같이 i2c_client 구조체를 얻어올 수 있다.

  1. static ssize_t xxxxx_store(struct device *dev, struct device_attribute *attr,  
  2.    const char *buf, size_t count)  
  3. {  
  4.     struct i2c_clinet *c = container_of(dev, struct i2c_client, dev);  
  5.     .............  
마 찬가지로, sysfs_create_bin_file()의 경우에는 인자로 struct kobject *를 받는다. 따라서 우선, struct device *를 구하고, 그것을이용해 다시 struct i2c_client *를 얻는다.

  1. static ssize_t xxxx_sysfs_read(struct kobject *, struct bin_attribute *,  
  2.            char *buf, loff_t off, size_t size)  
  3. {  
  4.     struct device *dev = container_of(kobj, struct device , kobj);  
  5.     struct i2c_client *c = container_of(dev, struct i2c_client, dev);  
  6.         ..................  

이런식으로 응용하시면 되겠다. 

출처 : http://suchman.tistory.com/

'Kernel & Uboot' 카테고리의 다른 글

linux logo 변경하기.  (0) 2012.10.08
u-boot home page  (0) 2012.08.17
i2c probe함수 호출 및 dev i2c addr등록 방법  (0) 2012.07.15
Video for Linux Two API Specification  (0) 2012.05.29
S5PC100 FIMC와 S3C6410 FIMC와의 차이  (0) 2011.03.03
http://www.winapi.co.kr/android/

'Etc > Site link' 카테고리의 다른 글

wireless driver 가 있는 사이트  (0) 2012.02.14
Network 관련 정리가 잘되어 있는곳  (0) 2012.02.08
삼성 open source  (0) 2011.10.31
안드로이드 관련 블로그  (0) 2011.10.04
java의 정석 지필자 카페  (0) 2011.07.21
[펌] http://noullove.tistory.com/entry/Windows-7-ADB-%EC%84%A4%EC%A0%95

OSX 에서 별 문제없이 adb 를 사용하다가 Windows 7 으로 옮겨오면서 ADB Interface 드라이버 인식되지 않았다.

모토로라에서 나온 모토글램 드라이버를 설치했지만 adb 사용시 폰을 찾을수 없었다.

해당 문제를 해결하기 위해서 구글링을 하다가 얻은 정보를 통해서 문제를 해결하였다.

혹시 나중에 재설정할 때 참고하기 위해서 여기에다가 기록해 둔다.

일단 모토로라에서 나온 드라이버를 설치하고 난 다음 시작 –> 장치 및 프린터 를 선택한다.

그러면 여러가지 장치가 나오는데 그 중에 “XT800W” 를 선택한다.

그런 다음 오른쪽 마우스로 속성을 선택한다.

거기에 하드웨어 탭에서 “Android Composite ADB Interface 를 선택한 다음 속성보기를 한다.

드라이버탭에서 드라이버 업데이트를 누르고 아래 다운로드 링크에서 다운로드 받는다.

압축 푼 다음 usb_driver 디렉토리를 선택한 다음 드라이버 업데이트를 한 후 리부팅을 하면 이제 정상적으로 ADB Interface 를 사용할 수 있다.

이것때문에 한 3시간 가량을 구글링 한 것 같다.

OSX 에서 Android 환경을 Windows 7 으로 변경하면서 몇가지 헤프닝이 있었지만 다 해결하고 지금은 잘 사용중이다.

앞으로는 윈도우에서 작업을 하게 될 것 같다.

다운로드 : ADBDriver_v3_Google.zip

[펌] http://ioriy2k.pe.kr/archives/1265


Ubuntu Maverick Meerokat(10.10)에서 VirtualBox를 사용할 때, USB Memory Stick과 같은 USB 장치를 Guest OS에 연결해서 사용할 수 없을 경우 아래와 같이 하시면 사용할 수 있습니다.

사용자와 그룹

사용자와 그룹

시스템의 관리에 사용자와 그룹을 Click합니다.

사용자 설정

사용자 설정

사용자 설정 Program이 표시되면 여기서 현재 Login한 사용자를 선택하고 오른쪽 아래에 고급 설정을 누릅니다.

고급 사용자 설정 바꾸기

고급 사용자 설정 바꾸기

Root권한을 얻기 위해서 Password를 입력한 후, 고급 사용자 설정 바꾸기 Dialog가 뜨면 사용자 권한 Tab을 선택합니다. 그 다음 VirtualBox 가상화 솔루션 사용을 Check하고 확인을 누릅니다.

USB 장치 인식

USB 장치 인식

그리고 권한을 적용하기 위해서 Gnome Session을 Logout합니다. 다시 Login한 뒤 VirtualBox를 실행해서 Guest OS를 실행하면 위의 그림과 같이 USB 장치가 사용 가능한 것을 확인할 수 있습니다.

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

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

https://opensource.samsung.com/index.jsp;jsessionid=4D7E38F8E471064089A27C2E7248C6FB

[펌] 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



[펌] http://jang574.tistory.com/entry/git-diff-%ED%95%9C-%EA%B2%83%EC%9D%84-patch%ED%95%98%EA%B8%B0

git 과 patch 툴 사용 팁이다.

git diff --no-prefix > patchfile # 패치파일 생성
cd path/to/top                     # 패치하고자 하는 소스 위치
patch -p0 < patchfile            # 패치 적용

--no-prefix 옵션 없이 패치파일 생성한 경우 -p1 옵션으로 패치 적용 (패치내용의 a/ b/ path prefix 무시)
git diff > patchfile                 # 패치파일 생성
cd path/to/top                     # 패치하고자 하는 소스 위치
patch -p1 < patchfile            # 패치 적용

+ Recent posts