[ 내 개인적인 생각임을 미리 밝힌다. ]


HLD이든 LLD(Low Level Design)이든 결국 block diagram의 형태 (Component 단위든, Class단위의 UML이든...)일 수 밖에 없고, 얼마나 작은 단위의 block까지 명세하느냐에 따라 구분되어 질 것이다.

그럼 이런 block diagram에서 가장 중요한 요소는 무엇인가?

결국 'Design'이라는 측면에서 본다면, 각 block의 input과 ouput을 정의하는 것이다.

그리고, input/output(IO)를 정의한다는 것은, "이 모듈의 역할을 명확히 정의"하는 것과 같다.

더 나아가, block diagram이라는 것 역시 결국,이런 block간 IO의 연결일 뿐이다.


IO를 명확히 하는 것이 왜 SW design에 중요한가?

SW design은 결국 block 간 IO 연결의 형태로 표현되게 된다. 예를 들면,

"A block은 B block의 output을 input으로 받아서 C block과 D block에서 사용할 값들을 만들어 낸다"

같은 형태가 될 것이다.

이때, 내부 구현의 문제는 해당 block하나에만 영향을 끼친다. 즉 A block의 내부 구현이 문제라고 한다면, A block 만 열심히 다시 구현/설계하면 되는 것이다.

그런데, A block의 IO로 정의된 내용이 틀리다면, 예를 들면, "이 input으로는 기대하는 output을 만드는 것이 불가능 혹은 현실적이지 않다."하다면?

그렇다면, A와 연결된 이후 모든 block의 설계다 전부 연쇄적으로 변경되어야 한다.

즉, 소위 "설계 변경"이 일어날 수 밖에 없게 된다.


일반적으로, 내부 구현 문제는 논란의 여지도 많고, 개선의 여지도 많지만, "A라는 input으로, B라는 output을 만들어 낼 수 있느냐?"의 문제는 내부 구현에 대한 고민과 관계없이 판단 가능한 경우가 많다. 혹은 '불가능'하다는 판단은 못하더라도, '가능하다'라는 판단은 명확히 할 수 있다.

따라서, HLD는 이런 block의 IO정의에 대한 잘못된 판단 요소를 조기에 찾아서, 나중에 설계전체에 영향을 주게되는 일을 미리 방지하는게 목적이 된다.


비단 HLD뿐만 아니라, LLD 및 기타 모든 SW 설계역시 마찬가지일 것이다.

얼마나 큰 단위의 block으로 IO를 설계하느냐의 문제이지 block의 IO를 명확히 하는 것이 무엇보다 중요하다.


그럼, 여기서 좋은 설계자는 어떤 차이를 만들어 내는가?

좋은 설계자는, block간 R&R을 명확히 하고, block의 내부 구현에 대한 어느 정도 '감' 을 가지고 있어서, performance및 resource 사용을 최소화 할 수 있는 형태로 block을 나눌 수 있다.

특히, 여기서, '내부 구현에 대한 감'역시 상당히 중요한데, 때로는 이론적으로 상당히 뛰어난 설계를 했음에도 불구하도, 특정 block이 설계에 정의된 IO를 만족하기 위해 너무 많은 비용 - performance, memory 등 - 이 들어가는 경우가 발생할 수도 있다. 불가능 하다는 말이 아니다, 단지 현실적이지 않다는 뜻이다.

이럴 경우, HLD에서는 IO가 타당하다고 Review되었겠지만, 실제 구현단계에서 설계변경이 필요해지는 경우가 발생하게 되는 경우이다.

이때, 경험이 많은 설계자라면, HLD시점에서, 이런 구현단계의 구체적인 문제를 알지는 못하겠지만, "이런 식의 IO로 module을 설계하면, 뭔가 문제가 발생할 여지가 많아 보이는데... 찝찝하다..."라는 소위 '감'을 가질 수도 있고, 이 '감'에 따라서, 이런 '문제 발생 가능성이 높은 설계'를 피할 수 있을 것이다.



project전체에 대한 개괄적인 schedule이 "주 단위 (혹은 2 주 단위), 아주 큰 project라면 한달 단위"로 나올 수 있다면 HLD가 끝났다고 볼 수 있을 것이다. "schedule이 나왔다."는 말은, "어떤 식으로 개발 할 것이다." 라는 것이 정했졌다는 말이고, 그 말은, "전체적인 Design(큰 그림)이 그려졌다."라는 뜻이기 때문이다.

