이제 XML 파싱도 끝났고 마지막 우리가 만들 플러그 인 클래스의 마지막 터치가 남아 있습니다
저번 시간에도 말씀 드렸듯이 자바의 꽃이라 불리우는 클래스 로딩은 말 그대로 자바의 클래스를 로딩하는 기술입니다.
자바의 JVM은 한마디로 인터프리터라고 불리는 데 인터프러터라는 의미는 바로 중간에 JVM이라는 스팩으로 시스템 커널과 사용자 애플리케이션 중간에 레이어를 추가 했다는 개념인데요 사용자가 할 수 있는 일이라고는
1. 자바를 코딩하고
2. 자바를 소위 바이트코드라는 클래스 파일을 만드는 컴파일 과정을 거치고 난 후
3. JVM에 갖다 맡기는 것입니다 (java.exe)
4. 그리고 자바는 자기만의 스팩을 가지고 커널과 통신에 의해서 사용자 애플리케이션을 구동하는 것입니다
이런 일련의 과정에서 바이트 코드를 JVM 상에 로딩하게 되는 데 이 로딩을 컴파일 타임에도 할 수 있고 런타임에서 할 수 있게 만든 것이 동적 클래스 로딩 즉, Dynamic Class Loading이라는 메커니즘입니다.
그러기 위해선 ClassLoader라는 특수한 클래스를 상속 받아서 내가 지금 어떤 자바를 동적으로 로딩할 것인지에 대한 로딩 정책을 정해야 하는 일이 남아있습니다
우선 안드로이드 API를 살펴보면
ClassLoader가 추상 클래스 입니다. 따라서 우선 해야 할 일들이 이 ClassLoader라는 놈을 구현해야만 하겠네요 (일반 자바 클래스로더도 틀리지는 않습니다)
사실 제대로 된 커스텀 클래스로더를 만든다는 것은 아무래도 어려운 일입니다. 날을 잡아서 구현해보지 않고서는 제대로 알 수 없는 문제라고 판단 되는 바,
유명한 웹서버 중 하나인 제티 일명 Jetty에서 안드로이드 용으로 웹서를 포팅하기 위해서 사용한 AndroidClassLoader를 사용하도록 하겠습니다.
설마 이런 비영리 목적의 문서에서 약간의 커스터마이징(?)을 가한 클래스로더를 가지고 뭐라고 하지 않을 것이라는 굳은 신념을 가지고 커스터마이징을 하였습니다.(^^;;) 이렇게 레퍼런스를 만들어 주신 Jetty의 고수님들에게 심심한 감사의 말씀을 드리고 싶습니다…
현재까지 만들어진 ConvertTemp.java 파일을 분리 시켜서 따로 컴파일을 하고 컨테이너와 파서 등의 클래스는 ant로 컴파일 하여 apk 파일을 만들고 분리시킨 플러그인 파일은 따로 jar 파일로 만들도록 하겠습니다
일단 일련의 과정을 위해서 다음과 같이 디렉토리를 정하고 프로젝트를 생성 합니다(프로젝트 생성 방법은 저번 글을 참고하시길)
파일이름은 plug-in.jar라고 임의로 정하겠습니다. 아래와 같이 컴파일 하고 jar 파일 만드는 과정을 거치게 되겠습니다.
우선 ant로 컴파일 하기 이전에 생성된 jar 파일을 libs 라는 폴더에 넣고 컴파일 하도록 하겠습니다
ConvertTemp 클래스는 원래 목적인 동적 로딩을 위해서 만들어진 클래스라서 컨테이너 클래스를 고칠 이유는 없으므로 아무런 이상 없이 컴파일 됩니다.
좀 더 정확한 결과치를 위해서 현재 패키지를 언인스톨 하고 다시 패키지를 인스톨 하기로 하겠습니다.
우선 컨테이너 클래스 소스 내용은
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
parser = new com.skcc.lec.parser.PlugParser("com/skcc/lec/plugin/");
try
{
System.out.println(parser.getPlugInData());
}
catch(java.io.IOException ie)
{
System.out.println(ie);
}
setContentView(R.layout.main);
}
위에서 보듯이 예전 소스와 별 다를 게 없이 컴파일 하였습니다
단지 달라진 것은 플러그인으로 정의 되었던 ConvertTemp가 jar 파일로 빠져 있다는 것 밖에 없습니다.
그럼 인스톨 과정을 거치고 프로그램을 실행해 보면
저번 프로그램에서 봤던 xml 내용을 그대로 파싱해서 제대로 보여 주었습니다 (근데 왜 두번 찍히지??..ㅡ.ㅡ;;.)
여하튼 libs 폴더에 들어간 jar 파일이 합쳐졌다는 생각 밖에 들지 않는 내용인데요
그래서 apk 파일을 풀어서 확인 해 보면 다음과 같습니다
역시나 저번 시간에 봤던 내용처럼 그대로 xml파일이 apk 파일안에 묶여 있는 것을 확인 할 수 있습니다.
그러니까 libs 폴더에 무엇을 넣는다는 것은 같이 apk 파일로 합쳐진다고 조심스럽게 생각 해 볼 수 있는 데요.
그러면, 무한정 많은 jar 파일도 다 묶여 들어 가는 것일까 파일 사이즈는 어느 정도까지 커질 수 있을까 하는 의문점이 듭니다 만…
제 생각에는 주제에 좀 어긋난다고 생각하고 다음에 풀기로 하겠습니다
그러면 만들어진 jar 파일을 일정한 디렉토리에 넣고 테스트를 해 보겠습니다 우선 쉘로 들어가서
현재 나의 프로그램을 살펴보면 다음과 같습니다
쉘에서 보듯이 저에게 할당된 사용자는 app_24:app_24 입니다
사실 에뮬레이터이기 때문에 어떻게든 root 유저로 사용 했으나 app_24 사용자로 들어가면 예를 들어 ls 같은 명령어는 생각 할 수도 없다는 것이지요
일단 OnCreate 소스를 약간 고쳐서 app_24 사용자 디렉토리에 파일을 하나 만들어 보겠습니다
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
parser = new com.skcc.lec.parser.PlugParser("com/skcc/lec/plugin/");
System.out.println(parser.getPlugInData());
clsLoader = new com.skcc.lec.clsload.AndroidJarLoader(".");
try{
java.io.File f = new java.io.File("/data/data/com.skcc.lec.container/tmp.dat");
System.out.println(f.getAbsolutePath() + " : \r\n" + f.getCanonicalPath());
System.out.println(f.createNewFile() + " : " + f.canWrite() + " : \r\n" + f.canRead());
}catch(java.io.IOException ie)
{
System.out.println(ie);
}
setContentView(R.layout.main);
}
프로그램을 다시 실행하고 쉘에 내용을 확인 해 보면 소스 상에서의 System.out으로 표시해본 파일의 권한이 다 실행 가능한 것으로 나옵니다 즉 읽기 쓰기가 가능하다는 것이지요…
그럼으로 다시 /data/data/com.aa.lec.container 디렉토리 내용을 확인 해보면
당연히 tmp.dat 파일이 생성 되어 있습니다
app_24 유저에게 허락된 디렉토리는 다음과 같이 가능하다는 것입니다
물론 모든 안드로이드 폰이 다음과 같은 디렉토리 구조를 따르는 지는 확인해 보지는 않았으나 이 비슷한 구조로 가져 갈 수 밖에 없겠죠?
자 이제부터 클래스로더를 만들어 아니 만들어진 클래스 로더를 사용해 보아야 하겠습니다
Plugin-ext라는 폴더를 만들고 분리 시킬 ConvertTemp.java 파일을 옮깁니다
자바를 컴파일 해야 하는 데 우선 안드로이드 메인 API 구현이 어디에 있는 지 알아야 하겠지요 저는 다음과 같이 안드로이드 SDK 설치 폴더 아래에 각 각 API 폴더 안에서 android.jar를 찾았습니다.
아주 전통적인 자바의 방식을 따라서 위의 android.jar 파일을 classpath에 잡아 주고
Javac –d classes *.java 로 컴파일 하고 ,
Jar cvf plug-in.jar classes로 묶겠습니다
Adb push plug-in.jar /data/data/com.aa.lec.container/ 로 해당 디렉토리로 전송합니다
다음과 같이 클래스를 로딩한다 치면
String jarFile = "/data/data/com.aa.lec.container/plug-in.jar";
DexClassLoader classLoader
= new DexClassLoader(jarFile, "/data/data/com.aa.lec.container/tmp", null,
getClass().getClassLoader());
Class<?> myClass = classLoader.loadClass("com/aa/lec/plugin/ConvertTemp");
우선 다 만들었다 치고 실행하면 다음과 같은 메시지를 필연적으로 만날 수 있을 겁니다
이딴 타입은 안된다고?? 왜 무슨 말이지…..?
일반적인 jar 파일이 아니라는 것 밖에 안된다는 소리인데.. 여기서 이런 생각을 해보아야 하겠습니다. 일반적인 자바파일이 아닌가하고 ConvertTemp.class를 열어 보면 우리가 생각하듯이 ‘CAFEBABE’가 있는 데…
여하튼 결론은 Dalvik JVM이라는 것은 DEX 파일이라는 구조로 한번 더 묶어놓고 있는 것이 아닌가 합니다. 그래야 아무 jar 파일을 (특히나 서명되지 않은) 갖다 쓰는 일이 없을테고
너무 어렵네요.. 다음 시간에는 진짜 클래스 로더를 사용해 보기로 하겠습니다
하지만 우선 위의 문제를 풀어야 하겠지만요…
'모바일프로그래밍 > 안드로이드' 카테고리의 다른 글
안드로이드 APK 분석 참고 문서 (0) | 2022.09.15 |
---|---|
내 멋대로 안드로이드 - 8 (0) | 2022.07.22 |
내 멋대로 안드로이드 - 6 (0) | 2022.07.20 |
내 멋대로 안드로이드 - 5 (0) | 2022.07.19 |
내 멋대로 안드로이드 - 4 (0) | 2022.07.18 |