안드로이드 프레임워크 프로그래밍(21) [System Service란?]

안드로이드/프레임워크 2015. 8. 23. 18:36

 지금까지 블로그를 통해 안드로이드 프레임워크에 대해 꾸준이 다루어 왔습니다. 그러다가 문득 이런 생각을 해보게 되었습니다.


"지금까지 프레임워크에 대한 이론을 정확히 다루었던 포스팅이 있었던가?"


 프로그래밍을 공부하면서 문제의 솔루션을 찾는 것만 생각을 하다보니 막상 솔루션을 설명하는 것에 대한 공부를 소흘히 해왔던 듯한 생각이 들게 되었습니다. 지금까지 개념들에 대해 간단한 설명만 하고 소스코드를 확인하고 넘어가는 과정만 보였지 실질적으로 해당 개념에 대해 심도있는 고찰을 하는 경우가 드물었음을 알게 되었습니다. 비록 지금 시점에서 포스팅하기엔 다소 늦은 감이 있습니다만 이후에 안드로이드 프레임워크에 대해 연구하실 분들을 위해 조금씩 생각나는 중요한 내용들을 정리해볼까 합니다. 그 첫번째로 안드로이드 프레임워크의 가장 기초적인 상식이라 할 수 있는 System Service에 대해 알아보고자 합니다.


Android System Service

 System Srevice란 안드로이드에서 제공하는 Framework API와 Hardware 사이를 연결해주는 기능을 담당하는 서비스입니다. System Service는 아래 빨간 네모로 강조한 부분을 일컫는 말입니다.


출저 : Android Open Source Project


  실제로 System Service의 일부 기능들은 안드로이드 Application과 같이 순수 Java로 구성되어 프로그램을 관리하는 기능을 하는가 하면 Camera와 같이 하드웨어를 사용하여 JNI를 통해 C++혹은 C와 상호작용 할 수 있도록 설계되어 있는 경우가 있습니다. 안드로이드 Application과는 달리 System Service는 Application이 종료된 후에도 계속 동작하여 이후 다른 Application이 실행되었을 때에도 계속 동작할 수 있도록 구성되어 있습니다.


 System Service는 위의 그림에서 보시는 바와 같이 특정한 기능에 집중되어 있습니다. 이러한 System Service의 기능은 Media Server와 System Server로 나누어서 볼 수 있습니다. 전체적인 기능을 보았을 때 Media Server는 Hardware Abstraction Library(HAL)에 의존적이다 보니 C와 C++과 같은 Native Library를 좀 더 적극적으로 사용하고 있다고 보셔도 될 듯 합니다.


 System Service는 수십개의 기능들로 구성되어 있으며 애플리케이션 프로그래밍을 할 때 필요로 하는 기능들을 제공합니다. 각 서비스들은 Binder를 통해 통신을 수행합니다. Application 또한 Binder를 통해 기능들이 초기화 됩니다. Binder에 대한 자세한 내용은 아래 링크를 참조해 주시기 바랍니다.


http://d2.naver.com/helloworld/47656


 


300x250

[JAVA]JDWP(Java™ Debug Wire Protocol)

프로그래밍 팁 2015. 8. 21. 23:20


 JDWP(Java™ Debug Wire Protocol)이란 디버거와 디버그를 하고자 하는 자바 가상머신(JVM) 사이의 통신을 위해 사용되는 프로토콜 입니다. JDWP는 같은 디버거가 다음과 같은 작업을 하는 것을 할 수 있도록 해줍니다.


 - 같은 컴퓨터 상의 다른 프로세스 내부간의 디버깅

 - 원격 컴퓨터 상에서의 디버깅


 JDWP는 통신 뿐 아니라 형식과 레이아웃을 상세히 다룬다는 점에서  다른 프로토콜들과 차이점을 가지고 있습니다. JDWP는 간단한 하나의 API를 통하여 여러가지의 전송 방식들을 수용할 수 있도록 만들어져 있습니다. 특정한 전송방식은 각 디버거와 타겟 JVM의 조합이 반드시 지원되지는 않습니다.


 아직은 JDWP가 장래엔 더욱 발전할 것으로 보이지만, JDWP는 간단한 실행에 있어서 충분히 실행할 수 있도록 고안되어 있습니다.


 안드로이드의 기반인 Dalvik 가상머신 또한 JDWP를 지원합니다. 안드로이드 기기 내의 애플리케이션은 Dalvik 가상머신을 통해 실행되고 있으며 각 애플리케이션은 또한 DDMS를 사용하여 특정한 포트를 통하여 디버깅을 할 수 있습니다. 만약 여러개의 애플리케이션을 디버깅을 할 때, DDMS는 특정한 가상머신의 디버깅 포트를 통한 포트포워딩 기능을 지원합니다. DDMS의 선택 메뉴를 통해 자신이 디버깅 하고자 하는 애플리케이션을 자유롭게 변경할 수 있는 것이지요. DDMS는 포트 8700번을 통해 포트포워딩을 합니다.

 

 실제 안드로이드 기기를 통해 Traceview를 해보면 JDWP 스레드를 확인하실 수 있습니다 JDWP의 Trace까지 추적되는 것 또한 확인하실 수 있습니다.





