Android VM은 일반적인 Java VM과 마찬가지로 boot class path와 class path를 지원한다.

그렇지만, Android App(APK)에서 위의 내용들이 어떻게 사용되고 있는가에 대한 점은 상세히 분석해 볼 필요가 있다.

왜냐하면, Android에서는 App(APK)가 처음부터 loading되는 것이 아니고 zygote를 통해서 fork되는 방식이기 때문에  Java의 경우와는 약간 다르기 때문이다.


Class Loader 의 종류와 내용.


VMClassLoader / BootClassLoader

BOOTCLASSPATH만을 load하는 기본적인 class loader


System Class Loader

BootClassLoader + "CLASSPATH" 를 가지는 Loader.

VM이 최초 "static main"을 invoke시킬때 사용하는 class loader이다.

근거:

startVm() -> DvmStartup() -> dvmPrepMainThread()

: SystemClassLoader를 Thread의 ContextClassLoader로 setting함.

AndroidRuntime::start()pEnv->FindClass() - Function pointer to 'dalvik/vm/Jni.cpp:FindClass' - 를 이용해서 "static main"을 invoke하는데, 이때 SystemClassLoader가 사용됨.


Context Class Loader

SystemClassLoader + "Package private configuration"을 가지는 loader.

VM이 뜬 이후, Android context instance - ex. Activity - 를 시작할때 - ex. performLaunchActivity() - 사용되는 class loader로 기본 System Class Loader에 package private configuration(LoadedApk.java) - ex. shared java library - 을 포함한다.

근거:

LoadedApk.getClassLoader() 함수를 자세히 살펴볼 필요가 있는데, package정보의 java shared library나 native shared library정보 등을 이용해서 PathClassLoader를 생성하고 이를 이용하는데, 이때 base class loader가 default로, SystemClassLoader이기 때문이다.


여기서 또 한가지 중요한 내용은, Java의 경우, class가 최초 reference될때, referer가 load될때 사용된 classLoader를 이용해서, reference되는 class도 load된다는 것이다. 이것은 Android VM의 경우도 마찬가지인데 예로, dalvik의 OP_NEW_INSTANCE op code처리 부분을 보면, dvmResolveClass() 를 call하고, 함수 내부의 구현을 보면, referer의 class loader 를 이용하는 것을 볼 수 있다.


이제 정리할 시간이다.

Android의 경우, 최초 vm이 뜰때는 System Class Loader가 사용되나, context가 수행될 때는 Context Class Loader가 사용된다. 따라서, Package(APK)에 추가적으로 사용할 library를 기록해 두면, Context내부에서는 정상적으로 사용이 가능하다.


그러면, Package 에서 사용할 library들은 어떤식으로 정의할 수 있을까?


먼저 사용할 library가 permission file에 정의되어 있고, platform build시 /system/etc/permissions 에 위치해야 한다.

(당연히, 해당 library도 정해진 위치에 있어야 한다.)


com.my.android.test.xml

<permissions>

<library name="com.my.android.test"

         file="/system/framework/com.my.android.test.jar" />

</permissions>


이제 위의 library는 package manager에 의해 shared library로 인식된다.


Package에서 사용하기 위해서는, package의 AndroidManifest.xml에 application element의 sub element로 아래 'uses-library' element를 추가해야 한다.


AndroidManifest.xml

<uses-library android:name="com.my.android.test" />


이렇게 정의되면, package manager service가 Context Class Loader에 해당 library를 추가해 준다.


또 한가지 짚고 넘어가야 할 것은, CLASSPATH 에 대한 부분이다.

CLASSPATH의 경우, VM이 시작할때, setting되는 java.class.path property를 읽는데, 이 값은 Dvm의 classPathStr 값이다.


[[ TO DO ]]

그런데, 재미있는 사실은, system의 CLASSPATH 환경변수를 설정하더라도, Zygote에서 fork되는 App에서는 이를 바로 사용하지 못하는데 (실험적. 확인 필요)이 부분은 좀더 분석해 봐야 한다.



====== Rough Reference - Starting new Activity ======


ActivityStackSupervisor
startActivityLocked
startActivityUncheckedLocked

ActivityStack (target stack)
startActivityLocked

ActivityManagerService

attachApplicationLocked

ActivityStackSupervisor

resumeTopActivityLocked

ActivityManagerService.java
startProcessLocked() -> Process.start("android.app.ActivityThread", app.processName, uid, uid, gids ....)

Process.java
Process.start()
startViaZygote()
zygoteSendArgsAndGetResult() === send argument list via socket ===> zygote

<<< Socket connection >>>

ZygoteInit
registerZygoteSocket()
acceptCommandPeer()

ZygoteConnection
readArgumentList()

Zygote.java
forkAndSpecialize

--- child process ---

'WrapperInit.execApplication' or 'execStandalone'
# executing execv -> "/system/bin/app_process /system/bin --application --nice-name=xxx com.android.internal.os.WrapperInit <pipe fd> <targetSdkVersion> <shell args>
<shell args> : Args from Process.zygoteSendArgsAndGetResult <= which comes from startProcessLocked ("android.app.ActivityThread" ...)
# executing execv -> "/system/bin/dalvikvm -classpath '...' ...

--- execv ---

AppRuntime : AndroidRuntime -> "com.android.internal.os.RuntimeInit"

AndroidRuntime.start()
: startVm()
...
# starts Java startClass or starts "main" method.

RuntimeInit.main()

AndroidRuntime.cpp:: com_android_internal_os_RuntimeInit_nativeFinishInit()

app_main::AppRuntime.onStarted

AndroidRuntime.callMain()

*** <class>.main() *** => WrapperInit.main (see app_process argument above....).

RuntimeInit
wrapperInit()
applicationInit()
invokeStaticMain()

static ActivityThread.main : <= See WrapperInit.execApplication.

ActivityThread
attach()
ActivityManager.attachApplication() ==> ActivityManagerService.attachApplication()
# enter message loop!

ActivityManagerService
attachApplication()
attachApplicationLocked()
:--- attaching applications...

ActivityStackSupervisor.attachApplication()

ActivityStackSupervisor
realStartActivityLocked()

ActivityThread.scheduleLaunchActivity()
-> queue message : ActivityThread.LAUNCH_ACTIVITY

'Domain > Android' 카테고리의 다른 글

Multiple ABI and 64bit on Lolipop  (2) 2014.11.08
[Android] WindowManager & Display Area  (0) 2014.08.08
Create and use java library from packages.  (0) 2014.02.03
[NDK] 불편한 진실... 00  (0) 2013.11.25
Android resource compiler의 한계...  (0) 2013.11.09

+ Recent posts