뭐, 이런 식의 기준이 틀렸을 수도 있지만... 일단 난 이 기준으로 판단하고자 한다.




LLDR은 아마도, 2~3일 단위 정도로 schedule이 나왔을 때 끝났다고 이야기 할 수 있지 않을까?


물론, 이 모든 것은 project 의 규모에 따라, flexible할 것이다....

system에 library를 embedding하고, 그것을 apk가 사용하고자 할때... (여러 apk에서 공유가능.)


Sample lib permission - com.my.lib.xml

<permissions>
    <library
        name="com.my.lib"
        file="/system/framework/com.my.lib.jar" />
</permissions>

library definition을 정의한, 위의 xml을 이용하면면, 해당 library를 system에 install하고, uses-library tag - AndroidManifest.xml - 를 이용해서 loading할 수 있게 된다.

Example uses-library

<uses-library
    android:name="com.my.lib"
    android:required="true" />

Sample Android.mk

LOCAL_PATH:= $(call my-dir)

# lib def
# -------
include $(CLEAR_VARS)
LOCAL_MODULE := com.my.lib.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)

# the library
# -----------
include $(CLEAR_VARS)
LOCAL_MODULE := com.my.lib
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_SRC_FILES := $(call all-subdir-java-files)
include $(BUILD_JAVA_LIBRARY)

# the package
# -----------
include $(CLEAR_VARS)
LOCAL_MODULE := myApk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_REQUIRED_MODULES := com.my.lib.xml com.my.lib
include $(BUILD_PREBUILT)

Explanation

* Product가 myApk 를 설치한다면, 위의 두 module 역시 설치하도록 하기 위해서 LOCAL_REQUIRED_MODULES 를 사용한다.

* Android framework은 library, feature 등을 등록하기위해서, $(TARGET_OUT_ETC)/permissions/*.xml 을 scan한다.


이렇게 하면, myApk가 load될때, uses-library 에 기록된, com.my.lib 이 같이 load된다.
단, system class loader는 여전히 BOOTCLASSPATH를 기준으로 하고 있고, Application context가 제공하는 class loader를 사용해야 위의 library가 load된 class loader를 사용할 수 있다.

다시 말하면, library에 정의된 class를 loading하기 위한 방법/예 는 아래와 같다.(class loader를 이용한 것은 example을 보여주기 위한 것 뿐, 그냥 원하는 class를 import해서 사용해도 된다. - 이미 load된 class 이므로...)

ClassLoader cloader; // cloader = new PathClassLoader("/system/framework/com.my.lib.jar", ClassLoader.getSystemClassLoader()); => (*A) // cloader = ClassLoader.getSystemClassLoader(); => (*B) // cloader = getApplicationContext().getClassLoader(); => (*C) cloader.loadClass("com.my.lib.SampleClass");


*A, *C : 정상적으로 SampleClass가 loading 됨.

*B : SampleClass를 load할 수 없음.

Done.



* First of all, check your kernel configuration.

- CONFIG_MODULES=y
- CONFIG_MODULE_UNLOAD=y    <- Optional

* Create your Kernel module code and Makefile


If you have luck, everything should be OK. But...


CASE: error at insmod?

insmod: init_module 'hello.ko' failed (Exec format error) in android
kernel message : unknown relocation: 27
Hmm, then you should check kernel functions you are using in the module (ex. printk)
You can check relocation type with following command (ex. printk)

readelf -r hello.ko | grep prink

Then, result may like below

xxxxxxxx  xxxxxxxx R_ARM_PLT32       00000000   printk

For your information : number 27 indicates R_ARM_PLT32.

Then, what's the problem?
ELF for the ARM Architecture(IHI0044E_aaelf.pdf) says that R_ARM_PLT32 is deprecated.
And, Linux kernel doesn't handle R_ARM_PLT32 at module.c : apply_relocation() function
We have two workaround for this issue.

* Update toolchains.
In my case, I faced this issue when I used gcc-4.4.3. And, gcc-4.7 resolved this issue.
(You can see, relocation type is changed into R_ARM_CALL instead of R_ARM_PLT32.)

* fpic / fno-pic HACK.
If you are in trouble with upgrading your toolchains, here is workaround (tested on gcc-4.4.3).
Add, -fpic or -fno-pic at CFLAGS_MODULE in your module Makefile like below.

make CFLAGS_MODULE=-fpic xxxx modules

Then, like above - updating toolchains -, relocation type is changed :-)



+ Recent posts