출저: http://docs.oracle.com/javase/1.5.0/docs/guide/jpda/jdwp-spec.html


300x250

[Java] Error 혹은 Debug시 등장하는 method인 access$000

프로그래밍 팁 2015. 8. 20. 23:57

 안드로이드 프레임워크를 공부하면서 종종 신기한 경우들을 마주치곤 합니다. 그 중 하나가 바로 실제 코드상에는 존재하지 않던 method가 디버깅을 할 때 예상치 못하게 등장하기 때문입니다.




 분명 소스코드 상에서는 존재 자체가 없었던 method인 'access$000'가 이렇게 디버깅을 하던 도중 발견되는 경우가 종종 있습니다. 과연 이것의 정체는 무엇일까요?


 이 문제의 원인은 바로 Java 언어의 특징 중 하나인 Inner class에서 원인을 찾을 수 있습니다.


 Java를 공부하신 분들이라면 누구나 아시는 듯이 Inner class는 말 그대로 Class 안에 내포된 Class를 의미합니다. C언어에서 마치 Struct 구조체 안에 또다른 Struct를 품은 듯한 형태를 띄고 있는 구조라고 이해하시면 되겠습니다.


아래는 Inner class가 구현되어 있는 예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Test {
 
  public void func() {
    System.out.println(new Inner().a);
    System.out.println(new Inner().getInt());
    System.out.println(new Inner2().b);
    System.out.println(new Inner2().getInt());
  }
 
  class Inner {
    private int a;
 
    public int getInt() {
      return a;
    }
  }
 
  class Inner2 {
    int b;
 
    public int getInt() {
      return b;
    }
  }
}
cs


 위의 예제는 Test 클래스 안에 두 개의 Inner class로 구성되어 있는 소스코드입니다. Test 클래스의 입장에서 Inner class는 private 인 경우에도 접근이 가능하여 위의 func() method에서 실행되는 모든 함수들이 제 기능을 하는 것을 확인하실 수 있습니다.


 그런데 여기서 문제가 발생하게 됩니다. Java의 소스코드를 컴파일한 결과물인 bytecode는 Inner class를 고려하지 않는다는 점입니다. 이로 인해 bytecode 상에서 func() method는 접근할수 없는 field 값은 Inner 클래스의 a의 값에 접근할 수 없게 됩니다.

 그렇기 때문에 실제 bytecode 상에서는 private로 설정된 내부클래스에 접근할 수 있도록 하기 위해 소스코드를 살짝 바꾸어서 기능을 똑같이 구현되게 하는데 실제 위의 설계된 소스코드를 디컴파일하게 되면 위에서 보았던 메소드인  access$000이 등장하는 것을 알 수 있습니다.


 아래의 예제는 Inner class가 적용되었을 경우를 가장한 예제입니다. 위의 소스코드와 비교하시면 자신이 설계한 소스코드에서 등장하는  access$000이 어느 시점에서 등장하게 되는지 어느 정도 감이 오실 것이라 생각됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Test {
  public void func() {
    System.out.println(Test$Inner.access$000(new Test$Inner(this)));
    System.out.println(new Test$Inner(this).getInt());
    System.out.println(new Test$Inner2(this).b);
    System.out.println(new Test$Inner2(this).getInt());
  }
}
 
class Test$Inner {
  final Test this$0;
 
  private int a;
 
  Test$Inner(Test test) {
    this$0 = test;
  }
 
  public int getInt() {
    return a;
  }
 
  static int access$000(Test$Inner inner) {
    return inner.a;
  }
 
}
 
class Test$Inner2 {
  final Test this$0;
 
  int b;
 
  Test$Inner2(Test test) {
    this$0 = test;
  }
 
  public int getInt() {
    return b;
  }
}
cs


 아래는 제가 안드로이드 프레임워크를 분석하던 도중  access$000가 뜨던 부분입니다. 보시는 대로 new Handler() 방식으로 내부클래스를 구성하고 있으며 이를  access$000 함수명을 통하여 updateWindow() 함수에 접근하고 있는 것을 확인할 수 있습니다.


/frameworks/base/core/java/android/view/SurfaceView.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SurfaceView extends View {
 
....
 
    final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case KEEP_SCREEN_ON_MSG: {
                    setKeepScreenOn(msg.arg1 != 0);
                } break;
                case GET_NEW_SURFACE_MSG: {
                    handleGetNewSurface();
                } break;
                case UPDATE_WINDOW_MSG: {
                    updateWindow(falsefalse);
                } break;
            }
        }
    };
 
....
 
}
cs



출저 : http://www.javacodegeeks.com/2012/05/java-pitfalls-field-access-in-inner.html

300x250